[core] support intermediate driver in clock arch

This commit is contained in:
tangxifan 2024-09-20 17:42:26 -07:00
parent 9a9d684f58
commit 965ee2190e
6 changed files with 172 additions and 1 deletions

View File

@ -1,6 +1,11 @@
<clock_networks default_segment="seg_len1" default_tap_switch="fast_switch" default_driver_switch="slow_switch">
<clock_network name="example_network" global_port="clk[0:7]">
<spine name="spine_lvl3" start_x="0" start_y="2" end_x="2" end_y="2">
<intermediate_driver x="1" y="2">
<tap from_pin="clb.O[0:0]" to_pin="clk[0:0]"/>
<tap from_pin="clb.O[1:1]" to_pin="clk[1:1]"/>
<tap from_pin="clb.O[2:3]" to_pin="clk[2:2]"/>
</intermediate_driver>
<switch_point tap="spine_lvl2_upper" x="2" y="2">
<internal_driver from_pin="clb.O[0:3]" to_pin="clk[1:1]"/>
</switch_point>

View File

@ -270,6 +270,18 @@ vtr::Point<int> ClockNetwork::spine_end_point(
return spine_end_points_[spine_id];
}
std::vector<ClockInternalDriverId> ClockNetwork::spine_intermediate_drivers(
const ClockSpineId& spine_id, const vtr::Point<int>& coord) const {
VTR_ASSERT(valid_spine_id(spine_id));
/* Convert coord to a unique string */
std::string coord_str = std::to_string(coord.x()) + std::string(",") + std::to_string(coord.y());
auto result = spine_intermediate_drivers_[spine_id].find(coord_str);
if (result == spine_intermediate_drivers_[spine_id].end()) {
return std::vector<ClockInternalDriverId>();
}
return result->second;
}
ClockLevelId ClockNetwork::spine_level(const ClockSpineId& spine_id) const {
VTR_ASSERT(valid_spine_id(spine_id));
if (is_dirty_) {
@ -624,6 +636,7 @@ void ClockNetwork::reserve_spines(const size_t& num_spines) {
spine_switch_points_.reserve(num_spines);
spine_switch_coords_.reserve(num_spines);
spine_switch_internal_drivers_.reserve(num_spines);
spine_intermediate_drivers_.reserve(num_spines);
spine_parents_.reserve(num_spines);
spine_children_.reserve(num_spines);
spine_parent_trees_.reserve(num_spines);
@ -716,6 +729,7 @@ ClockSpineId ClockNetwork::create_spine(const std::string& name) {
spine_switch_points_.emplace_back();
spine_switch_coords_.emplace_back();
spine_switch_internal_drivers_.emplace_back();
spine_intermediate_drivers_.emplace_back();
spine_parents_.emplace_back();
spine_children_.emplace_back();
spine_parent_trees_.emplace_back();
@ -817,6 +831,45 @@ ClockInternalDriverId ClockNetwork::add_spine_switch_point_internal_driver(
return int_driver_id;
}
ClockInternalDriverId ClockNetwork::add_spine_intermediate_driver(
const ClockSpineId& spine_id, const vtr::Point<int>& coord,
const std::string& int_driver_from_port,
const std::string& int_driver_to_port) {
VTR_ASSERT(valid_spine_id(spine_id));
/* Convert coord to a unique string */
std::string coord_str = std::to_string(coord.x()) + std::string(",") + std::to_string(coord.y());
/* Parse ports */
PortParser to_pin_parser(int_driver_to_port);
/* Find any existing id for the driver port */
ClockInternalDriverId int_driver_id_to_add = ClockInternalDriverId(internal_driver_ids_.size());
for (ClockInternalDriverId int_driver_id : internal_driver_ids_) {
if (internal_driver_from_pins_[int_driver_id] == int_driver_from_port &&
internal_driver_to_pins_[int_driver_id] == to_pin_parser.port()) {
int_driver_id_to_add = int_driver_id;
break;
}
}
/* Reaching here, no existing id can be reused, create a new one */
if (int_driver_id_to_add == ClockInternalDriverId(internal_driver_ids_.size())) {
internal_driver_ids_.push_back(int_driver_id_to_add);
internal_driver_from_pins_.push_back(int_driver_from_port);
internal_driver_to_pins_.push_back(to_pin_parser.port());
}
/* Add it to existing map, avoid duplicated id */
auto result = spine_intermediate_drivers_[spine_id].find(coord_str);
if (result == spine_intermediate_drivers_[spine_id].end()) {
spine_intermediate_drivers_[spine_id][coord_str].push_back(int_driver_id_to_add);
} else {
if (std::find(result->second.begin(), result->second.end(), int_driver_id_to_add) == result->second.end()) {
result->second.push_back(int_driver_id_to_add);
} else {
VTR_LOG_WARN("Skip intermediate driver (from_port='%s', to_port='%s') at (%s) as it is duplicated in the clock architecture description file!\n",
int_driver_from_port.c_str(), int_driver_to_port.c_str(), coord_str.c_str());
}
}
return int_driver_id_to_add;
}
ClockTapId ClockNetwork::add_tree_tap(const ClockTreeId& tree_id,
const BasicPort& from_port,
const std::string& to_port) {

View File

@ -97,6 +97,8 @@ class ClockNetwork {
std::string spine_name(const ClockSpineId& spine_id) const;
vtr::Point<int> spine_start_point(const ClockSpineId& spine_id) const;
vtr::Point<int> spine_end_point(const ClockSpineId& spine_id) const;
std::vector<ClockInternalDriverId> spine_intermediate_drivers(const ClockSpineId& spine_id, const vtr::Point<int>& coord) const;
/* Return the level where the spine locates in the multi-layer clock tree
* structure */
ClockLevelId spine_level(const ClockSpineId& spine_id) const;
@ -227,6 +229,10 @@ class ClockNetwork {
const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id,
const std::string& internal_driver_from_port,
const std::string& internal_driver_to_port);
ClockInternalDriverId add_spine_intermediate_driver(
const ClockSpineId& spine_id, const vtr::Point<int>& coord,
const std::string& internal_driver_from_port,
const std::string& internal_driver_to_port);
ClockTapId add_tree_tap(const ClockTreeId& tree_id,
const BasicPort& from_port,
const std::string& to_port);
@ -314,6 +320,7 @@ class ClockNetwork {
vtr::vector<ClockSpineId, std::vector<vtr::Point<int>>> spine_switch_coords_;
vtr::vector<ClockSpineId, std::vector<std::vector<ClockInternalDriverId>>>
spine_switch_internal_drivers_;
vtr::vector<ClockSpineId, std::map<std::string, std::vector<ClockInternalDriverId>>> spine_intermediate_drivers_;
vtr::vector<ClockSpineId, ClockSpineId> spine_parents_;
vtr::vector<ClockSpineId, std::vector<ClockSpineId>> spine_children_;
vtr::vector<ClockSpineId, ClockTreeId> spine_parent_trees_;

View File

@ -21,6 +21,12 @@ constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_END_X = "end_x";
constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_END_Y = "end_y";
constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_TYPE = "type";
constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_DIRECTION = "direction";
constexpr const char* XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_NODE_NAME = "intermediate_driver";
constexpr const char* XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_TAP_NODE_NAME = "tap";
constexpr const char* XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_X = "x";
constexpr const char* XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_Y = "y";
constexpr const char* XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_FROM_PIN = "from_pin";
constexpr const char* XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_TO_PIN = "to_pin";
constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_NODE_NAME = "switch_point";
constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_NODE_NAME =
"internal_driver";

View File

@ -178,6 +178,32 @@ static void read_xml_clock_spine_switch_point_internal_driver(
int_driver_to_port_name);
}
/********************************************************************
* Parse XML codes of a <tap> to an object of ClockNetwork
*******************************************************************/
static void read_xml_clock_spine_intermediate_driver_tap(
pugi::xml_node& xml_int_driver, const pugiutil::loc_data& loc_data,
ClockNetwork& clk_ntwk, const ClockSpineId& spine_id,
const vtr::Point<int>& spine_coord) {
if (!clk_ntwk.valid_spine_id(spine_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_int_driver),
"Invalid id of a clock spine!\n");
}
std::string int_driver_from_port_name =
get_attribute(
xml_int_driver,
XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_FROM_PIN, loc_data)
.as_string();
std::string int_driver_to_port_name =
get_attribute(xml_int_driver,
XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_TO_PIN,
loc_data)
.as_string();
clk_ntwk.add_spine_intermediate_driver(spine_id, spine_coord, int_driver_from_port_name,
int_driver_to_port_name);
}
/********************************************************************
* Parse XML codes of a <switch_point> to an object of ClockNetwork
*******************************************************************/
@ -229,6 +255,38 @@ static void read_xml_clock_spine_switch_point(
}
}
/********************************************************************
* Parse XML codes of a <driver> to an object of ClockNetwork
*******************************************************************/
static void read_xml_clock_spine_intermediate_driver(
pugi::xml_node& xml_driver, const pugiutil::loc_data& loc_data,
ClockNetwork& clk_ntwk, const ClockSpineId& spine_id) {
if (!clk_ntwk.valid_spine_id(spine_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_driver),
"Invalid id of a clock spine!\n");
}
int tap_x = get_attribute(xml_driver,
XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_X, loc_data)
.as_int();
int tap_y = get_attribute(xml_driver,
XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_Y, loc_data)
.as_int();
/* Add internal drivers if possible */
for (pugi::xml_node xml_int_driver : xml_driver.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_int_driver.name() ==
std::string(XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_TAP_NODE_NAME)) {
read_xml_clock_spine_intermediate_driver_tap(
xml_int_driver, loc_data, clk_ntwk, spine_id, vtr::Point<int>(tap_x, tap_y));
} else {
bad_tag(xml_int_driver, loc_data, xml_driver,
{XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_TAP_NODE_NAME});
}
}
}
/********************************************************************
* Convert string to the enumerate of model type
*******************************************************************/
@ -333,9 +391,14 @@ static void read_xml_clock_spine(pugi::xml_node& xml_spine,
std::string(XML_CLOCK_SPINE_SWITCH_POINT_NODE_NAME)) {
read_xml_clock_spine_switch_point(xml_switch_point, loc_data, clk_ntwk,
spine_id);
} else if (xml_switch_point.name() ==
std::string(XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_NODE_NAME)) {
read_xml_clock_spine_intermediate_driver(xml_switch_point, loc_data, clk_ntwk,
spine_id);
} else {
bad_tag(xml_switch_point, loc_data, xml_spine,
{XML_CLOCK_SPINE_SWITCH_POINT_NODE_NAME});
{XML_CLOCK_SPINE_SWITCH_POINT_NODE_NAME, XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_NODE_NAME});
}
}
}

