diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index c4bd0584d..3bfc16f40 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -28,6 +28,62 @@ ClockNetwork::clock_tree_range ClockNetwork::trees() const { /************************************************************************ * Public Accessors : Basic data query ***********************************************************************/ +std::string ClockNetwork::tree_name(const ClockTreeId& tree_id) const { + VTR_ASSERT(valid_tree_id(tree_id)); + return tree_names_[tree_id]; +} + +size_t ClockNetwork::tree_width(const ClockTreeId& tree_id) const { + VTR_ASSERT(valid_tree_id(tree_id)); + return tree_widths_[tree_id]; +} + +std::vector ClockNetwork::spines(const ClockTreeId& tree_id) const { + std::vector ret; + for (ClockSpineId spine_id : spine_ids_) { + if (spine_parent_tree_[spine_id] == tree_id) { + ret.push_back(spine_id); + } + } + return ret; +} + +std::string ClockNetwork::spine_name(const ClockSpineId& spine_id) const { + VTR_ASSERT(valid_spine_id(spine_id)); + return spine_names_[spine_id]; +} + +vtr::Point ClockNetwork::spine_start_point(const ClockSpineId& spine_id) const { + VTR_ASSERT(valid_spine_id(spine_id)); + return spine_start_points_[spine_id]; +} + +vtr::Point ClockNetwork::spine_end_point(const ClockSpineId& spine_id) const { + VTR_ASSERT(valid_spine_id(spine_id)); + return spine_end_points_[spine_id]; +} + +std::vector ClockNetwork::spine_switch_points(const ClockSpineId& spine_id) const { + VTR_ASSERT(valid_spine_id(spine_id)); + std::vector ret; + ret.reserve(spine_switch_points_[spine_id].size()); + for (size_t i = 0; i < spine_switch_points_[spine_id].size(); ++i) { + ret.push_back(ClockSwitchPointId(i)); + } + + return ret; +} + +ClockSpineId ClockNetwork::spine_switch_point_tap(const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id) const { + VTR_ASSERT(valid_spine_switch_point_id(spine_id, switch_point_id)); + return spine_switch_points_[spine_id][size_t(switch_point_id)]; +} + +vtr::Point ClockNetwork::spine_switch_point(const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id) const { + VTR_ASSERT(valid_spine_switch_point_id(spine_id, switch_point_id)); + return spine_switch_coords_[spine_id][size_t(switch_point_id)]; +} + bool ClockNetwork::find_spine(const std::string& name) const { auto result = spine_name2id_map_.find(name); if (result == spine_name2id_map_.end()) { @@ -135,10 +191,12 @@ void ClockNetwork::set_spine_end_point(const ClockSpineId& spine_id, const vtr:: spine_end_points_[spine_id] = coord; } -void ClockNetwork::add_spine_switch_point(const ClockSpineId& spine_id, const ClockSpineId& drive_spine, const vtr::Point& coord) { +void ClockNetwork::add_spine_switch_point(const ClockSpineId& spine_id, const ClockSpineId& drive_spine_id, const vtr::Point& coord) { VTR_ASSERT(valid_spine_id(spine_id)); + VTR_ASSERT(valid_spine_id(drive_spine_id)); spine_switch_points_[spine_id].push_back(drive_spine); spine_switch_coords_[spine_id].push_back(coord); + spine_parent_[drive_spine_id] = spine_id; } /************************************************************************ @@ -152,4 +210,11 @@ bool ClockNetwork::valid_spine_id(const ClockSpineId& spine_id) const { return (size_t(spine_id) < spine_ids_.size()) && (spine_id == spine_ids_[spine_id]); } +bool valid_spine_switch_point_id(const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id) const { + if (!valid_spine_id(spine_id)) { + return false; + } + return size_t(switch_point_id) < spine_switch_points_[spine_id].size(); +} + } // End of namespace openfpga diff --git a/libs/libclkarchopenfpga/src/base/clock_network.h b/libs/libclkarchopenfpga/src/base/clock_network.h index ba2f90b1b..c22a7bb93 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.h +++ b/libs/libclkarchopenfpga/src/base/clock_network.h @@ -47,41 +47,47 @@ class ClockNetwork { public: /* Accessors: aggregates */ clock_tree_range trees() const; + /* Return a list of spine id under a clock tree */ + std::vector spines(const ClockTreeId& tree_id) const; public: /* Public Accessors: Basic data query */ + std::string tree_name(const ClockTreeId& tree_id) const; + size_t tree_width(const ClockTreeId& tree_id) const; + std::string spine_name(const ClockSpineId& spine_id) const; + vtr::Point spine_start_point(const ClockSpineId& spine_id) const; + vtr::Point spine_end_point(const ClockSpineId& spine_id) const; + /* Return the unique id of switch points under a clock spine*/ + std::vector spine_switch_points(const ClockSpineId& spine_id) const; + ClockSpineId spine_switch_point_tap(const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id) const; + vtr::Point spine_switch_point(const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id) const; /* Find a spine with a given name, if not found, return an valid id, otherwise return an invalid one */ ClockSpineId find_spine(const std::string& name) const; - /* Check if there are clock tree */ bool empty() const; public: /* Public Mutators */ /* Reserve a number of spines to be memory efficent */ void reserve_spines(const size_t& num_spines); - /* Reserve a number of trees to be memory efficent */ void reserve_trees(const size_t& num_trees); - /* Create a new tree, by default the tree can accomodate only 1 clock signal; use width to adjust the size */ ClockTreeId create_tree(const std::string& name, const size_t& width = 1); - /* Create a new spine, if the spine is already created, return an invalid id */ ClockSpineId create_spine(const std::string& name); /* Try to create a new spine, if the spine is already existing, return the id. If not, create a new spine and return its id */ ClockSpineId try_create_spine(const std::string& name); - /* Set the parent tree for a given spine. It is illegal that a spine which does not belong to any tree */ void set_spine_parent_tree(const ClockSpineId& spine_id, const ClockTreeId& tree_id); void set_spine_start_point(const ClockSpineId& spine_id, const vtr::Point& coord); void set_spine_end_point(const ClockSpineId& spine_id, const vtr::Point& coord); - void add_spine_switch_point(const ClockSpineId& spine_id, const ClockSpineId& drive_spine, const vtr::Point& coord); + void add_spine_switch_point(const ClockSpineId& spine_id, const ClockSpineId& drive_spine_id, const vtr::Point& coord); public: /* Public invalidators/validators */ /* Show if the tree id is a valid for data queries */ bool valid_tree_id(const ClockTreeId& tree_id) const; - /* Show if the tree id is a valid for data queries */ bool valid_spine_id(const ClockSpineId& spine_id) const; + bool valid_spine_switch_point_id(const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id) const; private: /* Internal data */ /* Basic information of each tree */ diff --git a/libs/libclkarchopenfpga/src/base/clock_network_fwd.h b/libs/libclkarchopenfpga/src/base/clock_network_fwd.h index d936bbb9c..cc4af5f70 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network_fwd.h +++ b/libs/libclkarchopenfpga/src/base/clock_network_fwd.h @@ -16,9 +16,11 @@ namespace openfpga { // Begin namespace openfpga struct clock_tree_id_tag; struct clock_spine_id_tag; +struct clock_switch_point_id_tag; typedef vtr::StrongId ClockTreeId; typedef vtr::StrongId ClockSpineId; +typedef vtr::StrongId ClockSwitchPointId; /* Short declaration of class */ class ClockNetwork; diff --git a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp new file mode 100644 index 000000000..cdd58686e --- /dev/null +++ b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp @@ -0,0 +1,162 @@ +/******************************************************************** + * This file includes functions that outputs a clock network object to XML format + *******************************************************************/ +/* Headers from system goes first */ +#include +#include + +/* Headers from vtr util library */ +#include "vtr_assert.h" +#include "vtr_log.h" +#include "vtr_time.h" + +/* Headers from openfpga util library */ +#include "openfpga_digest.h" + +/* Headers from arch openfpga library */ +#include "write_xml_utils.h" + +/* Headers from pin constraint library */ +#include "clock_network_xml_constants.h" +#include "write_xml_clock_network.h" + +namespace openfpga { // Begin namespace openfpga + +static int write_xml_clock_spine_switch_point(std::fstream& fp, const ClockNetwork& clk_ntwk, + const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id) { + openfpga::write_tab_to_file(fp, 3); + fp << "<" << XML_CLOCK_SPINE_SWITCH_POINT_NODE_NAME << ""; + + write_xml_attribute(fp, XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_TAP, + clk_ntwk.spine_switch_point_tap(spine_id, switch_point_id)); + vtr::Point coord = clk_ntwk.spine_switch_point(spine_id); + write_xml_attribute(fp, XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_X, + coord.x()); + write_xml_attribute(fp, XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_Y, + coord.y()); + + fp << "/>" + << "\n"; + + return 0; +} + +static int write_xml_clock_spine(std::fstream& fp, const ClockNetwork& clk_ntwk, + const ClockSpineId& spine_id) { + openfpga::write_tab_to_file(fp, 2); + fp << "<" << XML_CLOCK_SPINE_NODE_NAME << ""; + + write_xml_attribute(fp, XML_CLOCK_SPINE_ATTRIBUTE_NAME, + clk_ntwk.spine_name(spine_id)); + vtr::Point start_coord = clk_ntwk.spine_start_point(spine_id); + write_xml_attribute(fp, XML_CLOCK_SPINE_ATTRIBUTE_START_X, + start_coord.x()); + write_xml_attribute(fp, XML_CLOCK_SPINE_ATTRIBUTE_START_Y, + start_coord.y()); + vtr::Point end_coord = clk_ntwk.spine_end_point(spine_id); + write_xml_attribute(fp, XML_CLOCK_SPINE_ATTRIBUTE_END_X, + end_coord.x()); + write_xml_attribute(fp, XML_CLOCK_SPINE_ATTRIBUTE_END_Y, + end_coord.y()); + + fp << ">" + << "\n"; + + for (const ClockSwitchPointId& switch_point_id : clk_ntwk.spine_switch_points(spine_id)) { + write_xml_clock_spine_switch_point(fp, clk_ntwk, spine_id, switch_point_id); + } + + openfpga::write_tab_to_file(fp, 2); + fp << "" + << "\n"; + + return 0; +} + +/******************************************************************** + * A writer to output a clock tree to XML format + * + * Return 0 if successful + * Return 1 if there are more serious bugs in the architecture + * Return 2 if fail when creating files + *******************************************************************/ +static int write_xml_clock_tree(std::fstream& fp, const ClockNetwork& clk_ntwk, + const ClockTreeId& tree_id) { + /* Validate the file stream */ + if (false == openfpga::valid_file_stream(fp)) { + return 2; + } + + openfpga::write_tab_to_file(fp, 1); + fp << "<" << XML_CLOCK_TREE_NODE_NAME << ""; + + if (false == clk_ntwk.valid_tree_id(tree_id)) { + return 1; + } + + write_xml_attribute( + fp, XML_CLOCK_TREE_ATTRIBUTE_NAME, + clk_ntwk.tree_name(tree_id).c_str()); + write_xml_attribute(fp, XML_CLOCK_TREE_ATTRIBUTE_WIDTH, + clk_ntwk.tree_width(tree_id)); + fp << ">" + << "\n"; + + /* Output all the pins under this bus */ + for (const ClockSpineId& spine_id : clk_ntwk.spines(tree_id)) { + write_xml_clock_spine(fp, clk_ntwk, spine_id); + } + + openfpga::write_tab_to_file(fp, 1); + fp << "" + << "\n"; + + return 0; +} + +/******************************************************************** + * A writer to output a bus group object to XML format + * + * Return 0 if successful + * Return 1 if there are more serious bugs in the architecture + * Return 2 if fail when creating files + *******************************************************************/ +int write_xml_clock_network(const char* fname, const ClockNetwork& clk_ntwk) { + vtr::ScopedStartFinishTimer timer("Write Clock Network"); + + /* Create a file handler */ + std::fstream fp; + /* Open the file stream */ + fp.open(std::string(fname), std::fstream::out | std::fstream::trunc); + + /* Validate the file stream */ + openfpga::check_file_stream(fname, fp); + + /* Write the root node */ + fp << "<" << XML_CLOCK_NETWORK_ROOT_NAME << ">" + << "\n"; + + int err_code = 0; + + /* Write each bus */ + for (const ClockTreeId& tree_id : clk_ntwk.trees()) { + /* Write bus */ + err_code = write_xml_clock_tree(fp, clk_ntwk, tree_id); + if (0 != err_code) { + return err_code; + } + } + + /* Finish writing the root node */ + fp << "" + << "\n"; + + /* Close the file stream */ + fp.close(); + + return err_code; +} + +} // End of namespace openfpga diff --git a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.h b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.h new file mode 100644 index 000000000..3019b414a --- /dev/null +++ b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.h @@ -0,0 +1,20 @@ +#ifndef WRITE_XML_CLOCK_NETWORK_H +#define WRITE_XML_CLOCK_NETWORK_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include + +#include "clock_network.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ +namespace openfpga { // Begin namespace openfpga + +int write_xml_clock_network(const char* fname, const ClockNetwork& clk_ntwk); + +} // End of namespace openfpga + +#endif