From 381a8cb53548e5c1402d46606d6cf3c22aa1050d Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 26 Jun 2024 15:41:56 -0700 Subject: [PATCH] [lib] clock tap syntax are reworked. Support region, single, all and from/to ports --- .../src/base/clock_network.cpp | 113 +++++++++++++++++- .../src/base/clock_network.h | 52 +++++++- .../src/base/clock_network_fwd.h | 2 + .../src/io/clock_network_xml_constants.h | 15 ++- .../src/io/read_xml_clock_network.cpp | 101 ++++++++++++++-- .../src/io/write_xml_clock_network.cpp | 63 ++++++++-- 6 files changed, 314 insertions(+), 32 deletions(-) diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index 20e1f116c..69fbed21b 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -20,6 +20,8 @@ ClockNetwork::ClockNetwork() { default_segment_id_ = RRSegmentId::INVALID(); default_tap_switch_id_ = RRSwitchId::INVALID(); default_driver_switch_id_ = RRSwitchId::INVALID(); + /* Set a default invalid bounding box */ + empty_tap_bb_ = vtr::Rect(1, 0, 1, 0); is_dirty_ = true; } @@ -345,17 +347,67 @@ std::string ClockNetwork::internal_driver_port( return internal_driver_ports_[int_driver_id]; } -std::vector ClockNetwork::tree_taps( +std::vector ClockNetwork::tree_taps( const ClockTreeId& tree_id) const { VTR_ASSERT(valid_tree_id(tree_id)); return tree_taps_[tree_id]; } -std::vector ClockNetwork::tree_flatten_taps( +std::string ClockNetwork::tap_from_port(const ClockTapId& tap_id) const { + VTR_ASSERT(valid_tap_id(tap_id)); + return tap_from_ports_[tap_id]; +} + +std::string ClockNetwork::tap_to_port(const ClockTapId& tap_id) const { + VTR_ASSERT(valid_tap_id(tap_id)); + return tap_to_ports_[tap_id]; +} + +ClockNetwork::e_tap_type ClockNetwork::tap_type(const ClockTapId& tap_id) const { + VTR_ASSERT(valid_tap_id(tap_id)); + /* If not a region, it is a default type covering all the coordinates*/ + if (tap_bbs_[tap_id] == empty_tap_bb_) { + return ClockNetwork::e_tap_type::ALL; + } + /* Now check if this a single point */ + if (tap_bbs_[tap_id].height() == 0 && tap_bbs_[tap_id].width() == 0) { + return ClockNetwork::e_tap_type::SINGLE; + } + return ClockNetwork::e_tap_type::REGION; +} + +size_t ClockNetwork::tap_x(const ClockTapId& tap_id) const { + VTR_ASSERT(tap_type(tap_id) == ClockNetwork::e_tap_type::SINGLE); + return tap_bbs_[tap_id].xmin(); +} + +size_t ClockNetwork::tap_y(const ClockTapId& tap_id) const { + VTR_ASSERT(tap_type(tap_id) == ClockNetwork::e_tap_type::SINGLE); + return tap_bbs_[tap_id].ymin(); +} + +vtr::Rect ClockNetwork::tap_bounding_box(const ClockTapId& tap_id) const { + VTR_ASSERT(tap_type(tap_id) == ClockNetwork::e_tap_type::REGION); + return tap_bbs_[tap_id]; +} + +size_t ClockNetwork::tap_step_x(const ClockTapId& tap_id) const { + VTR_ASSERT(tap_type(tap_id) == ClockNetwork::e_tap_type::REGION); + return tap_bb_steps_[tap_id].x(); +} + +size_t ClockNetwork::tap_step_y(const ClockTapId& tap_id) const { + VTR_ASSERT(tap_type(tap_id) == ClockNetwork::e_tap_type::REGION); + return tap_bb_steps_[tap_id].y(); +} + +std::vector ClockNetwork::tree_flatten_tap_to_ports( const ClockTreeId& tree_id, const ClockTreePinId& clk_pin_id) const { VTR_ASSERT(valid_tree_id(tree_id)); std::vector flatten_taps; - for (const std::string& tap_name : tree_taps_[tree_id]) { + for (ClockTapId tap_id : tree_taps_[tree_id]) { + VTR_ASSERT(valid_tap_id(tap_id)); + std::string tap_name = tap_to_ports_[tap_id]; StringToken tokenizer(tap_name); std::vector pin_tokens = tokenizer.split("."); if (pin_tokens.size() != 2) { @@ -649,10 +701,53 @@ ClockInternalDriverId ClockNetwork::add_spine_switch_point_internal_driver( return int_driver_id; } -void ClockNetwork::add_tree_tap(const ClockTreeId& tree_id, - const std::string& pin_name) { +ClockTapId ClockNetwork::add_tree_tap(const ClockTreeId& tree_id, + const std::string& from_port, + const std::string& to_port, + const ) { VTR_ASSERT(valid_tree_id(tree_id)); - tree_taps_[tree_id].push_back(pin_name); + /* TODO: Consider find existing tap template and avoid duplication in storage */ + ClockTapId tap_id = ClockTapId(tap_ids_.size()); + tap_ids_.push_back(tap_id); + tap_from_ports_.push_back(from_port); + tap_to_ports_.push_back(to_port); + tap_bbs_.emplace_back(empty_tap_bb_); + tap_bb_steps_.emplace_back(vtr::Point(1, 1)); + tree_taps_[tree_id].push_back(tap_id); + return tap_id; +} + +bool ClockNetwork::set_tap_bounding_box(const ClockTapId& tap_id, const vtr::Rect& bb) { + VTR_ASSERT(valid_tap_id(tap_id)); + /* Check the bounding box, ensure it must be valid */ + if (bb.height() < 0 || bb.width() < 0) { + VTR_LOG_ERROR("Invalid bounding box (xlow=%lu, ylow=%lu) -> (xhigh=%lu, yhigh=%lu)! Must follow: xlow <= xhigh, ylow <= yhigh!\n", bb.xmin(), bb.ymin(), bb.xmax(), bb.ymax()); + return false; + } + tap_bbs_[tap_id] = bb; + return true; +} + +bool ClockNetwork::set_tap_step_x(const ClockTapId& tap_id, const size_t step) { + VTR_ASSERT(valid_tap_id(tap_id)); + /* Must be a valid step >= 1 */ + if (step == 0) { + VTR_LOG_ERROR("Invalid x-direction step (=%lu) for any bounding box! Expect an integer >= 1!\n", step); + return false; + } + tap_bbs_[tap_id].set_x(step); + return true; +} + +bool ClockNetwork::set_tap_step_y(const ClockTapId& tap_id, const size_t step) { + VTR_ASSERT(valid_tap_id(tap_id)); + /* Must be a valid step >= 1 */ + if (step == 0) { + VTR_LOG_ERROR("Invalid y-direction step (=%lu) for any bounding box! Expect an integer >= 1!\n", step); + return false; + } + tap_bbs_[tap_id].set_y(step); + return true; } bool ClockNetwork::link() { @@ -807,6 +902,12 @@ bool ClockNetwork::valid_internal_driver_id( (int_driver_id == internal_driver_ids_[int_driver_id]); } +bool ClockNetwork::valid_tap_id( + const ClockTapId& tap_id) const { + return (size_t(tap_id) < tap_ids_.size()) && + (tap_id == tap_ids_[tap_id]); +} + bool ClockNetwork::valid_level_id(const ClockTreeId& tree_id, const ClockLevelId& lvl_id) const { return valid_tree_id(tree_id) && (size_t(lvl_id) < tree_depth(tree_id)); diff --git a/libs/libclkarchopenfpga/src/base/clock_network.h b/libs/libclkarchopenfpga/src/base/clock_network.h index 8884f5c55..f440c397c 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.h +++ b/libs/libclkarchopenfpga/src/base/clock_network.h @@ -48,6 +48,13 @@ class ClockNetwork { /* Create range */ typedef vtr::Range clock_internal_driver_range; + /* Type of tap points */ + enum class : unsigned char { + ALL = 0, + SINGLE, + REGION, + NUM_TYPES + }; public: /* Constructors */ ClockNetwork(); @@ -133,12 +140,30 @@ class ClockNetwork { /* Return the original list of tap pins that is in storage; useful for parsers */ - std::vector tree_taps(const ClockTreeId& tree_id) const; + std::vector tree_taps(const ClockTreeId& tree_id) const; + /* Return the source ports for a given tap */ + std::string tap_from_port(const ClockTapId& tap_id) const; + /* Return the destination ports for a given tap */ + std::string tap_to_port(const ClockTapId& tap_id) const; + /* Find the type of tap point: + * all -> all coordinates in efpga are required to tap + * single -> only 1 coordinate is required to tap + * region -> coordinates in a region required to tap. Steps in region may be required + */ + e_tap_type tap_type(const ClockTapId& tap_id) const; + /* Require the type of single */ + size_t tap_x(const ClockTapId& tap_id) const; + size_t tap_y(const ClockTapId& tap_id) const; + /* Require the type of region */ + vtr::Rect tap_bounding_box(const ClockTapId& tap_id) const; + /* Steps are only available when type is region */ + size_t tap_step_x(const ClockTapId& tap_id) const; + size_t tap_step_y(const ClockTapId& tap_id) const; /* Return the list of flatten tap pins. For example: clb[0:1].clk[2:2] is * flatten to { clb[0].clk[2], clb[1].clk[2] } Useful to build clock routing * resource graph Note that the clk_pin_id limits only 1 clock to be accessed */ - std::vector tree_flatten_taps( + std::vector tree_flatten_tap_to_ports( const ClockTreeId& tree_id, const ClockTreePinId& clk_pin_id) const; /* Find a spine with a given name, if not found, return an valid id, otherwise * return an invalid one */ @@ -193,7 +218,10 @@ class ClockNetwork { ClockInternalDriverId add_spine_switch_point_internal_driver( const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id, const std::string& internal_driver_port); - void add_tree_tap(const ClockTreeId& tree_id, const std::string& pin_name); + ClockTapId add_tree_tap(const ClockTreeId& tree_id, const std::string& from_port, const std::string& to_port); + bool set_tap_bounding_box(const ClockTapId& tap_id, const vtr::Rect& bb); + bool set_tap_step_x(const ClockTapId& tap_id, const size_t& step); + bool set_tap_step_y(const ClockTapId& tap_id, const size_t& step); /* Build internal links between clock tree, spines etc. This is also an * validator to verify the correctness of the clock network. Must run before * using the data! */ @@ -202,8 +230,6 @@ class ClockNetwork { public: /* Public invalidators/validators */ /* Show if the tree id is a valid for data queries */ bool valid_tree_id(const ClockTreeId& tree_id) const; - bool valid_internal_driver_id( - const ClockInternalDriverId& int_driver_id) const; /* Show if the level id is a valid for a given tree */ bool valid_level_id(const ClockTreeId& tree_id, const ClockLevelId& lvl_id) const; @@ -233,6 +259,11 @@ class ClockNetwork { /* Ensure tree data is clean. All the spines are valid, and switch points are * valid */ bool validate_tree() const; + /* Show if the internal driver id is a valid for data queries */ + bool valid_internal_driver_id( + const ClockInternalDriverId& int_driver_id) const; + /* Show if the tap id is a valid for data queries */ + bool valid_tap_id(const ClockTapId& tap_id) const; private: /* Private mutators */ /* Build internal links between spines under a given tree */ @@ -253,7 +284,7 @@ class ClockNetwork { vtr::vector tree_widths_; vtr::vector tree_depths_; vtr::vector> tree_top_spines_; - vtr::vector> tree_taps_; + vtr::vector tree_taps_; /* Basic information of each spine */ vtr::vector spine_ids_; @@ -275,6 +306,12 @@ class ClockNetwork { vtr::vector internal_driver_ids_; vtr::vector internal_driver_ports_; + /* Basic information about tap */ + vtr::vector tap_ids_; + vtr::vector tap_from_ports_; + vtr::vector tap_to_ports_; + vtr::vector> tap_bbs_; /* Bounding box for tap points, (xlow, ylow) -> (xhigh, yhigh) */ + vtr::vector> tap_bb_steps_; /* x() -> x-direction step, y() -> y-direction step */ /* Default routing resource */ std::string default_segment_name_; /* The routing segment representing the @@ -291,6 +328,9 @@ class ClockNetwork { std::map tree_name2id_map_; std::map spine_name2id_map_; + /* Constants */ + vtr::Rect empty_tap_bb_; + /* Flags */ mutable bool is_dirty_; }; diff --git a/libs/libclkarchopenfpga/src/base/clock_network_fwd.h b/libs/libclkarchopenfpga/src/base/clock_network_fwd.h index e9602d384..dc329d04b 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network_fwd.h +++ b/libs/libclkarchopenfpga/src/base/clock_network_fwd.h @@ -20,6 +20,7 @@ struct clock_tree_pin_id_tag; struct clock_spine_id_tag; struct clock_switch_point_id_tag; struct clock_internal_driver_id_tag; +struct clock_tap_id_tag; typedef vtr::StrongId ClockLevelId; typedef vtr::StrongId ClockTreeId; @@ -27,6 +28,7 @@ typedef vtr::StrongId ClockTreePinId; typedef vtr::StrongId ClockSpineId; typedef vtr::StrongId ClockSwitchPointId; typedef vtr::StrongId ClockInternalDriverId; +typedef vtr::StrongId ClockTapId; /* Short declaration of class */ class ClockNetwork; diff --git a/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h b/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h index 14b2f1204..cfa5c306d 100644 --- a/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h +++ b/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h @@ -30,7 +30,18 @@ constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_TAP = "tap"; constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_X = "x"; constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_Y = "y"; constexpr const char* XML_CLOCK_TREE_TAPS_NODE_NAME = "taps"; -constexpr const char* XML_CLOCK_TREE_TAP_NODE_NAME = "tap"; -constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_TILE_PIN = "tile_pin"; +constexpr const char* XML_CLOCK_TREE_TAP_ALL_NODE_NAME = "all"; +constexpr const char* XML_CLOCK_TREE_TAP_REGION_NODE_NAME = "region"; +constexpr const char* XML_CLOCK_TREE_TAP_SINGLE_NODE_NAME = "single"; +constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN = "from_pin"; +constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN = "to_pin"; +constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_X = "x"; +constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_Y = "y"; +constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTX = "start_x"; +constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTY = "start_y"; +constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDX = "end_x"; +constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDY = "end_y"; +constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_REPEATX = "repeat_x"; +constexpr const char* XML_CLOCK_TREE_TAP_ATTRIBUTE_REPEATY = "repeat_y"; #endif diff --git a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp index 152b4ae35..2c8e8fdfe 100644 --- a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp @@ -25,10 +25,10 @@ namespace openfpga { // Begin namespace openfpga /******************************************************************** - * Parse XML codes of a to an object of ClockNetwork + * Parse XML codes of a to an object of ClockNetwork *******************************************************************/ -static void read_xml_clock_tree_tap(pugi::xml_node& xml_tap, - const pugiutil::loc_data& loc_data, +static void read_xml_clock_tree_tap_type_all(pugi::xml_node& xml_tap, + const pugiutil::loc_data& loc_data, ClockNetwork& clk_ntwk, const ClockTreeId& tree_id) { if (!clk_ntwk.valid_tree_id(tree_id)) { @@ -36,10 +36,89 @@ static void read_xml_clock_tree_tap(pugi::xml_node& xml_tap, "Invalid id of a clock tree!\n"); } - std::string tile_pin_name = - get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_TILE_PIN, loc_data) + std::string from_pin_name = + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN, loc_data) .as_string(); - clk_ntwk.add_tree_tap(tree_id, tile_pin_name); + std::string to_pin_name = + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN, loc_data) + .as_string(); + clk_ntwk.add_tree_tap(tree_id, from_pin_name, to_pin_name); +} + +/******************************************************************** + * Parse XML codes of a to an object of ClockNetwork + *******************************************************************/ +static void read_xml_clock_tree_tap_type_single(pugi::xml_node& xml_tap, + const pugiutil::loc_data& loc_data, + ClockNetwork& clk_ntwk, + const ClockTreeId& tree_id) { + if (!clk_ntwk.valid_tree_id(tree_id)) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_tap), + "Invalid id of a clock tree!\n"); + } + + std::string from_pin_name = + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN, loc_data) + .as_string(); + std::string to_pin_name = + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN, loc_data) + .as_string(); + ClockTapId tap_id = clk_ntwk.add_tree_tap(tree_id, from_pin_name, to_pin_name); + + /* Single tap only require a coordinate */ + size_t tap_x = + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_X, loc_data, pugi::ReqOpt::REQUIRED) + .as_int(); + size_t tap_y = + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_Y, loc_data, pugi::ReqOpt::REQUIRED) + .as_int(); + clk_ntwk.set_tap_bounding_box(tap_id, vtr::Rect(tap_x, tap_y, tap_x, tap_y)); +} + +/******************************************************************** + * Parse XML codes of a to an object of ClockNetwork + *******************************************************************/ +static void read_xml_clock_tree_tap_type_region(pugi::xml_node& xml_tap, + const pugiutil::loc_data& loc_data, + ClockNetwork& clk_ntwk, + const ClockTreeId& tree_id) { + if (!clk_ntwk.valid_tree_id(tree_id)) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_tap), + "Invalid id of a clock tree!\n"); + } + + std::string from_pin_name = + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN, loc_data) + .as_string(); + std::string to_pin_name = + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN, loc_data) + .as_string(); + ClockTapId tap_id = clk_ntwk.add_tree_tap(tree_id, from_pin_name, to_pin_name); + + /* Region require a bounding box */ + size_t tap_start_x = + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTX, loc_data, pugi::ReqOpt::REQUIRED) + .as_int(); + size_t tap_start_y = + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTY, loc_data, pugi::ReqOpt::REQUIRED) + .as_int(); + size_t tap_end_x = + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDX, loc_data, pugi::ReqOpt::REQUIRED) + .as_int(); + size_t tap_end_y = + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDY, loc_data, pugi::ReqOpt::REQUIRED) + .as_int(); + clk_ntwk.set_tap_bounding_box(tap_id, vtr::Rect(tap_start_x, tap_start_y, tap_end_x, tap_end_y)); + + /* Default step is all 1 */ + size_t tap_step_x = + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_REPEATX, loc_data) + .as_int(1); + size_t tap_step_y = + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_REPEATY, loc_data) + .as_int(1); + clk_ntwk.set_tap_step_x(tap_id, tap_step_x); + clk_ntwk.set_tap_step_y(tap_id, tap_step_y); } static void read_xml_clock_tree_taps(pugi::xml_node& xml_taps, @@ -48,10 +127,14 @@ static void read_xml_clock_tree_taps(pugi::xml_node& xml_taps, const ClockTreeId& tree_id) { for (pugi::xml_node xml_tap : xml_taps.children()) { /* Error out if the XML child has an invalid name! */ - if (xml_tap.name() == std::string(XML_CLOCK_TREE_TAP_NODE_NAME)) { - read_xml_clock_tree_tap(xml_tap, loc_data, clk_ntwk, tree_id); + if (xml_tap.name() == std::string(XML_CLOCK_TREE_TAP_ALL_NODE_NAME)) { + read_xml_clock_tree_tap_type_all(xml_tap, loc_data, clk_ntwk, tree_id); + } else if (xml_tap.name() == std::string(XML_CLOCK_TREE_TAP_REGION_NODE_NAME)) { + read_xml_clock_tree_tap_type_region(xml_tap, loc_data, clk_ntwk, tree_id); + } else if (xml_tap.name() == std::string(XML_CLOCK_TREE_TAP_SINGLE_NODE_NAME)) { + read_xml_clock_tree_tap_type_single(xml_tap, loc_data, clk_ntwk, tree_id); } else { - bad_tag(xml_taps, loc_data, xml_tap, {XML_CLOCK_TREE_TAP_NODE_NAME}); + bad_tag(xml_taps, loc_data, xml_tap, {XML_CLOCK_TREE_TAP_ALL_NODE_NAME, XML_CLOCK_TREE_TAP_REGION_NODE_NAME, XML_CLOCK_TREE_TAP_SINGLE_NODE_NAME}); } } } diff --git a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp index 76d10fbe8..addb745ed 100644 --- a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp @@ -28,15 +28,60 @@ static int write_xml_clock_tree_taps(std::fstream& fp, const ClockTreeId& tree_id) { openfpga::write_tab_to_file(fp, 3); fp << "<" << XML_CLOCK_TREE_TAPS_NODE_NAME << ">\n"; - for (const std::string& tile_pin_name : clk_ntwk.tree_taps(tree_id)) { - openfpga::write_tab_to_file(fp, 4); - fp << "<" << XML_CLOCK_TREE_TAP_NODE_NAME << ""; - - write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_TILE_PIN, - tile_pin_name.c_str()); - fp << "/>" - << "\n"; - } + /* Depends on the type */ + for (ClockTapId tap_id : clk_ntwk.tree_taps(tree_id)) { + switch clk_ntwk.tap_type(tap_id): { + case ClockNetwork::e_tap_type::ALL: { + openfpga::write_tab_to_file(fp, 4); + fp << "<" << XML_CLOCK_TREE_TAP_ALL_NODE_NAME << ""; + write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN, + clk_ntwk.tap_from_port(tap_id).c_str()); + write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN, + clk_ntwk.tap_to_port(tap_id).c_str()); + fp << "/>" + << "\n"; + } + case ClockNetwork::e_tap_type::SINGLE: { + openfpga::write_tab_to_file(fp, 4); + fp << "<" << XML_CLOCK_TREE_TAP_SINGLE_NODE_NAME << ""; + write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN, + clk_ntwk.tap_from_port(tap_id).c_str()); + write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN, + clk_ntwk.tap_to_port(tap_id).c_str()); + write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_X, + clk_ntwk.tap_x(tap_id)); + write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_Y, + clk_ntwk.tap_y(tap_id)); + fp << "/>" + << "\n"; + } + case ClockNetwork::e_tap_type::REGION: { + openfpga::write_tab_to_file(fp, 4); + fp << "<" << XML_CLOCK_TREE_TAP_SINGLE_NODE_NAME << ""; + write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN, + clk_ntwk.tap_from_port(tap_id).c_str()); + write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN, + clk_ntwk.tap_to_port(tap_id).c_str()); + write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTX, + clk_ntwk.tap_bounding_box(tap_id).xmin()); + write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTY, + clk_ntwk.tap_bounding_box(tap_id).ymin()); + write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDX, + clk_ntwk.tap_bounding_box(tap_id).xmax()); + write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDY, + clk_ntwk.tap_bounding_box(tap_id).ymax()); + write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_REPEATX, + clk_ntwk.tap_step_x(tap_id)); + write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_REPEATY, + clk_ntwk.tap_step_y(tap_id)); + fp << "/>" + << "\n"; + } + default: { + VTR_LOG_ERROR("Invalid type of tap point!\n"); + return 1; + } + } openfpga::write_tab_to_file(fp, 3); fp << "\n";