View File

@ -142,6 +142,39 @@ static int write_xml_clock_spine_switch_point(
return 0;
}
static int write_xml_clock_spine_intermediate_drivers(
std::fstream& fp, const ClockNetwork& clk_ntwk, const ClockSpineId& spine_id,
const vtr::Point<int>& coord) {
std::vector<ClockInternalDriverId> int_drivers = clk_ntwk.spine_intermediate_drivers(spine_id, coord);
if (int_drivers.empty()) {
return 0;
}
openfpga::write_tab_to_file(fp, 3);
fp << "<" << XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_NODE_NAME << "";
write_xml_attribute(fp, XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_X, coord.x());
write_xml_attribute(fp, XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_Y, coord.y());
for (ClockInternalDriverId int_driver_id : int_drivers) {
openfpga::write_tab_to_file(fp, 4);
fp << "<" << XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_TAP_NODE_NAME;
write_xml_attribute(
fp, XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_FROM_PIN,
clk_ntwk.internal_driver_from_pin(int_driver_id).c_str());
write_xml_attribute(
fp, XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_ATTRIBUTE_TO_PIN,
clk_ntwk.internal_driver_to_pin(int_driver_id)
.to_verilog_string()
.c_str());
fp << "/>"
<< "\n";
}
fp << "</" << XML_CLOCK_SPINE_INTERMEDIATE_DRIVER_NODE_NAME << ">\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);
@ -166,6 +199,10 @@ static int write_xml_clock_spine(std::fstream& fp, const ClockNetwork& clk_ntwk,
fp << ">"
<< "\n";
for (const vtr::Point<int>& coord : clk_ntwk.spine_coordinates(spine_id)) {
write_xml_clock_spine_intermediate_drivers(fp, clk_ntwk, spine_id, coord);
}
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);