[lib] clock tap syntax are reworked. Support region, single, all and from/to ports

This commit is contained in:
tangxifan 2024-06-26 15:41:56 -07:00
parent ec1ad94d4a
commit 381a8cb535
6 changed files with 314 additions and 32 deletions

View File

@ -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<size_t>(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<std::string> ClockNetwork::tree_taps(
std::vector<ClockTapId> ClockNetwork::tree_taps(
const ClockTreeId& tree_id) const {
VTR_ASSERT(valid_tree_id(tree_id));
return tree_taps_[tree_id];
}
std::vector<std::string> 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<size_t> 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<std::string> 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<std::string> 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<std::string> 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<size_t>(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<size_t>& 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));

View File

@ -48,6 +48,13 @@ class ClockNetwork {
/* Create range */
typedef vtr::Range<clock_internal_driver_iterator>
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<std::string> tree_taps(const ClockTreeId& tree_id) const;
std::vector<ClockTapId> 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<size_t> 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<std::string> tree_flatten_taps(
std::vector<std::string> 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<size_t>& 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<ClockTreeId, size_t> tree_widths_;
vtr::vector<ClockTreeId, size_t> tree_depths_;
vtr::vector<ClockTreeId, std::vector<ClockSpineId>> tree_top_spines_;
vtr::vector<ClockTreeId, std::vector<std::string>> tree_taps_;
vtr::vector<ClockTreeId, ClockTapId> tree_taps_;
/* Basic information of each spine */
vtr::vector<ClockSpineId, ClockSpineId> spine_ids_;
@ -275,6 +306,12 @@ class ClockNetwork {
vtr::vector<ClockInternalDriverId, ClockInternalDriverId>
internal_driver_ids_;
vtr::vector<ClockInternalDriverId, std::string> internal_driver_ports_;
/* Basic information about tap */
vtr::vector<ClockTapId, ClockTapId> tap_ids_;
vtr::vector<ClockTapId, std::string> tap_from_ports_;
vtr::vector<ClockTapId, std::string> tap_to_ports_;
vtr::vector<ClockTapId, vtr::Rect<size_t>> tap_bbs_; /* Bounding box for tap points, (xlow, ylow) -> (xhigh, yhigh) */
vtr::vector<ClockTapId, vtr::Point<size_t>> 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<std::string, ClockTreeId> tree_name2id_map_;
std::map<std::string, ClockSpineId> spine_name2id_map_;
/* Constants */
vtr::Rect<size_t> empty_tap_bb_;
/* Flags */
mutable bool is_dirty_;
};

View File

@ -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<clock_level_id_tag> ClockLevelId;
typedef vtr::StrongId<clock_tree_id_tag> ClockTreeId;
@ -27,6 +28,7 @@ typedef vtr::StrongId<clock_tree_pin_id_tag> ClockTreePinId;
typedef vtr::StrongId<clock_spine_id_tag> ClockSpineId;
typedef vtr::StrongId<clock_switch_point_id_tag> ClockSwitchPointId;
typedef vtr::StrongId<clock_internal_driver_id_tag> ClockInternalDriverId;
typedef vtr::StrongId<clock_tap_id_tag> ClockTapId;
/* Short declaration of class */
class ClockNetwork;

View File

@ -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

View File

@ -25,10 +25,10 @@
namespace openfpga { // Begin namespace openfpga
/********************************************************************
* Parse XML codes of a <tap> to an object of ClockNetwork
* Parse XML codes of a <all> 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 <single> 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<size_t>(tap_x, tap_y, tap_x, tap_y));
}
/********************************************************************
* Parse XML codes of a <region> 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<size_t>(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});
}
}
}

View File

@ -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 << "</" << XML_CLOCK_TREE_TAPS_NODE_NAME << ">\n";