From 9ccd14bf4d674c3fdffc5b7fd1d03367398e40ca Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 21 Jun 2024 16:45:05 -0700 Subject: [PATCH 01/86] [lib] now default switch of clk ntwk is split to default_tap_switch and default_driver_switch --- libs/libclkarchopenfpga/arch/example.xml | 2 +- .../src/base/clock_network.cpp | 30 ++++++++++++++----- .../src/base/clock_network.h | 13 +++++--- .../src/io/clock_network_xml_constants.h | 6 ++-- .../src/io/read_xml_clock_network.cpp | 12 ++++++-- .../src/io/write_xml_clock_network.cpp | 6 ++-- 6 files changed, 49 insertions(+), 20 deletions(-) diff --git a/libs/libclkarchopenfpga/arch/example.xml b/libs/libclkarchopenfpga/arch/example.xml index ac6e722dd..ac251bd3c 100644 --- a/libs/libclkarchopenfpga/arch/example.xml +++ b/libs/libclkarchopenfpga/arch/example.xml @@ -1,4 +1,4 @@ - + diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index ee562bfd5..7ae5b9a4f 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -18,7 +18,8 @@ namespace openfpga { // Begin namespace openfpga ***********************************************************************/ ClockNetwork::ClockNetwork() { default_segment_id_ = RRSegmentId::INVALID(); - default_switch_id_ = RRSwitchId::INVALID(); + default_tap_switch_id_ = RRSwitchId::INVALID(); + default_driver_switch_id_ = RRSwitchId::INVALID(); is_dirty_ = true; } @@ -172,11 +173,16 @@ RRSegmentId ClockNetwork::default_segment() const { return default_segment_id_; } -std::string ClockNetwork::default_switch_name() const { - return default_switch_name_; +std::string ClockNetwork::default_tap_switch_name() const { + return default_tap_switch_name_; } -RRSwitchId ClockNetwork::default_switch() const { return default_switch_id_; } +std::string ClockNetwork::default_driver_switch_name() const { + return default_driver_switch_name_; +} + +RRSwitchId ClockNetwork::default_tap_switch() const { return default_tap_switch_id_; } +RRSwitchId ClockNetwork::default_driver_switch() const { return default_driver_switch_id_; } std::string ClockNetwork::tree_name(const ClockTreeId& tree_id) const { VTR_ASSERT(valid_tree_id(tree_id)); @@ -417,16 +423,24 @@ void ClockNetwork::set_default_segment(const RRSegmentId& seg_id) { default_segment_id_ = seg_id; } -void ClockNetwork::set_default_switch(const RRSwitchId& switch_id) { - default_switch_id_ = switch_id; +void ClockNetwork::set_default_tap_switch(const RRSwitchId& switch_id) { + default_tap_switch_id_ = switch_id; +} + +void ClockNetwork::set_default_driver_switch(const RRSwitchId& switch_id) { + default_driver_switch_id_ = switch_id; } void ClockNetwork::set_default_segment_name(const std::string& name) { default_segment_name_ = name; } -void ClockNetwork::set_default_switch_name(const std::string& name) { - default_switch_name_ = name; +void ClockNetwork::set_default_tap_switch_name(const std::string& name) { + default_tap_switch_name_ = name; +} + +void ClockNetwork::set_default_driver_switch_name(const std::string& name) { + default_driver_switch_name_ = name; } ClockTreeId ClockNetwork::create_tree(const std::string& name, size_t width) { diff --git a/libs/libclkarchopenfpga/src/base/clock_network.h b/libs/libclkarchopenfpga/src/base/clock_network.h index 0b9b8a42b..ad8d5e61f 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.h +++ b/libs/libclkarchopenfpga/src/base/clock_network.h @@ -145,9 +145,11 @@ class ClockNetwork { /* Reserve a number of trees to be memory efficent */ void reserve_trees(const size_t& num_trees); void set_default_segment(const RRSegmentId& seg_id); - void set_default_switch(const RRSwitchId& switch_id); + void set_default_tap_switch(const RRSwitchId& switch_id); + void set_default_driver_switch(const RRSwitchId& switch_id); void set_default_segment_name(const std::string& name); - void set_default_switch_name(const std::string& name); + void set_default_tap_switch_name(const std::string& name); + void set_default_driver_switch_name(const std::string& name); /* 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, size_t width = 1); @@ -250,8 +252,11 @@ class ClockNetwork { clock wires */ RRSegmentId default_segment_id_; std::string - default_switch_name_; /* The routing switch interconnecting clock wire */ - RRSwitchId default_switch_id_; + default_tap_switch_name_; /* The routing switch interconnecting clock wire */ + RRSwitchId default_tap_switch_id_; + std::string + default_driver_switch_name_; /* The routing switch interconnecting clock wire */ + RRSwitchId default_driver_switch_id_; /* Fast lookup */ std::map tree_name2id_map_; diff --git a/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h b/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h index db7216f2d..a172b88ec 100644 --- a/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h +++ b/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h @@ -6,8 +6,10 @@ constexpr const char* XML_CLOCK_NETWORK_ROOT_NAME = "clock_networks"; constexpr const char* XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_SEGMENT = "default_segment"; -constexpr const char* XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_SWITCH = - "default_switch"; +constexpr const char* XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_TAP_SWITCH = + "default_tap_switch"; +constexpr const char* XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_DRIVER_SWITCH = + "default_driver_switch"; constexpr const char* XML_CLOCK_TREE_NODE_NAME = "clock_network"; constexpr const char* XML_CLOCK_TREE_ATTRIBUTE_NAME = "name"; constexpr const char* XML_CLOCK_TREE_ATTRIBUTE_WIDTH = "width"; diff --git a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp index ed083f483..372ec0c81 100644 --- a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp @@ -263,11 +263,17 @@ ClockNetwork read_xml_clock_network(const char* fname) { .as_string(); clk_ntwk.set_default_segment_name(default_segment_name); - std::string default_switch_name = - get_attribute(xml_root, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_SWITCH, + std::string default_tap_switch_name = + get_attribute(xml_root, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_TAP_SWITCH, loc_data) .as_string(); - clk_ntwk.set_default_switch_name(default_switch_name); + clk_ntwk.set_default_tap_switch_name(default_tap_switch_name); + + std::string default_driver_switch_name = + get_attribute(xml_root, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_DRIVER_SWITCH, + loc_data) + .as_string(); + clk_ntwk.set_default_driver_switch_name(default_driver_switch_name); size_t num_trees = std::distance(xml_root.children().begin(), xml_root.children().end()); diff --git a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp index 720335aa4..a71051fe1 100644 --- a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp @@ -168,8 +168,10 @@ int write_xml_clock_network(const char* fname, const ClockNetwork& clk_ntwk) { fp << "<" << XML_CLOCK_NETWORK_ROOT_NAME; write_xml_attribute(fp, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_SEGMENT, clk_ntwk.default_segment_name().c_str()); - write_xml_attribute(fp, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_SWITCH, - clk_ntwk.default_switch_name().c_str()); + write_xml_attribute(fp, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_TAP_SWITCH, + clk_ntwk.default_tap_switch_name().c_str()); + write_xml_attribute(fp, XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_DRIVER_SWITCH, + clk_ntwk.default_driver_switch_name().c_str()); fp << ">" << "\n"; From 1ab75cf76c4920eab9e1b7cfb61a1683cf2a7d8a Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 21 Jun 2024 16:52:22 -0700 Subject: [PATCH 02/86] [lib] now link clock arch supports tap and driver default switches --- .../src/utils/clock_network_utils.cpp | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp b/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp index 79737b46c..45b367809 100644 --- a/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp +++ b/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp @@ -32,18 +32,40 @@ static int link_clock_network_rr_segments(ClockNetwork& clk_ntwk, *******************************************************************/ static int link_clock_network_rr_switches(ClockNetwork& clk_ntwk, const RRGraphView& rr_graph) { - /* default switch id */ - std::string default_switch_name = clk_ntwk.default_switch_name(); + /* default tap switch id */ + int status = CMD_EXEC_FATAL_ERROR; + std::string default_tap_switch_name = clk_ntwk.default_tap_switch_name(); for (size_t rr_switch_id = 0; rr_switch_id < rr_graph.num_rr_switches(); ++rr_switch_id) { if (std::string(rr_graph.rr_switch_inf(RRSwitchId(rr_switch_id)).name) == - default_switch_name) { - clk_ntwk.set_default_switch(RRSwitchId(rr_switch_id)); - return CMD_EXEC_SUCCESS; + default_tap_switch_name) { + clk_ntwk.set_default_tap_switch(RRSwitchId(rr_switch_id)); + status = CMD_EXEC_SUCCESS; + break; } } + if (status != CMD_EXEC_SUCCESS) { + VTR_LOG("Unable to find the default tap switch '%s' in VPR architecture description!\n", default_tap_switch_name.c_str()); + return CMD_EXEC_FATAL_ERROR; + } + /* default driver switch id */ + status = CMD_EXEC_FATAL_ERROR; + std::string default_driver_switch_name = clk_ntwk.default_driver_switch_name(); + for (size_t rr_switch_id = 0; rr_switch_id < rr_graph.num_rr_switches(); + ++rr_switch_id) { + if (std::string(rr_graph.rr_switch_inf(RRSwitchId(rr_switch_id)).name) == + default_driver_switch_name) { + clk_ntwk.set_default_driver_switch(RRSwitchId(rr_switch_id)); + status = CMD_EXEC_SUCCESS; + break; + } + } + if (status != CMD_EXEC_SUCCESS) { + VTR_LOG("Unable to find the default driver switch '%s' in VPR architecture description!\n", default_driver_switch_name.c_str()); + return CMD_EXEC_FATAL_ERROR; + } - return CMD_EXEC_FATAL_ERROR; + return status; } int link_clock_network_rr_graph(ClockNetwork& clk_ntwk, From 486cd01c1505823c5696e9dd4078ba9503de54a8 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 21 Jun 2024 16:54:22 -0700 Subject: [PATCH 03/86] [core] now clock graph builder supports two types of switches --- openfpga/src/annotation/append_clock_rr_graph.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfpga/src/annotation/append_clock_rr_graph.cpp b/openfpga/src/annotation/append_clock_rr_graph.cpp index a52a86ed2..d6d6fe1b7 100644 --- a/openfpga/src/annotation/append_clock_rr_graph.cpp +++ b/openfpga/src/annotation/append_clock_rr_graph.cpp @@ -526,7 +526,7 @@ static void add_rr_graph_block_clock_edges( /* Create edges */ VTR_ASSERT(rr_graph_view.valid_node(des_node)); rr_graph_builder.create_edge(src_node, des_node, - clk_ntwk.default_switch(), false); + clk_ntwk.default_driver_switch(), false); edge_count++; } VTR_LOGV(verbose, "\tWill add %lu edges to other clock nodes\n", @@ -542,7 +542,7 @@ static void add_rr_graph_block_clock_edges( /* Create edges */ VTR_ASSERT(rr_graph_view.valid_node(des_node)); rr_graph_builder.create_edge(src_node, des_node, - clk_ntwk.default_switch(), false); + clk_ntwk.default_tap_switch(), false); edge_count++; } VTR_LOGV(verbose, "\tWill add %lu edges to other IPIN\n", From 6c5988575cae36962e0ca976ca66fff6947de26b Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 21 Jun 2024 16:59:21 -0700 Subject: [PATCH 04/86] [test] update clock network testcase --- .../homo_1clock_2layer/config/clk_arch_1clk_2layer.xml | 2 +- .../homo_1clock_2layer_full_tb/config/clk_arch_1clk_2layer.xml | 2 +- .../homo_2clock_2layer/config/clk_arch_2clk_2layer.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer/config/clk_arch_1clk_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer/config/clk_arch_1clk_2layer.xml index 0570406fd..6aaf1b9b4 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer/config/clk_arch_1clk_2layer.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer/config/clk_arch_1clk_2layer.xml @@ -1,4 +1,4 @@ - + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer_full_tb/config/clk_arch_1clk_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer_full_tb/config/clk_arch_1clk_2layer.xml index 0570406fd..6aaf1b9b4 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer_full_tb/config/clk_arch_1clk_2layer.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer_full_tb/config/clk_arch_1clk_2layer.xml @@ -1,4 +1,4 @@ - + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/clk_arch_2clk_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/clk_arch_2clk_2layer.xml index 46fec8fd5..fdf1dc149 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/clk_arch_2clk_2layer.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/clk_arch_2clk_2layer.xml @@ -1,4 +1,4 @@ - + From 3ddaefc2a2af2f5460b65df3ae592d3b7e9d27e0 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 21 Jun 2024 17:02:37 -0700 Subject: [PATCH 05/86] [lib] syntax --- libs/libclkarchopenfpga/src/base/clock_network.cpp | 2 +- libs/libclkarchopenfpga/src/base/clock_network.h | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index 7ae5b9a4f..eea5c8dbf 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -636,7 +636,7 @@ bool ClockNetwork::validate_tree() const { bool ClockNetwork::validate() const { is_dirty_ = true; - if (default_segment_id_ && default_switch_id_ && validate_tree()) { + if (default_segment_id_ && default_tap_switch_id_ && default_driver_switch_id_ && validate_tree()) { is_dirty_ = false; } return true; diff --git a/libs/libclkarchopenfpga/src/base/clock_network.h b/libs/libclkarchopenfpga/src/base/clock_network.h index ad8d5e61f..3873eae50 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.h +++ b/libs/libclkarchopenfpga/src/base/clock_network.h @@ -73,8 +73,10 @@ class ClockNetwork { * information from RRGraph */ RRSegmentId default_segment() const; std::string default_segment_name() const; - RRSwitchId default_switch() const; - std::string default_switch_name() const; + RRSwitchId default_tap_switch() const; + std::string default_tap_switch_name() const; + RRSwitchId default_driver_switch() const; + std::string default_driver_switch_name() const; std::string tree_name(const ClockTreeId& tree_id) const; size_t tree_width(const ClockTreeId& tree_id) const; size_t tree_depth(const ClockTreeId& tree_id) const; From ecd31955b1e7d9e11fbffa4807403a8bd9c6af4b Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 21 Jun 2024 17:11:32 -0700 Subject: [PATCH 06/86] [core] code format --- libs/libclkarchopenfpga/src/base/clock_network.cpp | 11 ++++++++--- libs/libclkarchopenfpga/src/base/clock_network.h | 8 ++++---- .../src/utils/clock_network_utils.cpp | 13 ++++++++++--- openfpga/src/annotation/append_clock_rr_graph.cpp | 8 ++++---- 4 files changed, 26 insertions(+), 14 deletions(-) diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index eea5c8dbf..c235bab7a 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -181,8 +181,12 @@ std::string ClockNetwork::default_driver_switch_name() const { return default_driver_switch_name_; } -RRSwitchId ClockNetwork::default_tap_switch() const { return default_tap_switch_id_; } -RRSwitchId ClockNetwork::default_driver_switch() const { return default_driver_switch_id_; } +RRSwitchId ClockNetwork::default_tap_switch() const { + return default_tap_switch_id_; +} +RRSwitchId ClockNetwork::default_driver_switch() const { + return default_driver_switch_id_; +} std::string ClockNetwork::tree_name(const ClockTreeId& tree_id) const { VTR_ASSERT(valid_tree_id(tree_id)); @@ -636,7 +640,8 @@ bool ClockNetwork::validate_tree() const { bool ClockNetwork::validate() const { is_dirty_ = true; - if (default_segment_id_ && default_tap_switch_id_ && default_driver_switch_id_ && validate_tree()) { + if (default_segment_id_ && default_tap_switch_id_ && + default_driver_switch_id_ && validate_tree()) { is_dirty_ = false; } return true; diff --git a/libs/libclkarchopenfpga/src/base/clock_network.h b/libs/libclkarchopenfpga/src/base/clock_network.h index 3873eae50..3cf37a79a 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.h +++ b/libs/libclkarchopenfpga/src/base/clock_network.h @@ -253,11 +253,11 @@ class ClockNetwork { std::string default_segment_name_; /* The routing segment representing the clock wires */ RRSegmentId default_segment_id_; - std::string - default_tap_switch_name_; /* The routing switch interconnecting clock wire */ + std::string default_tap_switch_name_; /* The routing switch interconnecting + clock wire */ RRSwitchId default_tap_switch_id_; - std::string - default_driver_switch_name_; /* The routing switch interconnecting clock wire */ + std::string default_driver_switch_name_; /* The routing switch interconnecting + clock wire */ RRSwitchId default_driver_switch_id_; /* Fast lookup */ diff --git a/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp b/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp index 45b367809..723fc51ea 100644 --- a/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp +++ b/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp @@ -45,12 +45,16 @@ static int link_clock_network_rr_switches(ClockNetwork& clk_ntwk, } } if (status != CMD_EXEC_SUCCESS) { - VTR_LOG("Unable to find the default tap switch '%s' in VPR architecture description!\n", default_tap_switch_name.c_str()); + VTR_LOG( + "Unable to find the default tap switch '%s' in VPR architecture " + "description!\n", + default_tap_switch_name.c_str()); return CMD_EXEC_FATAL_ERROR; } /* default driver switch id */ status = CMD_EXEC_FATAL_ERROR; - std::string default_driver_switch_name = clk_ntwk.default_driver_switch_name(); + std::string default_driver_switch_name = + clk_ntwk.default_driver_switch_name(); for (size_t rr_switch_id = 0; rr_switch_id < rr_graph.num_rr_switches(); ++rr_switch_id) { if (std::string(rr_graph.rr_switch_inf(RRSwitchId(rr_switch_id)).name) == @@ -61,7 +65,10 @@ static int link_clock_network_rr_switches(ClockNetwork& clk_ntwk, } } if (status != CMD_EXEC_SUCCESS) { - VTR_LOG("Unable to find the default driver switch '%s' in VPR architecture description!\n", default_driver_switch_name.c_str()); + VTR_LOG( + "Unable to find the default driver switch '%s' in VPR architecture " + "description!\n", + default_driver_switch_name.c_str()); return CMD_EXEC_FATAL_ERROR; } diff --git a/openfpga/src/annotation/append_clock_rr_graph.cpp b/openfpga/src/annotation/append_clock_rr_graph.cpp index d6d6fe1b7..dee65e605 100644 --- a/openfpga/src/annotation/append_clock_rr_graph.cpp +++ b/openfpga/src/annotation/append_clock_rr_graph.cpp @@ -525,8 +525,8 @@ static void add_rr_graph_block_clock_edges( chan_coord, itree, ilvl, ClockTreePinId(ipin), node_dir)) { /* Create edges */ VTR_ASSERT(rr_graph_view.valid_node(des_node)); - rr_graph_builder.create_edge(src_node, des_node, - clk_ntwk.default_driver_switch(), false); + rr_graph_builder.create_edge( + src_node, des_node, clk_ntwk.default_driver_switch(), false); edge_count++; } VTR_LOGV(verbose, "\tWill add %lu edges to other clock nodes\n", @@ -541,8 +541,8 @@ static void add_rr_graph_block_clock_edges( itree, ClockTreePinId(ipin))) { /* Create edges */ VTR_ASSERT(rr_graph_view.valid_node(des_node)); - rr_graph_builder.create_edge(src_node, des_node, - clk_ntwk.default_tap_switch(), false); + rr_graph_builder.create_edge( + src_node, des_node, clk_ntwk.default_tap_switch(), false); edge_count++; } VTR_LOGV(verbose, "\tWill add %lu edges to other IPIN\n", From 3f08b83b3a9b1fd692b08c6a1986f76b1ec7d0e0 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 21 Jun 2024 17:12:10 -0700 Subject: [PATCH 07/86] [core] remove restrictions on 1 clock tree definition --- .../src/annotation/append_clock_rr_graph.cpp | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/openfpga/src/annotation/append_clock_rr_graph.cpp b/openfpga/src/annotation/append_clock_rr_graph.cpp index dee65e605..ac48b5cef 100644 --- a/openfpga/src/annotation/append_clock_rr_graph.cpp +++ b/openfpga/src/annotation/append_clock_rr_graph.cpp @@ -525,8 +525,8 @@ static void add_rr_graph_block_clock_edges( chan_coord, itree, ilvl, ClockTreePinId(ipin), node_dir)) { /* Create edges */ VTR_ASSERT(rr_graph_view.valid_node(des_node)); - rr_graph_builder.create_edge( - src_node, des_node, clk_ntwk.default_driver_switch(), false); + rr_graph_builder.create_edge(src_node, des_node, + clk_ntwk.default_driver_switch(), false); edge_count++; } VTR_LOGV(verbose, "\tWill add %lu edges to other clock nodes\n", @@ -541,8 +541,8 @@ static void add_rr_graph_block_clock_edges( itree, ClockTreePinId(ipin))) { /* Create edges */ VTR_ASSERT(rr_graph_view.valid_node(des_node)); - rr_graph_builder.create_edge( - src_node, des_node, clk_ntwk.default_tap_switch(), false); + rr_graph_builder.create_edge(src_node, des_node, + clk_ntwk.default_tap_switch(), false); edge_count++; } VTR_LOGV(verbose, "\tWill add %lu edges to other IPIN\n", @@ -638,14 +638,6 @@ int append_clock_rr_graph(DeviceContext& vpr_device_ctx, return CMD_EXEC_SUCCESS; } - /* Report any clock structure we do not support yet! */ - if (clk_ntwk.num_trees() > 1) { - VTR_LOG( - "Currently only support 1 clock tree in programmable clock " - "architecture\nPlease update your clock architecture definition\n"); - return CMD_EXEC_FATAL_ERROR; - } - /* Estimate the number of nodes and pre-allocate */ size_t orig_num_nodes = vpr_device_ctx.rr_graph.num_nodes(); size_t num_clock_nodes = estimate_clock_rr_graph_num_nodes( From 8d7dba2d57ab136c95b45d0e781efe270de7264c Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 21 Jun 2024 18:13:37 -0700 Subject: [PATCH 08/86] [test] add a new testcase to programmable clock network on supporting reset signals --- ...acff_40nm_Ntwk1clk1rst2lvl_cc_openfpga.xml | 255 ++++++++++++++++++ .../example_clkntwk_no_ace_script.openfpga | 75 ++++++ .../config/clk_arch_1clk_1rst_2layer.xml | 32 +++ .../config/pin_constraints_reset.xml | 7 + .../config/pin_constraints_resetb.xml | 7 + .../config/task.conf | 49 ++++ 6 files changed, 425 insertions(+) create mode 100644 openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_Ntwk1clk1rst2lvl_cc_openfpga.xml create mode 100644 openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/clk_arch_1clk_1rst_2layer.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/pin_constraints_reset.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/pin_constraints_resetb.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/task.conf diff --git a/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_Ntwk1clk1rst2lvl_cc_openfpga.xml b/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_Ntwk1clk1rst2lvl_cc_openfpga.xml new file mode 100644 index 000000000..e8b0e755f --- /dev/null +++ b/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_Ntwk1clk1rst2lvl_cc_openfpga.xml @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + + + + + 10e-12 5e-12 + + + 10e-12 5e-12 + + + + + + + + + + + + + 10e-12 5e-12 5e-12 + + + 10e-12 5e-12 5e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga b/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga new file mode 100644 index 000000000..83cc44860 --- /dev/null +++ b/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga @@ -0,0 +1,75 @@ +# Run VPR for the 'and' design +#--write_rr_graph example_rr_graph.xml +vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} \ + --clock_modeling ideal \ + --device ${OPENFPGA_VPR_DEVICE_LAYOUT} \ + --route_chan_width ${OPENFPGA_VPR_ROUTE_CHAN_WIDTH} + +# Read OpenFPGA architecture definition +read_openfpga_arch -f ${OPENFPGA_ARCH_FILE} + +# Read OpenFPGA simulation settings +read_openfpga_simulation_setting -f ${OPENFPGA_SIM_SETTING_FILE} + +# Read OpenFPGA clock architecture +read_openfpga_clock_arch -f ${OPENFPGA_CLOCK_ARCH_FILE} + +# Append clock network to vpr's routing resource graph +append_clock_rr_graph + +# Annotate the OpenFPGA architecture to VPR data base +# to debug use --verbose options +link_openfpga_arch --activity_file ${ACTIVITY_FILE} --sort_gsb_chan_node_in_edges + +# Route clock based on clock network definition +route_clock_rr_graph --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} + +# Check and correct any naming conflicts in the BLIF netlist +check_netlist_naming_conflict --fix --report ./netlist_renaming.xml + +# Apply fix-up to Look-Up Table truth tables based on packing results +lut_truth_table_fixup + +# Build the module graph +# - Enabled compression on routing architecture modules +# - Enable pin duplication on grid modules +build_fabric --compress_routing #--verbose + +# Write the fabric hierarchy of module graph to a file +# This is used by hierarchical PnR flows +write_fabric_hierarchy --file ./fabric_hierarchy.txt + +# Repack the netlist to physical pbs +# This must be done before bitstream generator and testbench generation +# Strongly recommend it is done after all the fix-up have been applied +repack --design_constraints ${OPENFPGA_REPACK_CONSTRAINTS_FILE} #--verbose + +# Build the bitstream +# - Output the fabric-independent bitstream to a file +build_architecture_bitstream --verbose --write_file fabric_independent_bitstream.xml + +# Build fabric-dependent bitstream +build_fabric_bitstream --verbose + +# Write fabric-dependent bitstream +write_fabric_bitstream --file fabric_bitstream.bit --format plain_text + +# Write the Verilog netlist for FPGA fabric +# - Enable the use of explicit port mapping in Verilog netlist +write_fabric_verilog --file ./SRC --explicit_port_mapping --include_timing --print_user_defined_template --verbose + +# Write the Verilog testbench for FPGA fabric +# - We suggest the use of same output directory as fabric Verilog netlists +# - Must specify the reference benchmark file if you want to output any testbenches +# - Enable top-level testbench which is a full verification including programming circuit and core logic of FPGA +# - Enable pre-configured top-level testbench which is a fast verification skipping programming phase +# - Simulation ini file is optional and is needed only when you need to interface different HDL simulators using openfpga flow-run scripts +write_full_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} --explicit_port_mapping --include_signal_init --bitstream fabric_bitstream.bit --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} +write_preconfigured_fabric_wrapper --embed_bitstream iverilog --file ./SRC --explicit_port_mapping --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} +write_preconfigured_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} --explicit_port_mapping --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} + +# Finish and exit OpenFPGA +exit + +# Note : +# To run verification at the end of the flow maintain source in ./SRC directory diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/clk_arch_1clk_1rst_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/clk_arch_1clk_1rst_2layer.xml new file mode 100644 index 000000000..fde2c515a --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/clk_arch_1clk_1rst_2layer.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/pin_constraints_reset.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/pin_constraints_reset.xml new file mode 100644 index 000000000..abcf209f6 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/pin_constraints_reset.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/pin_constraints_resetb.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/pin_constraints_resetb.xml new file mode 100644 index 000000000..cdef2ad86 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/pin_constraints_resetb.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/task.conf b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/task.conf new file mode 100644 index 000000000..9b038d744 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/task.conf @@ -0,0 +1,49 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# Configuration file for running experiments +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs +# Each job execute fpga_flow script on combination of architecture & benchmark +# timeout_each_job is timeout for each job +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + +[GENERAL] +run_engine=openfpga_shell +power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml +power_analysis = false +spice_output=false +verilog_output=true +timeout_each_job = 3*60 +fpga_flow=yosys_vpr + +[OpenFPGA_SHELL] +openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_Ntwk1clk1rst2lvl_cc_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml +openfpga_vpr_device_layout=2x2 +openfpga_vpr_route_chan_width=40 +openfpga_clock_arch_file=${PATH:TASK_DIR}/config/clk_arch_1clk_1rst_2layer.xml + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_reset/counter.v +bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_resetb/counter.v + +[SYNTHESIS_PARAM] +# Yosys script parameters +bench_yosys_cell_sim_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/openfpga_dff_sim.v +bench_yosys_dff_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/openfpga_dff_map.v +bench_read_verilog_options_common = -nolatches +bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dff_flow.ys +bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys;${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_rewrite_flow.ys + +bench0_top = counter +bench0_openfpga_pin_constraints_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/pin_constraints_reset.xml + +bench1_top = counter +bench1_openfpga_pin_constraints_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/pin_constraints_resetb.xml + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= +vpr_fpga_verilog_formal_verification_top_netlist= From 7d67b9d5b92d4c39143e71cd715b2ebdd00fe3af Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 21 Jun 2024 18:14:54 -0700 Subject: [PATCH 09/86] [test] deploy new tests to basic reg tests --- openfpga_flow/regression_test_scripts/basic_reg_test.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/openfpga_flow/regression_test_scripts/basic_reg_test.sh b/openfpga_flow/regression_test_scripts/basic_reg_test.sh index c4b3ebcb8..0f2e1514e 100755 --- a/openfpga_flow/regression_test_scripts/basic_reg_test.sh +++ b/openfpga_flow/regression_test_scripts/basic_reg_test.sh @@ -232,6 +232,7 @@ echo -e "Testing programmable clock architecture"; run-task basic_tests/clock_network/homo_1clock_2layer $@ run-task basic_tests/clock_network/homo_1clock_2layer_full_tb $@ run-task basic_tests/clock_network/homo_2clock_2layer $@ +run-task basic_tests/clock_network/homo_1clock_1_reset_2layer $@ echo -e "Testing configuration chain of a K4N4 FPGA using .blif generated by yosys+verific"; run-task basic_tests/verific_test $@ From c2e759fa70418c408b08cb8bc49fdcf84c452c90 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 21 Jun 2024 18:42:29 -0700 Subject: [PATCH 10/86] [arch] fixed some bugs --- .../k4_frac_N4_fracff_40nm_Ntwk1clk1rst2lvl_cc_openfpga.xml | 1 + openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_Ntwk1clk1rst2lvl_cc_openfpga.xml b/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_Ntwk1clk1rst2lvl_cc_openfpga.xml index e8b0e755f..36d5dce05 100644 --- a/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_Ntwk1clk1rst2lvl_cc_openfpga.xml +++ b/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_Ntwk1clk1rst2lvl_cc_openfpga.xml @@ -197,6 +197,7 @@ + diff --git a/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml b/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml index cc4d5de0e..19447dd7e 100644 --- a/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml +++ b/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml @@ -194,6 +194,11 @@ With the 96 nm half pitch, such wires would take 60 um of height, vs. a 90 nm high (approximated as square) Stratix IV tile so this seems reasonable. Using a tile length of 90 nm, corresponding to the length of a Stratix IV tile if it were square. --> + + + 1 1 + 1 + 1 1 1 1 1 From 2193f108ee77fa88d95f125b14711d859f05e3d9 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 21 Jun 2024 18:42:35 -0700 Subject: [PATCH 11/86] [core] add debugging messages --- .../src/utils/clock_network_utils.cpp | 55 ++++++++++--------- .../src/base/openfpga_read_arch_template.h | 12 +++- 2 files changed, 39 insertions(+), 28 deletions(-) diff --git a/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp b/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp index 723fc51ea..138ac4087 100644 --- a/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp +++ b/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp @@ -22,7 +22,10 @@ static int link_clock_network_rr_segments(ClockNetwork& clk_ntwk, return CMD_EXEC_SUCCESS; } } - + VTR_LOG_ERROR( + "Unable to find the default segement '%s' in VPR architecture " + "description!\n", + default_segment_name.c_str()); return CMD_EXEC_FATAL_ERROR; } @@ -30,29 +33,32 @@ static int link_clock_network_rr_segments(ClockNetwork& clk_ntwk, * Link all the switches that are defined in a routing resource graph to a given *clock network *******************************************************************/ -static int link_clock_network_rr_switches(ClockNetwork& clk_ntwk, +static int link_clock_network_tap_rr_switches(ClockNetwork& clk_ntwk, const RRGraphView& rr_graph) { /* default tap switch id */ - int status = CMD_EXEC_FATAL_ERROR; std::string default_tap_switch_name = clk_ntwk.default_tap_switch_name(); for (size_t rr_switch_id = 0; rr_switch_id < rr_graph.num_rr_switches(); ++rr_switch_id) { if (std::string(rr_graph.rr_switch_inf(RRSwitchId(rr_switch_id)).name) == default_tap_switch_name) { clk_ntwk.set_default_tap_switch(RRSwitchId(rr_switch_id)); - status = CMD_EXEC_SUCCESS; - break; + return CMD_EXEC_SUCCESS; } } - if (status != CMD_EXEC_SUCCESS) { - VTR_LOG( - "Unable to find the default tap switch '%s' in VPR architecture " - "description!\n", - default_tap_switch_name.c_str()); - return CMD_EXEC_FATAL_ERROR; - } + VTR_LOG_ERROR( + "Unable to find the default tap switch '%s' in VPR architecture " + "description!\n", + default_tap_switch_name.c_str()); + return CMD_EXEC_FATAL_ERROR; +} + +/******************************************************************** + * Link all the switches that are defined in a routing resource graph to a given + *clock network + *******************************************************************/ +static int link_clock_network_driver_rr_switches(ClockNetwork& clk_ntwk, + const RRGraphView& rr_graph) { /* default driver switch id */ - status = CMD_EXEC_FATAL_ERROR; std::string default_driver_switch_name = clk_ntwk.default_driver_switch_name(); for (size_t rr_switch_id = 0; rr_switch_id < rr_graph.num_rr_switches(); @@ -60,19 +66,14 @@ static int link_clock_network_rr_switches(ClockNetwork& clk_ntwk, if (std::string(rr_graph.rr_switch_inf(RRSwitchId(rr_switch_id)).name) == default_driver_switch_name) { clk_ntwk.set_default_driver_switch(RRSwitchId(rr_switch_id)); - status = CMD_EXEC_SUCCESS; - break; + return CMD_EXEC_SUCCESS; } } - if (status != CMD_EXEC_SUCCESS) { - VTR_LOG( - "Unable to find the default driver switch '%s' in VPR architecture " - "description!\n", - default_driver_switch_name.c_str()); - return CMD_EXEC_FATAL_ERROR; - } - - return status; + VTR_LOG_ERROR( + "Unable to find the default driver switch '%s' in VPR architecture " + "description!\n", + default_driver_switch_name.c_str()); + return CMD_EXEC_FATAL_ERROR; } int link_clock_network_rr_graph(ClockNetwork& clk_ntwk, @@ -83,7 +84,11 @@ int link_clock_network_rr_graph(ClockNetwork& clk_ntwk, if (CMD_EXEC_FATAL_ERROR == status) { return status; } - status = link_clock_network_rr_switches(clk_ntwk, rr_graph); + status = link_clock_network_tap_rr_switches(clk_ntwk, rr_graph); + if (CMD_EXEC_FATAL_ERROR == status) { + return status; + } + status = link_clock_network_driver_rr_switches(clk_ntwk, rr_graph); if (CMD_EXEC_FATAL_ERROR == status) { return status; } diff --git a/openfpga/src/base/openfpga_read_arch_template.h b/openfpga/src/base/openfpga_read_arch_template.h index 829499c45..91e25a607 100644 --- a/openfpga/src/base/openfpga_read_arch_template.h +++ b/openfpga/src/base/openfpga_read_arch_template.h @@ -236,9 +236,15 @@ int read_openfpga_clock_arch_template(T& openfpga_context, const Command& cmd, openfpga_context.mutable_clock_arch() = read_xml_clock_network(arch_file_name.c_str()); /* Build internal links */ - openfpga_context.mutable_clock_arch().link(); - link_clock_network_rr_graph(openfpga_context.mutable_clock_arch(), - g_vpr_ctx.device().rr_graph); + if (!openfpga_context.mutable_clock_arch().link()) { + VTR_LOG_ERROR("Link clock network failed!"); + return CMD_EXEC_FATAL_ERROR; + } + if (CMD_EXEC_SUCCESS != link_clock_network_rr_graph(openfpga_context.mutable_clock_arch(), + g_vpr_ctx.device().rr_graph)) { + VTR_LOG_ERROR("Link clock network to routing architecture failed!"); + return CMD_EXEC_FATAL_ERROR; + } /* Ensure clean data */ openfpga_context.clock_arch().validate(); if (!openfpga_context.clock_arch().is_valid()) { From 292f4a9273b83c7f87b58cfb1514e61a4ef2f298 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 21 Jun 2024 18:43:25 -0700 Subject: [PATCH 12/86] [test] fixed a bug where ace is no required --- .../example_clkntwk_no_ace_script.openfpga | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga b/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga index 83cc44860..1cdaa1932 100644 --- a/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga +++ b/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga @@ -19,7 +19,7 @@ append_clock_rr_graph # Annotate the OpenFPGA architecture to VPR data base # to debug use --verbose options -link_openfpga_arch --activity_file ${ACTIVITY_FILE} --sort_gsb_chan_node_in_edges +link_openfpga_arch --sort_gsb_chan_node_in_edges # Route clock based on clock network definition route_clock_rr_graph --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} From d2053db21c434c83e9606e0f76a8ba68acd014a1 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 21 Jun 2024 19:00:01 -0700 Subject: [PATCH 13/86] [core] removing the restrictions on only 1 clock tree is supported in programmable clock network --- openfpga/src/annotation/route_clock_rr_graph.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index bafc8215f..d669304c0 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -210,14 +210,6 @@ int route_clock_rr_graph(VprRoutingAnnotation& vpr_routing_annotation, return CMD_EXEC_SUCCESS; } - /* Report any clock structure we do not support yet! */ - if (clk_ntwk.num_trees() > 1) { - VTR_LOG( - "Currently only support 1 clock tree in programmable clock " - "architecture\nPlease update your clock architecture definition\n"); - return CMD_EXEC_FATAL_ERROR; - } - /* If there are multiple clock signals from the netlist, require pin * constraints */ std::vector clock_net_names = From 9bb076d89296508c5795b6647897b4973cd71192 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 21 Jun 2024 20:29:21 -0700 Subject: [PATCH 14/86] [test] fixed a bug on pin mapping of tetbenche --- .../example_clkntwk_no_ace_script.openfpga | 6 +++--- .../homo_1clock_1reset_2layer/config/task.conf | 4 ++++ 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga b/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga index 1cdaa1932..f62d62ecc 100644 --- a/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga +++ b/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga @@ -64,9 +64,9 @@ write_fabric_verilog --file ./SRC --explicit_port_mapping --include_timing --pri # - Enable top-level testbench which is a full verification including programming circuit and core logic of FPGA # - Enable pre-configured top-level testbench which is a fast verification skipping programming phase # - Simulation ini file is optional and is needed only when you need to interface different HDL simulators using openfpga flow-run scripts -write_full_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} --explicit_port_mapping --include_signal_init --bitstream fabric_bitstream.bit --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} -write_preconfigured_fabric_wrapper --embed_bitstream iverilog --file ./SRC --explicit_port_mapping --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} -write_preconfigured_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} --explicit_port_mapping --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} +write_full_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} ${OPENFPGA_VERILOG_TESTBENCH_PORT_MAPPING} --include_signal_init --bitstream fabric_bitstream.bit --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} +write_preconfigured_fabric_wrapper --embed_bitstream iverilog --file ./SRC ${OPENFPGA_VERILOG_TESTBENCH_PORT_MAPPING} --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} +write_preconfigured_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} ${OPENFPGA_VERILOG_TESTBENCH_PORT_MAPPING} --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} # Finish and exit OpenFPGA exit diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/task.conf b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/task.conf index 9b038d744..d47ef31c7 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/task.conf +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/task.conf @@ -19,9 +19,11 @@ fpga_flow=yosys_vpr openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_Ntwk1clk1rst2lvl_cc_openfpga.xml openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml +openfpga_repack_constraints_file=${PATH:TASK_DIR}/config/repack_pin_constraints.xml openfpga_vpr_device_layout=2x2 openfpga_vpr_route_chan_width=40 openfpga_clock_arch_file=${PATH:TASK_DIR}/config/clk_arch_1clk_1rst_2layer.xml +openfpga_verilog_testbench_port_mapping=--explicit_port_mapping [ARCHITECTURES] arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml @@ -40,9 +42,11 @@ bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosy bench0_top = counter bench0_openfpga_pin_constraints_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/pin_constraints_reset.xml +bench0_openfpga_verilog_testbench_port_mapping= bench1_top = counter bench1_openfpga_pin_constraints_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/pin_constraints_resetb.xml +bench1_openfpga_verilog_testbench_port_mapping= [SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] end_flow_with_test= From 253e3e0cbac13a06f0483670d8bc19343808c21f Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 23 Jun 2024 17:43:38 -0700 Subject: [PATCH 15/86] [doc] add new syntax for clock network --- .../manual/file_formats/clock_network.rst | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/docs/source/manual/file_formats/clock_network.rst b/docs/source/manual/file_formats/clock_network.rst index 9d6baad98..fe6d89b79 100644 --- a/docs/source/manual/file_formats/clock_network.rst +++ b/docs/source/manual/file_formats/clock_network.rst @@ -22,7 +22,7 @@ Using the clock network description language, users can define multiple clock ne .. code-block:: xml - + @@ -56,23 +56,28 @@ where the segment is defined in the VPR architecture file: .. note:: Currently, clock network requires only length-1 wire segment to be used! -.. option:: default_switch="" +.. option:: default_tap_switch="" + + Define the default routing switch to be used when interconnects the routing tracks to the input pins of programmable blocks in the clock network. Must be a valid routing switch defined in the VPR architecture file. See the example in the ``default_driver_switch``. + +.. option:: default_driver_switch="" Define the default routing switch to be used when interconnects the routing tracks in the clock network. Must be a valid routing switch defined in the VPR architecture file. For example, .. code-block:: xml - default_switch="clk_mux" + default_tap_switch="cb_mux" default_driver_switch="sb_clk_mux" where the switch is defined in the VPR architecture file: .. code-block:: xml - + + -.. note:: Currently, clock network only supports one type of routing switch, which means all the programmable routing switch in the clock network will be in the same type and circuit design topology. +.. note:: Currently, clock network only supports the default types of routing switch, which means all the programmable routing switch in the clock network will be in the same type and circuit design topology. Clock Network Settings ^^^^^^^^^^^^^^^^^^^^^^ @@ -94,7 +99,7 @@ where the clock network is used to drive the global clock pin ``clk0`` in OpenFP - From 0c442f6238abf3e5df96693ac3ffd4ed4e0f04bf Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 24 Jun 2024 17:54:58 -0700 Subject: [PATCH 16/86] [lib] add syntax to support internal drivers in clock network parsers --- .../src/base/clock_network.cpp | 46 ++++++++++++++++++- .../src/base/clock_network.h | 21 ++++++++- .../src/base/clock_network_fwd.h | 2 + .../src/io/clock_network_xml_constants.h | 2 + .../src/io/read_xml_clock_network.cpp | 35 +++++++++++++- .../src/io/write_xml_clock_network.cpp | 20 ++++++-- 6 files changed, 119 insertions(+), 7 deletions(-) diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index c235bab7a..4972e303b 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -32,6 +32,10 @@ ClockNetwork::clock_tree_range ClockNetwork::trees() const { return vtr::make_range(tree_ids_.begin(), tree_ids_.end()); } +ClockNetwork::clock_internal_driver_range ClockNetwork::internal_drivers() const { + return vtr::make_range(internal_driver_ids_.begin(), internal_driver_ids_.end()); +} + std::vector ClockNetwork::levels( const ClockTreeId& tree_id) const { std::vector ret; @@ -325,6 +329,18 @@ vtr::Point ClockNetwork::spine_switch_point( return spine_switch_coords_[spine_id][size_t(switch_point_id)]; } +std::vector ClockNetwork::spine_switch_point_internal_drivers( + 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_internal_drivers_[spine_id][size_t(switch_point_id)]; +} + +std::string ClockNetwork::internal_driver_port(const ClockInternalDriverId& int_driver_id) const { + VTR_ASSERT(valid_internal_driver_id(int_driver_id)); + return internal_driver_ports_[int_driver_id]; +} + std::vector ClockNetwork::tree_taps( const ClockTreeId& tree_id) const { VTR_ASSERT(valid_tree_id(tree_id)); @@ -410,6 +426,7 @@ void ClockNetwork::reserve_spines(const size_t& num_spines) { spine_track_types_.reserve(num_spines); spine_switch_points_.reserve(num_spines); spine_switch_coords_.reserve(num_spines); + spine_switch_internal_drivers_.reserve(num_spines); spine_parents_.reserve(num_spines); spine_children_.reserve(num_spines); spine_parent_trees_.reserve(num_spines); @@ -494,6 +511,7 @@ ClockSpineId ClockNetwork::create_spine(const std::string& name) { spine_track_types_.emplace_back(NUM_RR_TYPES); spine_switch_points_.emplace_back(); spine_switch_coords_.emplace_back(); + spine_switch_internal_drivers_.emplace_back(); spine_parents_.emplace_back(); spine_children_.emplace_back(); spine_parent_trees_.emplace_back(); @@ -544,7 +562,7 @@ void ClockNetwork::set_spine_track_type(const ClockSpineId& spine_id, spine_track_types_[spine_id] = type; } -void ClockNetwork::add_spine_switch_point(const ClockSpineId& spine_id, +ClockSwitchPointId 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)); @@ -563,6 +581,27 @@ void ClockNetwork::add_spine_switch_point(const ClockSpineId& spine_id, } spine_parents_[drive_spine_id] = spine_id; spine_children_[spine_id].push_back(drive_spine_id); + return ClockSwitchPointId(spine_switch_points_[spine_id].size() - 1); +} + +ClockInternalDriverId ClockNetwork::add_spine_switch_point_internal_driver(const ClockSpineId& spine_id, + const ClockSwitchPointId& switch_point_id, + const std::string& int_driver_port) { + VTR_ASSERT(valid_spine_id(spine_id)); + VTR_ASSERT(valid_spine_switch_point_id(spine_id, switch_point_id)); + /* Find any existing id for the driver port */ + for (ClockInternalDriverId int_driver_id : internal_driver_ids_) { + if (internal_driver_ports_[int_driver_id] == int_driver_port) { + spine_switch_internal_drivers_[spine_id][size_t(switch_point_id)].push_back(int_driver_id); + return int_driver_id; + } + } + /* Reaching here, no existing id can be reused, create a new one */ + ClockInternalDriverId int_driver_id = ClockInternalDriverId(internal_driver_ids_.size()); + internal_driver_ids_.push_back(int_driver_id); + internal_driver_ports_.push_back(int_driver_port); + spine_switch_internal_drivers_[spine_id][size_t(switch_point_id)].push_back(int_driver_id); + return int_driver_id; } void ClockNetwork::add_tree_tap(const ClockTreeId& tree_id, @@ -717,6 +756,11 @@ bool ClockNetwork::valid_tree_id(const ClockTreeId& tree_id) const { (tree_id == tree_ids_[tree_id]); } +bool ClockNetwork::valid_internal_driver_id(const ClockInternalDriverId& int_driver_id) const { + return (size_t(int_driver_id) < internal_driver_ids_.size()) && + (int_driver_id == internal_driver_ids_[int_driver_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 3cf37a79a..836781ee6 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.h +++ b/libs/libclkarchopenfpga/src/base/clock_network.h @@ -42,6 +42,10 @@ class ClockNetwork { clock_tree_iterator; /* Create range */ typedef vtr::Range clock_tree_range; + typedef vtr::vector::const_iterator + clock_internal_driver_iterator; + /* Create range */ + typedef vtr::Range clock_internal_driver_range; public: /* Constructors */ ClockNetwork(); @@ -49,6 +53,7 @@ class ClockNetwork { public: /* Accessors: aggregates */ size_t num_trees() const; clock_tree_range trees() const; + clock_internal_driver_range internal_drivers() const; /* Return the range of clock levels */ std::vector levels(const ClockTreeId& tree_id) const; /* Return a list of spine id under a clock tree */ @@ -116,6 +121,11 @@ class ClockNetwork { vtr::Point spine_switch_point( const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id) const; + std::vector spine_switch_point_internal_drivers( + const ClockSpineId& spine_id, + const ClockSwitchPointId& switch_point_id) const; + std::string internal_driver_port(const ClockInternalDriverId& int_driver_id) const; + /* Return the original list of tap pins that is in storage; useful for parsers */ std::vector tree_taps(const ClockTreeId& tree_id) const; @@ -172,9 +182,12 @@ class ClockNetwork { void set_spine_direction(const ClockSpineId& spine_id, const Direction& dir); void set_spine_track_type(const ClockSpineId& spine_id, const t_rr_type& type); - void add_spine_switch_point(const ClockSpineId& spine_id, + ClockSwitchPointId add_spine_switch_point(const ClockSpineId& spine_id, const ClockSpineId& drive_spine_id, const vtr::Point& coord); + 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); /* Build internal links between clock tree, spines etc. This is also an * validator to verify the correctness of the clock network. Must run before @@ -184,6 +197,7 @@ 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; @@ -245,10 +259,15 @@ class ClockNetwork { vtr::vector spine_track_types_; vtr::vector> spine_switch_points_; vtr::vector>> spine_switch_coords_; + vtr::vector>> spine_switch_internal_drivers_; vtr::vector spine_parents_; vtr::vector> spine_children_; vtr::vector spine_parent_trees_; + /* Basic Information about internal drivers */ + vtr::vector internal_driver_ids_; + vtr::vector internal_driver_ports_; + /* Default routing resource */ std::string default_segment_name_; /* The routing segment representing the clock wires */ diff --git a/libs/libclkarchopenfpga/src/base/clock_network_fwd.h b/libs/libclkarchopenfpga/src/base/clock_network_fwd.h index 1285f069c..e9602d384 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network_fwd.h +++ b/libs/libclkarchopenfpga/src/base/clock_network_fwd.h @@ -19,12 +19,14 @@ struct clock_tree_id_tag; struct clock_tree_pin_id_tag; struct clock_spine_id_tag; struct clock_switch_point_id_tag; +struct clock_internal_driver_id_tag; typedef vtr::StrongId ClockLevelId; typedef vtr::StrongId ClockTreeId; typedef vtr::StrongId ClockTreePinId; typedef vtr::StrongId ClockSpineId; typedef vtr::StrongId ClockSwitchPointId; +typedef vtr::StrongId ClockInternalDriverId; /* 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 a172b88ec..6856a49f2 100644 --- a/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h +++ b/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h @@ -22,6 +22,8 @@ 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_SWITCH_POINT_NODE_NAME = "switch_point"; +constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_NODE_NAME = "internal_driver"; +constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ARRIBUTER_TILE_PIN = "tile_pin"; 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"; diff --git a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp index 372ec0c81..bdd3c6ab1 100644 --- a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp @@ -56,6 +56,24 @@ static void read_xml_clock_tree_taps(pugi::xml_node& xml_taps, } } +/******************************************************************** + * Parse XML codes of a to an object of ClockNetwork + *******************************************************************/ +static void read_xml_clock_spine_switch_point_internal_driver( + pugi::xml_node& xml_int_driver, const pugiutil::loc_data& loc_data, + ClockNetwork& clk_ntwk, const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id) { + if (!clk_ntwk.valid_spine_id(spine_id)) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_switch_point), + "Invalid id of a clock spine!\n"); + } + + std::string int_driver_port_name = + get_attribute(xml_int_driver, XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ATTRIBUTE_TILE_PIN, + loc_data) + .as_string(); + clk_ntwk.add_spine_switch_point(spine_id, switch_point_id, int_driver_port_name); +} + /******************************************************************** * Parse XML codes of a to an object of ClockNetwork *******************************************************************/ @@ -90,8 +108,21 @@ static void read_xml_clock_spine_switch_point( XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_Y, loc_data) .as_int(); - clk_ntwk.add_spine_switch_point(spine_id, tap_spine_id, - vtr::Point(tap_x, tap_y)); + ClockSwitchPointId switch_point_id = clk_ntwk.add_spine_switch_point(spine_id, tap_spine_id, + vtr::Point(tap_x, tap_y)); + + /* Add internal drivers if possible */ + for (pugi::xml_node xml_int_driver : xml_switch_point.children()) { + /* Error out if the XML child has an invalid name! */ + if (xml_int_driver.name() == + std::string(XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_NODE_NAME)) { + read_xml_clock_spine_switch_point_internal_driver(xml_int_driver, loc_data, clk_ntwk, + spine_id, switch_point_id); + } else { + bad_tag(xml_int_driver, loc_data, xml_switch_point, + {XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_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 a71051fe1..ce8380c77 100644 --- a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp @@ -59,9 +59,23 @@ static int write_xml_clock_spine_switch_point( clk_ntwk.spine_switch_point(spine_id, switch_point_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"; + + /* Optional: internal drivers */ + if (clk_ntwk.spine_switch_point_internal_drivers(spine_id, switch_point_id).empty()) { + fp << "/>" + << "\n"; + } else { + fp << ">" + << "\n"; + for (ClockInternalDriverId int_driver_id : clk_ntwk.spine_switch_point_internal_drivers(spine_id, switch_point_id)) { + openfpga::write_tab_to_file(fp, 4); + fp << "<" << XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_NODE_NAME; + write_xml_attribute(fp, XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ARRIBUTER_TILE_PIN, clk_ntwk.internal_driver_port(int_driver_id).c_str()); + fp << "/>" + << "\n"; + } + fp << "\n"; + } return 0; } From 2eda2825b7417501a8bc6ff6e92b3c47f041f6df Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 24 Jun 2024 18:28:42 -0700 Subject: [PATCH 17/86] [lib] syntax --- libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h | 2 +- libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp | 4 ++-- libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h b/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h index 6856a49f2..9eab6bd8f 100644 --- a/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h +++ b/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h @@ -23,7 +23,7 @@ constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_TYPE = "type"; constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_DIRECTION = "direction"; 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"; -constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ARRIBUTER_TILE_PIN = "tile_pin"; +constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ATTRIBUTE_TILE_PIN = "tile_pin"; 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"; diff --git a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp index bdd3c6ab1..be73eb689 100644 --- a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp @@ -63,7 +63,7 @@ static void read_xml_clock_spine_switch_point_internal_driver( pugi::xml_node& xml_int_driver, const pugiutil::loc_data& loc_data, ClockNetwork& clk_ntwk, const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id) { if (!clk_ntwk.valid_spine_id(spine_id)) { - archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_switch_point), + archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_int_driver), "Invalid id of a clock spine!\n"); } @@ -71,7 +71,7 @@ static void read_xml_clock_spine_switch_point_internal_driver( get_attribute(xml_int_driver, XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ATTRIBUTE_TILE_PIN, loc_data) .as_string(); - clk_ntwk.add_spine_switch_point(spine_id, switch_point_id, int_driver_port_name); + clk_ntwk.add_spine_switch_point_internal_driver(spine_id, switch_point_id, int_driver_port_name); } /******************************************************************** diff --git a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp index ce8380c77..e107a4606 100644 --- a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp @@ -70,7 +70,7 @@ static int write_xml_clock_spine_switch_point( for (ClockInternalDriverId int_driver_id : clk_ntwk.spine_switch_point_internal_drivers(spine_id, switch_point_id)) { openfpga::write_tab_to_file(fp, 4); fp << "<" << XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_NODE_NAME; - write_xml_attribute(fp, XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ARRIBUTER_TILE_PIN, clk_ntwk.internal_driver_port(int_driver_id).c_str()); + write_xml_attribute(fp, XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ATTRIBUTE_TILE_PIN, clk_ntwk.internal_driver_port(int_driver_id).c_str()); fp << "/>" << "\n"; } From 36ef555dda41a9fb63c2be06b34ed21d778b0581 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 24 Jun 2024 18:33:47 -0700 Subject: [PATCH 18/86] [lib] add example arch for clock arch with internal drivers --- .../arch/example_internal_drivers.xml | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 libs/libclkarchopenfpga/arch/example_internal_drivers.xml diff --git a/libs/libclkarchopenfpga/arch/example_internal_drivers.xml b/libs/libclkarchopenfpga/arch/example_internal_drivers.xml new file mode 100644 index 000000000..2b8a5fe0d --- /dev/null +++ b/libs/libclkarchopenfpga/arch/example_internal_drivers.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 22bee35fd178a8b7bc5dedb8e2401949634d7bbf Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 24 Jun 2024 18:47:56 -0700 Subject: [PATCH 19/86] [lib] mem allocate --- libs/libclkarchopenfpga/src/base/clock_network.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index 4972e303b..ecfdd48c6 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -569,6 +569,7 @@ ClockSwitchPointId ClockNetwork::add_spine_switch_point(const ClockSpineId& spin VTR_ASSERT(valid_spine_id(drive_spine_id)); spine_switch_points_[spine_id].push_back(drive_spine_id); spine_switch_coords_[spine_id].push_back(coord); + spine_switch_internal_drivers_[spine_id].emplace_back(); /* Do not allow any spine has different parents */ if (spine_parents_[drive_spine_id]) { VTR_LOG_ERROR( From 272d78eb43fa56d2d793f943b2fb7ff9d6399809 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 24 Jun 2024 19:13:36 -0700 Subject: [PATCH 20/86] [test] add a new unit test --- libs/libclkarchopenfpga/test/xml_io_clock_network.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libs/libclkarchopenfpga/test/xml_io_clock_network.cpp b/libs/libclkarchopenfpga/test/xml_io_clock_network.cpp index 7a3708c67..fbabf50c5 100644 --- a/libs/libclkarchopenfpga/test/xml_io_clock_network.cpp +++ b/libs/libclkarchopenfpga/test/xml_io_clock_network.cpp @@ -22,6 +22,10 @@ int main(int argc, const char** argv) { /* Validate before write out */ if (!clk_ntwk.link()) { + VTR_LOG_ERROR("Invalid clock network when linking.\n"); + exit(1); + } + if (!clk_ntwk.validate()) { VTR_LOG_ERROR("Invalid clock network.\n"); exit(1); } From 31d4b4c40258e65f207f87cebe749f6285d0ddd0 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 25 Jun 2024 11:27:22 -0700 Subject: [PATCH 21/86] [core] now support add internal drivers to clock tree --- .../src/base/clock_network.cpp | 40 +++++ .../src/base/clock_network.h | 1 + .../src/annotation/append_clock_rr_graph.cpp | 145 +++++++++++++++++- 3 files changed, 185 insertions(+), 1 deletion(-) diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index ecfdd48c6..9c493c9f7 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -389,6 +389,46 @@ std::vector ClockNetwork::tree_flatten_taps( return flatten_taps; } +std::vector ClockNetwork::flatten_internal_driver_port(const ClockInternalDriverId& int_driver_id) const { + std::vector flatten_taps; + for (const std::string& tap_name : internal_driver_port(int_driver_id)) { + StringToken tokenizer(tap_name); + std::vector pin_tokens = tokenizer.split("."); + if (pin_tokens.size() != 2) { + VTR_LOG_ERROR("Invalid pin name '%s'. Expect .\n", + tap_name.c_str()); + exit(1); + } + PortParser tile_parser(pin_tokens[0]); + BasicPort tile_info = tile_parser.port(); + PortParser pin_parser(pin_tokens[1]); + BasicPort pin_info = pin_parser.port(); + if (!tile_info.is_valid()) { + VTR_LOG_ERROR("Invalid pin name '%s' whose subtile index is not valid\n", + tap_name.c_str()); + exit(1); + } + if (!pin_info.is_valid()) { + VTR_LOG_ERROR("Invalid pin name '%s' whose pin index is not valid\n", + tap_name.c_str()); + exit(1); + } + for (size_t& tile_idx : tile_info.pins()) { + std::string flatten_tile_str = + tile_info.get_name() + "[" + std::to_string(tile_idx) + "]"; + for (size_t& pin_idx : pin_info.pins()) { + if (pin_idx != size_t(clk_pin_id)) { + continue; + } + std::string flatten_pin_str = + pin_info.get_name() + "[" + std::to_string(pin_idx) + "]"; + flatten_taps.push_back(flatten_tile_str + "." + flatten_pin_str); + } + } + } + return flatten_taps; +} + ClockTreeId ClockNetwork::find_tree(const std::string& name) const { auto result = tree_name2id_map_.find(name); if (result == tree_name2id_map_.end()) { diff --git a/libs/libclkarchopenfpga/src/base/clock_network.h b/libs/libclkarchopenfpga/src/base/clock_network.h index 836781ee6..6a972cb46 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.h +++ b/libs/libclkarchopenfpga/src/base/clock_network.h @@ -125,6 +125,7 @@ class ClockNetwork { const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id) const; std::string internal_driver_port(const ClockInternalDriverId& int_driver_id) const; + std::vector flatten_internal_driver_port(const ClockInternalDriverId& int_driver_id) const; /* Return the original list of tap pins that is in storage; useful for parsers */ diff --git a/openfpga/src/annotation/append_clock_rr_graph.cpp b/openfpga/src/annotation/append_clock_rr_graph.cpp index ac48b5cef..3263c838b 100644 --- a/openfpga/src/annotation/append_clock_rr_graph.cpp +++ b/openfpga/src/annotation/append_clock_rr_graph.cpp @@ -545,7 +545,7 @@ static void add_rr_graph_block_clock_edges( clk_ntwk.default_tap_switch(), false); edge_count++; } - VTR_LOGV(verbose, "\tWill add %lu edges to other IPIN\n", + VTR_LOGV(verbose, "\tWill add %lu edges to IPINs\n", edge_count - curr_edge_count); } } @@ -557,6 +557,147 @@ static void add_rr_graph_block_clock_edges( num_edges_to_create += edge_count; } +/******************************************************************** + * Try to find an OPIN of a grid which satisfy the requirement of clock pins + * that has been defined in clock network. If the OPIN does exist in a + * routing resource graph, add it to the node list + *******************************************************************/ +static void try_find_and_add_clock_opin2track_node( + std::vector& opin_nodes, const DeviceGrid& grids, + const RRGraphView& rr_graph_view, const size_t& layer, + const vtr::Point& grid_coord, const e_side& pin_side, + const ClockNetwork& clk_ntwk, + const ClockInternalDriverId& int_driver_id) { + t_physical_tile_type_ptr grid_type = grids.get_physical_type( + t_physical_tile_loc(grid_coord.x(), grid_coord.y(), layer)); + for (std::string tap_pin_name : + clk_ntwk.flatten_internal_driver_port(int_driver_id)) { + /* tap pin name could be 'io[5:5].a2f[0]' */ + int grid_pin_idx = find_physical_tile_pin_index(grid_type, tap_pin_name); + if (grid_pin_idx == grid_type->num_pins) { + continue; + } + RRNodeId opin_node = rr_graph_view.node_lookup().find_node( + layer, grid_coord.x(), grid_coord.y(), OPIN, grid_pin_idx, pin_side); + if (rr_graph_view.valid_node(opin_node)) { + opin_nodes.push_back(opin_node); + } + } +} + +/******************************************************************** + * Find the source OPIN nodes as internal drivers for a clock node + * For example + * clk0_lvl1_chany[1][1] + * ^ + * | + * internal_driver OPIN[0] -->-------+ + * ^ + * | + * internal_driver OPIN[1] + * + * Coordinate system: + * + * +----------+----------+------------+ + * | Grid | CBy | Grid | + * | [x][y+1] | [x][y+1] | [x+1][y+1] | + * +----------+----------+------------+ + * | CBx | SB | CBx | + * | [x][y] | [x][y] | [x+1][y] | + * +----------+----------+------------+ + * | Grid | CBy | Grid | + * | [x][y] | [x][y] | [x+1][y] | + * +----------+----------+------------+ + *******************************************************************/ +static std::vector find_clock_opin2track_node( + const DeviceGrid& grids, const RRGraphView& rr_graph_view, + const size_t& layer, + const vtr::Point& sb_coord, + const ClockNetwork& clk_ntwk, + const std::vector& int_driver_ids +) { + std::vector opin_nodes; + /* Find opins from + * - Grid[x][y+1] on right and bottom sides + * - Grid[x+1][y+1] on left and bottom sides + * - Grid[x][y] on right and top sides + * - Grid[x+1][y] on left and top sides + */ + std::array, 4> grid_coords; + std::array, 2>, 4> grid_sides; + grid_coords[0] = grid_coord(sb_coord.x(), sb_coord.y() + 1); + grid_sides[0] = {RIGHT, BOTTOM}; + grid_coords[1] = grid_coord(sb_coord.x() + 1, sb_coord.y() + 1); + grid_sides[1] = {LEFT, BOTTOM}; + grid_coords[2] = grid_coord(sb_coord.x() + 1, sb_coord.y()); + grid_sides[2] = {RIGHT, TOP}; + grid_coords[3] = grid_coord(sb_coord.x(), sb_coord.y()); + grid_sides[3] = {LEFT, TOP}; + for (size_t igrid = 0; igrid < 4; igrid++) { + vtr::Point grid_coord = grid_coords[igrid]; + for (e_side grid_side : grid_sides[igrid]) { + for (ClockInternalDriverId int_driver_id : int_driver_ids) { + try_find_and_add_clock_opin2track_node(opin_nodes, grids, rr_graph_view, + layer, grid_coord, grid_side, + clk_ntwk, int_driver_id); + } + } + } + return opin_nodes; +} + +/******************************************************************** + * Add edges between OPIN of programmable blocks and clock routing tracks + * Note that such edges only occur at the switching points of spines + * Different from add_rr_graph_block_clock_edges(), we follow the clock spines here + * By expanding on switching points, internal drivers will be added + *******************************************************************/ +static int add_rr_graph_opin2clk_edges(RRGraphBuilder& rr_graph_builder, size_t& num_edges_to_create, + const RRClockSpatialLookup& clk_rr_lookup, const RRGraphView& rr_graph_view, + const DeviceGrid& grids, const size_t& layer, + const ClockNetwork& clk_ntwk, const bool& verbose) { + size_t edge_count = 0; + for (ClockSpineId ispine : clk_ntwk.spines(clk_tree)) { + VTR_LOGV(verbose, "Finding internal drivers on spine '%s'...\n", + clk_ntwk.spine_name(ispine).c_str()); + for (auto ipin : clk_ntwk.pins(clk_tree)) { + for (ClockSwitchPointId switch_point_id : + clk_ntwk.spine_switch_points(ispine)) { + if (clk_ntwk.spine_switch_point_internal_drivers(ispine, switch_point_id).empty()) { + continue; /* We only focus on switching points containing internal drivers */ + } + size_t curr_edge_count = edge_count; + /* Get the rr node of destination spine */ + ClockSpineId des_spine = + clk_ntwk.spine_switch_point_tap(ispine, switch_point_id); + vtr::Point des_coord = clk_ntwk.spine_start_point(des_spine); + Direction des_spine_direction = clk_ntwk.spine_direction(des_spine); + ClockLevelId des_spine_level = clk_ntwk.spine_level(des_spine); + RRNodeId des_node = + clk_rr_lookup.find_node(des_coord.x(), des_coord.y(), clk_tree, + des_spine_level, ipin, des_spine_direction); + /* Walk through each qualified OPIN, build edges */ + vtr::Point src_coord = + clk_ntwk.spine_switch_point(ispine, switch_point_id); + std::vector int_driver_ids = clk_ntwk.spine_switch_point_internal_drivers(ispine, switch_point_id); + for (RRNodId src_node : find_clock_opin2track_node(grids, rr_graph_view, layer, src_coord, clk_ntwk, int_driver_ids)) { + /* Create edges */ + VTR_ASSERT(rr_graph_view.valid_node(des_node)); + rr_graph_builder.create_edge(src_node, des_node, + clk_ntwk.default_driver_switch(), false); + edge_count++; + } + VTR_LOGV(verbose, "\tWill add %lu edges to OPINs at (x=%lu, y=%lu)\n", + edge_count - curr_edge_count, des_coord.x(), des_coord.y()); + } + } + } + /* Allocate edges */ + rr_graph_builder.build_edges(true); + num_edges_to_create += edge_count; + return CMD_EXEC_SUCCESS; +} + /******************************************************************** * Add edges to interconnect clock nodes * Walk through the routing tracks in each connection block (driver nodes) @@ -614,6 +755,8 @@ static void add_rr_graph_clock_edges( clk_ntwk, chany_coord, CHANY, verbose); } } + /* Add edges between OPIN (internal driver) and clock routing tracks */ + add_rr_graph_opin2clk_edges(rr_graph_builder, num_edges_to_create, rr_graph_view, grids, layer, clk_ntwk, verbose); } /******************************************************************** From 3b2c13402a3cfa2ea35160ba9f6bfa23500288c8 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 25 Jun 2024 11:44:25 -0700 Subject: [PATCH 22/86] [core] syntax --- .../src/base/clock_network.cpp | 62 +++++++-------- .../src/annotation/append_clock_rr_graph.cpp | 78 ++++++++++--------- 2 files changed, 69 insertions(+), 71 deletions(-) diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index 9c493c9f7..b76631c5c 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -391,39 +391,35 @@ std::vector ClockNetwork::tree_flatten_taps( std::vector ClockNetwork::flatten_internal_driver_port(const ClockInternalDriverId& int_driver_id) const { std::vector flatten_taps; - for (const std::string& tap_name : internal_driver_port(int_driver_id)) { - StringToken tokenizer(tap_name); - std::vector pin_tokens = tokenizer.split("."); - if (pin_tokens.size() != 2) { - VTR_LOG_ERROR("Invalid pin name '%s'. Expect .\n", - tap_name.c_str()); - exit(1); - } - PortParser tile_parser(pin_tokens[0]); - BasicPort tile_info = tile_parser.port(); - PortParser pin_parser(pin_tokens[1]); - BasicPort pin_info = pin_parser.port(); - if (!tile_info.is_valid()) { - VTR_LOG_ERROR("Invalid pin name '%s' whose subtile index is not valid\n", - tap_name.c_str()); - exit(1); - } - if (!pin_info.is_valid()) { - VTR_LOG_ERROR("Invalid pin name '%s' whose pin index is not valid\n", - tap_name.c_str()); - exit(1); - } - for (size_t& tile_idx : tile_info.pins()) { - std::string flatten_tile_str = - tile_info.get_name() + "[" + std::to_string(tile_idx) + "]"; - for (size_t& pin_idx : pin_info.pins()) { - if (pin_idx != size_t(clk_pin_id)) { - continue; - } - std::string flatten_pin_str = - pin_info.get_name() + "[" + std::to_string(pin_idx) + "]"; - flatten_taps.push_back(flatten_tile_str + "." + flatten_pin_str); - } + std::string tap_name = internal_driver_port(int_driver_id); + StringToken tokenizer(tap_name); + std::vector pin_tokens = tokenizer.split("."); + if (pin_tokens.size() != 2) { + VTR_LOG_ERROR("Invalid pin name '%s'. Expect .\n", + tap_name.c_str()); + exit(1); + } + PortParser tile_parser(pin_tokens[0]); + BasicPort tile_info = tile_parser.port(); + PortParser pin_parser(pin_tokens[1]); + BasicPort pin_info = pin_parser.port(); + if (!tile_info.is_valid()) { + VTR_LOG_ERROR("Invalid pin name '%s' whose subtile index is not valid\n", + tap_name.c_str()); + exit(1); + } + if (!pin_info.is_valid()) { + VTR_LOG_ERROR("Invalid pin name '%s' whose pin index is not valid\n", + tap_name.c_str()); + exit(1); + } + for (size_t& tile_idx : tile_info.pins()) { + std::string flatten_tile_str = + tile_info.get_name() + "[" + std::to_string(tile_idx) + "]"; + for (size_t& pin_idx : pin_info.pins()) { + std::string flatten_pin_str = + pin_info.get_name() + "[" + std::to_string(pin_idx) + "]"; + flatten_taps.push_back(flatten_tile_str + "." + flatten_pin_str); } } return flatten_taps; diff --git a/openfpga/src/annotation/append_clock_rr_graph.cpp b/openfpga/src/annotation/append_clock_rr_graph.cpp index 3263c838b..ecfe5e874 100644 --- a/openfpga/src/annotation/append_clock_rr_graph.cpp +++ b/openfpga/src/annotation/append_clock_rr_graph.cpp @@ -565,7 +565,7 @@ static void add_rr_graph_block_clock_edges( static void try_find_and_add_clock_opin2track_node( std::vector& opin_nodes, const DeviceGrid& grids, const RRGraphView& rr_graph_view, const size_t& layer, - const vtr::Point& grid_coord, const e_side& pin_side, + const vtr::Point& grid_coord, const e_side& pin_side, const ClockNetwork& clk_ntwk, const ClockInternalDriverId& int_driver_id) { t_physical_tile_type_ptr grid_type = grids.get_physical_type( @@ -624,14 +624,14 @@ static std::vector find_clock_opin2track_node( * - Grid[x+1][y] on left and top sides */ std::array, 4> grid_coords; - std::array, 2>, 4> grid_sides; - grid_coords[0] = grid_coord(sb_coord.x(), sb_coord.y() + 1); + std::array, 4> grid_sides; + grid_coords[0] = vtr::Point(sb_coord.x(), sb_coord.y() + 1); grid_sides[0] = {RIGHT, BOTTOM}; - grid_coords[1] = grid_coord(sb_coord.x() + 1, sb_coord.y() + 1); + grid_coords[1] = vtr::Point(sb_coord.x() + 1, sb_coord.y() + 1); grid_sides[1] = {LEFT, BOTTOM}; - grid_coords[2] = grid_coord(sb_coord.x() + 1, sb_coord.y()); + grid_coords[2] = vtr::Point(sb_coord.x() + 1, sb_coord.y()); grid_sides[2] = {RIGHT, TOP}; - grid_coords[3] = grid_coord(sb_coord.x(), sb_coord.y()); + grid_coords[3] = vtr::Point(sb_coord.x(), sb_coord.y()); grid_sides[3] = {LEFT, TOP}; for (size_t igrid = 0; igrid < 4; igrid++) { vtr::Point grid_coord = grid_coords[igrid]; @@ -657,38 +657,40 @@ static int add_rr_graph_opin2clk_edges(RRGraphBuilder& rr_graph_builder, size_t& const DeviceGrid& grids, const size_t& layer, const ClockNetwork& clk_ntwk, const bool& verbose) { size_t edge_count = 0; - for (ClockSpineId ispine : clk_ntwk.spines(clk_tree)) { - VTR_LOGV(verbose, "Finding internal drivers on spine '%s'...\n", - clk_ntwk.spine_name(ispine).c_str()); - for (auto ipin : clk_ntwk.pins(clk_tree)) { - for (ClockSwitchPointId switch_point_id : - clk_ntwk.spine_switch_points(ispine)) { - if (clk_ntwk.spine_switch_point_internal_drivers(ispine, switch_point_id).empty()) { - continue; /* We only focus on switching points containing internal drivers */ + for (ClockTreeId clk_tree : clk_ntwk.trees()) { + for (ClockSpineId ispine : clk_ntwk.spines(clk_tree)) { + VTR_LOGV(verbose, "Finding internal drivers on spine '%s'...\n", + clk_ntwk.spine_name(ispine).c_str()); + for (auto ipin : clk_ntwk.pins(clk_tree)) { + for (ClockSwitchPointId switch_point_id : + clk_ntwk.spine_switch_points(ispine)) { + if (clk_ntwk.spine_switch_point_internal_drivers(ispine, switch_point_id).empty()) { + continue; /* We only focus on switching points containing internal drivers */ + } + size_t curr_edge_count = edge_count; + /* Get the rr node of destination spine */ + ClockSpineId des_spine = + clk_ntwk.spine_switch_point_tap(ispine, switch_point_id); + vtr::Point des_coord = clk_ntwk.spine_start_point(des_spine); + Direction des_spine_direction = clk_ntwk.spine_direction(des_spine); + ClockLevelId des_spine_level = clk_ntwk.spine_level(des_spine); + RRNodeId des_node = + clk_rr_lookup.find_node(des_coord.x(), des_coord.y(), clk_tree, + des_spine_level, ipin, des_spine_direction); + /* Walk through each qualified OPIN, build edges */ + vtr::Point src_coord = + clk_ntwk.spine_switch_point(ispine, switch_point_id); + std::vector int_driver_ids = clk_ntwk.spine_switch_point_internal_drivers(ispine, switch_point_id); + for (RRNodeId src_node : find_clock_opin2track_node(grids, rr_graph_view, layer, src_coord, clk_ntwk, int_driver_ids)) { + /* Create edges */ + VTR_ASSERT(rr_graph_view.valid_node(des_node)); + rr_graph_builder.create_edge(src_node, des_node, + clk_ntwk.default_driver_switch(), false); + edge_count++; + } + VTR_LOGV(verbose, "\tWill add %lu edges to OPINs at (x=%lu, y=%lu)\n", + edge_count - curr_edge_count, des_coord.x(), des_coord.y()); } - size_t curr_edge_count = edge_count; - /* Get the rr node of destination spine */ - ClockSpineId des_spine = - clk_ntwk.spine_switch_point_tap(ispine, switch_point_id); - vtr::Point des_coord = clk_ntwk.spine_start_point(des_spine); - Direction des_spine_direction = clk_ntwk.spine_direction(des_spine); - ClockLevelId des_spine_level = clk_ntwk.spine_level(des_spine); - RRNodeId des_node = - clk_rr_lookup.find_node(des_coord.x(), des_coord.y(), clk_tree, - des_spine_level, ipin, des_spine_direction); - /* Walk through each qualified OPIN, build edges */ - vtr::Point src_coord = - clk_ntwk.spine_switch_point(ispine, switch_point_id); - std::vector int_driver_ids = clk_ntwk.spine_switch_point_internal_drivers(ispine, switch_point_id); - for (RRNodId src_node : find_clock_opin2track_node(grids, rr_graph_view, layer, src_coord, clk_ntwk, int_driver_ids)) { - /* Create edges */ - VTR_ASSERT(rr_graph_view.valid_node(des_node)); - rr_graph_builder.create_edge(src_node, des_node, - clk_ntwk.default_driver_switch(), false); - edge_count++; - } - VTR_LOGV(verbose, "\tWill add %lu edges to OPINs at (x=%lu, y=%lu)\n", - edge_count - curr_edge_count, des_coord.x(), des_coord.y()); } } } @@ -756,7 +758,7 @@ static void add_rr_graph_clock_edges( } } /* Add edges between OPIN (internal driver) and clock routing tracks */ - add_rr_graph_opin2clk_edges(rr_graph_builder, num_edges_to_create, rr_graph_view, grids, layer, clk_ntwk, verbose); + add_rr_graph_opin2clk_edges(rr_graph_builder, num_edges_to_create, clk_rr_lookup, rr_graph_view, grids, layer, clk_ntwk, verbose); } /******************************************************************** From 7bcbd8a88be36b1fef8186465d74c1b8a3c5efad Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 25 Jun 2024 11:44:50 -0700 Subject: [PATCH 23/86] [core] code format --- .../src/base/clock_network.cpp | 43 +++++++++------- .../src/base/clock_network.h | 31 ++++++----- .../src/io/clock_network_xml_constants.h | 6 ++- .../src/io/read_xml_clock_network.cpp | 21 ++++---- .../src/io/write_xml_clock_network.cpp | 13 +++-- .../src/utils/clock_network_utils.cpp | 4 +- .../src/annotation/append_clock_rr_graph.cpp | 51 +++++++++++-------- .../src/base/openfpga_read_arch_template.h | 5 +- 8 files changed, 104 insertions(+), 70 deletions(-) diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index b76631c5c..20e1f116c 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -32,8 +32,10 @@ ClockNetwork::clock_tree_range ClockNetwork::trees() const { return vtr::make_range(tree_ids_.begin(), tree_ids_.end()); } -ClockNetwork::clock_internal_driver_range ClockNetwork::internal_drivers() const { - return vtr::make_range(internal_driver_ids_.begin(), internal_driver_ids_.end()); +ClockNetwork::clock_internal_driver_range ClockNetwork::internal_drivers() + const { + return vtr::make_range(internal_driver_ids_.begin(), + internal_driver_ids_.end()); } std::vector ClockNetwork::levels( @@ -329,14 +331,16 @@ vtr::Point ClockNetwork::spine_switch_point( return spine_switch_coords_[spine_id][size_t(switch_point_id)]; } -std::vector ClockNetwork::spine_switch_point_internal_drivers( +std::vector +ClockNetwork::spine_switch_point_internal_drivers( 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_internal_drivers_[spine_id][size_t(switch_point_id)]; } -std::string ClockNetwork::internal_driver_port(const ClockInternalDriverId& int_driver_id) const { +std::string ClockNetwork::internal_driver_port( + const ClockInternalDriverId& int_driver_id) const { VTR_ASSERT(valid_internal_driver_id(int_driver_id)); return internal_driver_ports_[int_driver_id]; } @@ -389,7 +393,8 @@ std::vector ClockNetwork::tree_flatten_taps( return flatten_taps; } -std::vector ClockNetwork::flatten_internal_driver_port(const ClockInternalDriverId& int_driver_id) const { +std::vector ClockNetwork::flatten_internal_driver_port( + const ClockInternalDriverId& int_driver_id) const { std::vector flatten_taps; std::string tap_name = internal_driver_port(int_driver_id); StringToken tokenizer(tap_name); @@ -598,9 +603,9 @@ void ClockNetwork::set_spine_track_type(const ClockSpineId& spine_id, spine_track_types_[spine_id] = type; } -ClockSwitchPointId ClockNetwork::add_spine_switch_point(const ClockSpineId& spine_id, - const ClockSpineId& drive_spine_id, - const vtr::Point& coord) { +ClockSwitchPointId 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_id); @@ -621,24 +626,27 @@ ClockSwitchPointId ClockNetwork::add_spine_switch_point(const ClockSpineId& spin return ClockSwitchPointId(spine_switch_points_[spine_id].size() - 1); } -ClockInternalDriverId ClockNetwork::add_spine_switch_point_internal_driver(const ClockSpineId& spine_id, - const ClockSwitchPointId& switch_point_id, - const std::string& int_driver_port) { +ClockInternalDriverId ClockNetwork::add_spine_switch_point_internal_driver( + const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id, + const std::string& int_driver_port) { VTR_ASSERT(valid_spine_id(spine_id)); VTR_ASSERT(valid_spine_switch_point_id(spine_id, switch_point_id)); /* Find any existing id for the driver port */ for (ClockInternalDriverId int_driver_id : internal_driver_ids_) { if (internal_driver_ports_[int_driver_id] == int_driver_port) { - spine_switch_internal_drivers_[spine_id][size_t(switch_point_id)].push_back(int_driver_id); - return int_driver_id; + spine_switch_internal_drivers_[spine_id][size_t(switch_point_id)] + .push_back(int_driver_id); + return int_driver_id; } } /* Reaching here, no existing id can be reused, create a new one */ - ClockInternalDriverId int_driver_id = ClockInternalDriverId(internal_driver_ids_.size()); + ClockInternalDriverId int_driver_id = + ClockInternalDriverId(internal_driver_ids_.size()); internal_driver_ids_.push_back(int_driver_id); internal_driver_ports_.push_back(int_driver_port); - spine_switch_internal_drivers_[spine_id][size_t(switch_point_id)].push_back(int_driver_id); - return int_driver_id; + spine_switch_internal_drivers_[spine_id][size_t(switch_point_id)].push_back( + int_driver_id); + return int_driver_id; } void ClockNetwork::add_tree_tap(const ClockTreeId& tree_id, @@ -793,7 +801,8 @@ bool ClockNetwork::valid_tree_id(const ClockTreeId& tree_id) const { (tree_id == tree_ids_[tree_id]); } -bool ClockNetwork::valid_internal_driver_id(const ClockInternalDriverId& int_driver_id) const { +bool ClockNetwork::valid_internal_driver_id( + const ClockInternalDriverId& int_driver_id) const { return (size_t(int_driver_id) < internal_driver_ids_.size()) && (int_driver_id == internal_driver_ids_[int_driver_id]); } diff --git a/libs/libclkarchopenfpga/src/base/clock_network.h b/libs/libclkarchopenfpga/src/base/clock_network.h index 6a972cb46..8884f5c55 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.h +++ b/libs/libclkarchopenfpga/src/base/clock_network.h @@ -42,10 +42,12 @@ class ClockNetwork { clock_tree_iterator; /* Create range */ typedef vtr::Range clock_tree_range; - typedef vtr::vector::const_iterator + typedef vtr::vector::const_iterator clock_internal_driver_iterator; /* Create range */ - typedef vtr::Range clock_internal_driver_range; + typedef vtr::Range + clock_internal_driver_range; public: /* Constructors */ ClockNetwork(); @@ -124,8 +126,10 @@ class ClockNetwork { std::vector spine_switch_point_internal_drivers( const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id) const; - std::string internal_driver_port(const ClockInternalDriverId& int_driver_id) const; - std::vector flatten_internal_driver_port(const ClockInternalDriverId& int_driver_id) const; + std::string internal_driver_port( + const ClockInternalDriverId& int_driver_id) const; + std::vector flatten_internal_driver_port( + const ClockInternalDriverId& int_driver_id) const; /* Return the original list of tap pins that is in storage; useful for parsers */ @@ -184,11 +188,11 @@ class ClockNetwork { void set_spine_track_type(const ClockSpineId& spine_id, const t_rr_type& type); ClockSwitchPointId add_spine_switch_point(const ClockSpineId& spine_id, - const ClockSpineId& drive_spine_id, - const vtr::Point& coord); - ClockInternalDriverId add_spine_switch_point_internal_driver(const ClockSpineId& spine_id, - const ClockSwitchPointId& switch_point_id, - const std::string& internal_driver_port); + const ClockSpineId& drive_spine_id, + const vtr::Point& coord); + 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); /* Build internal links between clock tree, spines etc. This is also an * validator to verify the correctness of the clock network. Must run before @@ -198,7 +202,8 @@ 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; + 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; @@ -260,13 +265,15 @@ class ClockNetwork { vtr::vector spine_track_types_; vtr::vector> spine_switch_points_; vtr::vector>> spine_switch_coords_; - vtr::vector>> spine_switch_internal_drivers_; + vtr::vector>> + spine_switch_internal_drivers_; vtr::vector spine_parents_; vtr::vector> spine_children_; vtr::vector spine_parent_trees_; /* Basic Information about internal drivers */ - vtr::vector internal_driver_ids_; + vtr::vector + internal_driver_ids_; vtr::vector internal_driver_ports_; /* Default routing resource */ diff --git a/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h b/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h index 9eab6bd8f..14b2f1204 100644 --- a/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h +++ b/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h @@ -22,8 +22,10 @@ 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_SWITCH_POINT_NODE_NAME = "switch_point"; -constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_NODE_NAME = "internal_driver"; -constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ATTRIBUTE_TILE_PIN = "tile_pin"; +constexpr const char* XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_NODE_NAME = + "internal_driver"; +constexpr const char* + XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ATTRIBUTE_TILE_PIN = "tile_pin"; 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"; diff --git a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp index be73eb689..152b4ae35 100644 --- a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp @@ -61,17 +61,20 @@ static void read_xml_clock_tree_taps(pugi::xml_node& xml_taps, *******************************************************************/ static void read_xml_clock_spine_switch_point_internal_driver( pugi::xml_node& xml_int_driver, const pugiutil::loc_data& loc_data, - ClockNetwork& clk_ntwk, const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id) { + ClockNetwork& clk_ntwk, const ClockSpineId& spine_id, + const ClockSwitchPointId& switch_point_id) { 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_port_name = - get_attribute(xml_int_driver, XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ATTRIBUTE_TILE_PIN, - loc_data) + get_attribute( + xml_int_driver, + XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ATTRIBUTE_TILE_PIN, loc_data) .as_string(); - clk_ntwk.add_spine_switch_point_internal_driver(spine_id, switch_point_id, int_driver_port_name); + clk_ntwk.add_spine_switch_point_internal_driver(spine_id, switch_point_id, + int_driver_port_name); } /******************************************************************** @@ -108,16 +111,16 @@ static void read_xml_clock_spine_switch_point( XML_CLOCK_SPINE_SWITCH_POINT_ATTRIBUTE_Y, loc_data) .as_int(); - ClockSwitchPointId switch_point_id = clk_ntwk.add_spine_switch_point(spine_id, tap_spine_id, - vtr::Point(tap_x, tap_y)); + ClockSwitchPointId switch_point_id = clk_ntwk.add_spine_switch_point( + spine_id, tap_spine_id, vtr::Point(tap_x, tap_y)); - /* Add internal drivers if possible */ + /* Add internal drivers if possible */ for (pugi::xml_node xml_int_driver : xml_switch_point.children()) { /* Error out if the XML child has an invalid name! */ if (xml_int_driver.name() == std::string(XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_NODE_NAME)) { - read_xml_clock_spine_switch_point_internal_driver(xml_int_driver, loc_data, clk_ntwk, - spine_id, switch_point_id); + read_xml_clock_spine_switch_point_internal_driver( + xml_int_driver, loc_data, clk_ntwk, spine_id, switch_point_id); } else { bad_tag(xml_int_driver, loc_data, xml_switch_point, {XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_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 e107a4606..76d10fbe8 100644 --- a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp @@ -59,18 +59,23 @@ static int write_xml_clock_spine_switch_point( clk_ntwk.spine_switch_point(spine_id, switch_point_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()); - + /* Optional: internal drivers */ - if (clk_ntwk.spine_switch_point_internal_drivers(spine_id, switch_point_id).empty()) { + if (clk_ntwk.spine_switch_point_internal_drivers(spine_id, switch_point_id) + .empty()) { fp << "/>" << "\n"; } else { fp << ">" << "\n"; - for (ClockInternalDriverId int_driver_id : clk_ntwk.spine_switch_point_internal_drivers(spine_id, switch_point_id)) { + for (ClockInternalDriverId int_driver_id : + clk_ntwk.spine_switch_point_internal_drivers(spine_id, + switch_point_id)) { openfpga::write_tab_to_file(fp, 4); fp << "<" << XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_NODE_NAME; - write_xml_attribute(fp, XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ATTRIBUTE_TILE_PIN, clk_ntwk.internal_driver_port(int_driver_id).c_str()); + write_xml_attribute( + fp, XML_CLOCK_SPINE_SWITCH_POINT_INTERNAL_DRIVER_ATTRIBUTE_TILE_PIN, + clk_ntwk.internal_driver_port(int_driver_id).c_str()); fp << "/>" << "\n"; } diff --git a/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp b/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp index 138ac4087..3d82f9c23 100644 --- a/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp +++ b/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp @@ -34,7 +34,7 @@ static int link_clock_network_rr_segments(ClockNetwork& clk_ntwk, *clock network *******************************************************************/ static int link_clock_network_tap_rr_switches(ClockNetwork& clk_ntwk, - const RRGraphView& rr_graph) { + const RRGraphView& rr_graph) { /* default tap switch id */ std::string default_tap_switch_name = clk_ntwk.default_tap_switch_name(); for (size_t rr_switch_id = 0; rr_switch_id < rr_graph.num_rr_switches(); @@ -57,7 +57,7 @@ static int link_clock_network_tap_rr_switches(ClockNetwork& clk_ntwk, *clock network *******************************************************************/ static int link_clock_network_driver_rr_switches(ClockNetwork& clk_ntwk, - const RRGraphView& rr_graph) { + const RRGraphView& rr_graph) { /* default driver switch id */ std::string default_driver_switch_name = clk_ntwk.default_driver_switch_name(); diff --git a/openfpga/src/annotation/append_clock_rr_graph.cpp b/openfpga/src/annotation/append_clock_rr_graph.cpp index ecfe5e874..38d06efc6 100644 --- a/openfpga/src/annotation/append_clock_rr_graph.cpp +++ b/openfpga/src/annotation/append_clock_rr_graph.cpp @@ -525,8 +525,8 @@ static void add_rr_graph_block_clock_edges( chan_coord, itree, ilvl, ClockTreePinId(ipin), node_dir)) { /* Create edges */ VTR_ASSERT(rr_graph_view.valid_node(des_node)); - rr_graph_builder.create_edge(src_node, des_node, - clk_ntwk.default_driver_switch(), false); + rr_graph_builder.create_edge( + src_node, des_node, clk_ntwk.default_driver_switch(), false); edge_count++; } VTR_LOGV(verbose, "\tWill add %lu edges to other clock nodes\n", @@ -541,8 +541,8 @@ static void add_rr_graph_block_clock_edges( itree, ClockTreePinId(ipin))) { /* Create edges */ VTR_ASSERT(rr_graph_view.valid_node(des_node)); - rr_graph_builder.create_edge(src_node, des_node, - clk_ntwk.default_tap_switch(), false); + rr_graph_builder.create_edge( + src_node, des_node, clk_ntwk.default_tap_switch(), false); edge_count++; } VTR_LOGV(verbose, "\tWill add %lu edges to IPINs\n", @@ -566,8 +566,7 @@ static void try_find_and_add_clock_opin2track_node( std::vector& opin_nodes, const DeviceGrid& grids, const RRGraphView& rr_graph_view, const size_t& layer, const vtr::Point& grid_coord, const e_side& pin_side, - const ClockNetwork& clk_ntwk, - const ClockInternalDriverId& int_driver_id) { + const ClockNetwork& clk_ntwk, const ClockInternalDriverId& int_driver_id) { t_physical_tile_type_ptr grid_type = grids.get_physical_type( t_physical_tile_loc(grid_coord.x(), grid_coord.y(), layer)); for (std::string tap_pin_name : @@ -611,11 +610,9 @@ static void try_find_and_add_clock_opin2track_node( *******************************************************************/ static std::vector find_clock_opin2track_node( const DeviceGrid& grids, const RRGraphView& rr_graph_view, - const size_t& layer, - const vtr::Point& sb_coord, + const size_t& layer, const vtr::Point& sb_coord, const ClockNetwork& clk_ntwk, - const std::vector& int_driver_ids -) { + const std::vector& int_driver_ids) { std::vector opin_nodes; /* Find opins from * - Grid[x][y+1] on right and bottom sides @@ -649,13 +646,14 @@ static std::vector find_clock_opin2track_node( /******************************************************************** * Add edges between OPIN of programmable blocks and clock routing tracks * Note that such edges only occur at the switching points of spines - * Different from add_rr_graph_block_clock_edges(), we follow the clock spines here - * By expanding on switching points, internal drivers will be added + * Different from add_rr_graph_block_clock_edges(), we follow the clock spines + *here By expanding on switching points, internal drivers will be added *******************************************************************/ -static int add_rr_graph_opin2clk_edges(RRGraphBuilder& rr_graph_builder, size_t& num_edges_to_create, +static int add_rr_graph_opin2clk_edges( + RRGraphBuilder& rr_graph_builder, size_t& num_edges_to_create, const RRClockSpatialLookup& clk_rr_lookup, const RRGraphView& rr_graph_view, - const DeviceGrid& grids, const size_t& layer, - const ClockNetwork& clk_ntwk, const bool& verbose) { + const DeviceGrid& grids, const size_t& layer, const ClockNetwork& clk_ntwk, + const bool& verbose) { size_t edge_count = 0; for (ClockTreeId clk_tree : clk_ntwk.trees()) { for (ClockSpineId ispine : clk_ntwk.spines(clk_tree)) { @@ -664,8 +662,11 @@ static int add_rr_graph_opin2clk_edges(RRGraphBuilder& rr_graph_builder, size_t& for (auto ipin : clk_ntwk.pins(clk_tree)) { for (ClockSwitchPointId switch_point_id : clk_ntwk.spine_switch_points(ispine)) { - if (clk_ntwk.spine_switch_point_internal_drivers(ispine, switch_point_id).empty()) { - continue; /* We only focus on switching points containing internal drivers */ + if (clk_ntwk + .spine_switch_point_internal_drivers(ispine, switch_point_id) + .empty()) { + continue; /* We only focus on switching points containing internal + drivers */ } size_t curr_edge_count = edge_count; /* Get the rr node of destination spine */ @@ -680,12 +681,16 @@ static int add_rr_graph_opin2clk_edges(RRGraphBuilder& rr_graph_builder, size_t& /* Walk through each qualified OPIN, build edges */ vtr::Point src_coord = clk_ntwk.spine_switch_point(ispine, switch_point_id); - std::vector int_driver_ids = clk_ntwk.spine_switch_point_internal_drivers(ispine, switch_point_id); - for (RRNodeId src_node : find_clock_opin2track_node(grids, rr_graph_view, layer, src_coord, clk_ntwk, int_driver_ids)) { + std::vector int_driver_ids = + clk_ntwk.spine_switch_point_internal_drivers(ispine, + switch_point_id); + for (RRNodeId src_node : find_clock_opin2track_node( + grids, rr_graph_view, layer, src_coord, clk_ntwk, + int_driver_ids)) { /* Create edges */ VTR_ASSERT(rr_graph_view.valid_node(des_node)); - rr_graph_builder.create_edge(src_node, des_node, - clk_ntwk.default_driver_switch(), false); + rr_graph_builder.create_edge( + src_node, des_node, clk_ntwk.default_driver_switch(), false); edge_count++; } VTR_LOGV(verbose, "\tWill add %lu edges to OPINs at (x=%lu, y=%lu)\n", @@ -758,7 +763,9 @@ static void add_rr_graph_clock_edges( } } /* Add edges between OPIN (internal driver) and clock routing tracks */ - add_rr_graph_opin2clk_edges(rr_graph_builder, num_edges_to_create, clk_rr_lookup, rr_graph_view, grids, layer, clk_ntwk, verbose); + add_rr_graph_opin2clk_edges(rr_graph_builder, num_edges_to_create, + clk_rr_lookup, rr_graph_view, grids, layer, + clk_ntwk, verbose); } /******************************************************************** diff --git a/openfpga/src/base/openfpga_read_arch_template.h b/openfpga/src/base/openfpga_read_arch_template.h index 91e25a607..4ee895977 100644 --- a/openfpga/src/base/openfpga_read_arch_template.h +++ b/openfpga/src/base/openfpga_read_arch_template.h @@ -240,8 +240,9 @@ int read_openfpga_clock_arch_template(T& openfpga_context, const Command& cmd, VTR_LOG_ERROR("Link clock network failed!"); return CMD_EXEC_FATAL_ERROR; } - if (CMD_EXEC_SUCCESS != link_clock_network_rr_graph(openfpga_context.mutable_clock_arch(), - g_vpr_ctx.device().rr_graph)) { + if (CMD_EXEC_SUCCESS != + link_clock_network_rr_graph(openfpga_context.mutable_clock_arch(), + g_vpr_ctx.device().rr_graph)) { VTR_LOG_ERROR("Link clock network to routing architecture failed!"); return CMD_EXEC_FATAL_ERROR; } From 2cbb04b90d4e0be272cda002e79130acf0742b4b Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 25 Jun 2024 11:58:05 -0700 Subject: [PATCH 24/86] [test] add a new testcase to validate programmable clock network with internal drivers --- .../regression_test_scripts/basic_reg_test.sh | 1 + .../clk_arch_1clk_1rst_2layer_int_driver.xml | 40 ++++++++++++++ .../config/pin_constraints_reset.xml | 7 +++ .../config/pin_constraints_resetb.xml | 7 +++ .../config/repack_pin_constraints.xml | 4 ++ .../config/task.conf | 53 +++++++++++++++++++ 6 files changed, 112 insertions(+) create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/clk_arch_1clk_1rst_2layer_int_driver.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/pin_constraints_reset.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/pin_constraints_resetb.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/repack_pin_constraints.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/task.conf diff --git a/openfpga_flow/regression_test_scripts/basic_reg_test.sh b/openfpga_flow/regression_test_scripts/basic_reg_test.sh index 0f2e1514e..20b2e3bf0 100755 --- a/openfpga_flow/regression_test_scripts/basic_reg_test.sh +++ b/openfpga_flow/regression_test_scripts/basic_reg_test.sh @@ -233,6 +233,7 @@ run-task basic_tests/clock_network/homo_1clock_2layer $@ run-task basic_tests/clock_network/homo_1clock_2layer_full_tb $@ run-task basic_tests/clock_network/homo_2clock_2layer $@ run-task basic_tests/clock_network/homo_1clock_1_reset_2layer $@ +run-task basic_tests/clock_network/homo_1clock_1_reset_2layer_internal_driver $@ echo -e "Testing configuration chain of a K4N4 FPGA using .blif generated by yosys+verific"; run-task basic_tests/verific_test $@ diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/clk_arch_1clk_1rst_2layer_int_driver.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/clk_arch_1clk_1rst_2layer_int_driver.xml new file mode 100644 index 000000000..78f156469 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/clk_arch_1clk_1rst_2layer_int_driver.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/pin_constraints_reset.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/pin_constraints_reset.xml new file mode 100644 index 000000000..abcf209f6 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/pin_constraints_reset.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/pin_constraints_resetb.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/pin_constraints_resetb.xml new file mode 100644 index 000000000..cdef2ad86 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/pin_constraints_resetb.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/repack_pin_constraints.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/repack_pin_constraints.xml new file mode 100644 index 000000000..06a125111 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/repack_pin_constraints.xml @@ -0,0 +1,4 @@ + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/task.conf b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/task.conf new file mode 100644 index 000000000..6bc568fb0 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/task.conf @@ -0,0 +1,53 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# Configuration file for running experiments +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs +# Each job execute fpga_flow script on combination of architecture & benchmark +# timeout_each_job is timeout for each job +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + +[GENERAL] +run_engine=openfpga_shell +power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml +power_analysis = false +spice_output=false +verilog_output=true +timeout_each_job = 3*60 +fpga_flow=yosys_vpr + +[OpenFPGA_SHELL] +openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_Ntwk1clk1rst2lvl_cc_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml +openfpga_repack_constraints_file=${PATH:TASK_DIR}/config/repack_pin_constraints.xml +openfpga_vpr_device_layout=2x2 +openfpga_vpr_route_chan_width=40 +openfpga_clock_arch_file=${PATH:TASK_DIR}/config/clk_arch_1clk_1rst_2layer_int_driver.xml +openfpga_verilog_testbench_port_mapping=--explicit_port_mapping + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_reset/counter.v +bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_resetb/counter.v + +[SYNTHESIS_PARAM] +# Yosys script parameters +bench_yosys_cell_sim_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/openfpga_dff_sim.v +bench_yosys_dff_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/openfpga_dff_map.v +bench_read_verilog_options_common = -nolatches +bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dff_flow.ys +bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys;${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_rewrite_flow.ys + +bench0_top = counter +bench0_openfpga_pin_constraints_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/pin_constraints_reset.xml +bench0_openfpga_verilog_testbench_port_mapping= + +bench1_top = counter +bench1_openfpga_pin_constraints_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/pin_constraints_resetb.xml +bench1_openfpga_verilog_testbench_port_mapping= + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= +vpr_fpga_verilog_formal_verification_top_netlist= From fbece49047c88a2ca0f64e71b626c8982c6e67b9 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 25 Jun 2024 12:07:19 -0700 Subject: [PATCH 25/86] [core] fixed a bug where unexpected OPINs are added as internal drivers --- openfpga/src/annotation/append_clock_rr_graph.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfpga/src/annotation/append_clock_rr_graph.cpp b/openfpga/src/annotation/append_clock_rr_graph.cpp index 38d06efc6..53cad0453 100644 --- a/openfpga/src/annotation/append_clock_rr_graph.cpp +++ b/openfpga/src/annotation/append_clock_rr_graph.cpp @@ -626,9 +626,9 @@ static std::vector find_clock_opin2track_node( grid_sides[0] = {RIGHT, BOTTOM}; grid_coords[1] = vtr::Point(sb_coord.x() + 1, sb_coord.y() + 1); grid_sides[1] = {LEFT, BOTTOM}; - grid_coords[2] = vtr::Point(sb_coord.x() + 1, sb_coord.y()); + grid_coords[2] = vtr::Point(sb_coord.x(), sb_coord.y()); grid_sides[2] = {RIGHT, TOP}; - grid_coords[3] = vtr::Point(sb_coord.x(), sb_coord.y()); + grid_coords[3] = vtr::Point(sb_coord.x() + 1, sb_coord.y()); grid_sides[3] = {LEFT, TOP}; for (size_t igrid = 0; igrid < 4; igrid++) { vtr::Point grid_coord = grid_coords[igrid]; From 66af73e91e837f83956d5240d29e57e763fb49b9 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 25 Jun 2024 12:24:46 -0700 Subject: [PATCH 26/86] [lib] now accept reset and set in programmable clock network --- .../src/read_xml_tile_annotation.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/libs/libarchopenfpga/src/read_xml_tile_annotation.cpp b/libs/libarchopenfpga/src/read_xml_tile_annotation.cpp index 135e38361..c6ca09012 100644 --- a/libs/libarchopenfpga/src/read_xml_tile_annotation.cpp +++ b/libs/libarchopenfpga/src/read_xml_tile_annotation.cpp @@ -89,14 +89,6 @@ static void read_xml_tile_global_port_annotation( get_attribute(xml_tile, "is_clock", loc_data, pugiutil::ReqOpt::OPTIONAL) .as_bool(false)); - /* Get clock tree attributes if this is a clock */ - if (tile_annotation.global_port_is_clock(tile_global_port_id)) { - tile_annotation.set_global_port_clock_arch_tree_name( - tile_global_port_id, get_attribute(xml_tile, "clock_arch_tree_name", - loc_data, pugiutil::ReqOpt::OPTIONAL) - .as_string()); - } - /* Get is_set attributes */ tile_annotation.set_global_port_is_set( tile_global_port_id, @@ -109,6 +101,16 @@ static void read_xml_tile_global_port_annotation( get_attribute(xml_tile, "is_reset", loc_data, pugiutil::ReqOpt::OPTIONAL) .as_bool(false)); + /* Get clock tree attributes if this is a clock, reset or set */ + if (tile_annotation.global_port_is_clock(tile_global_port_id) + || tile_annotation.global_port_is_reset(tile_global_port_id) + || tile_annotation.global_port_is_set(tile_global_port_id)) { + tile_annotation.set_global_port_clock_arch_tree_name( + tile_global_port_id, get_attribute(xml_tile, "clock_arch_tree_name", + loc_data, pugiutil::ReqOpt::OPTIONAL) + .as_string()); + } + /* Get default_value attributes */ tile_annotation.set_global_port_default_value( tile_global_port_id, From 4640e74e7e6e047d3f3f4eae7117d9ed8447a0ad Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 25 Jun 2024 12:25:16 -0700 Subject: [PATCH 27/86] [core] code format --- libs/libarchopenfpga/src/read_xml_tile_annotation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/libarchopenfpga/src/read_xml_tile_annotation.cpp b/libs/libarchopenfpga/src/read_xml_tile_annotation.cpp index c6ca09012..960f9352d 100644 --- a/libs/libarchopenfpga/src/read_xml_tile_annotation.cpp +++ b/libs/libarchopenfpga/src/read_xml_tile_annotation.cpp @@ -102,9 +102,9 @@ static void read_xml_tile_global_port_annotation( .as_bool(false)); /* Get clock tree attributes if this is a clock, reset or set */ - if (tile_annotation.global_port_is_clock(tile_global_port_id) - || tile_annotation.global_port_is_reset(tile_global_port_id) - || tile_annotation.global_port_is_set(tile_global_port_id)) { + if (tile_annotation.global_port_is_clock(tile_global_port_id) || + tile_annotation.global_port_is_reset(tile_global_port_id) || + tile_annotation.global_port_is_set(tile_global_port_id)) { tile_annotation.set_global_port_clock_arch_tree_name( tile_global_port_id, get_attribute(xml_tile, "clock_arch_tree_name", loc_data, pugiutil::ReqOpt::OPTIONAL) From c99178f350b94e931c6883e3e0dc395d23132b54 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 25 Jun 2024 12:34:52 -0700 Subject: [PATCH 28/86] [test] fixed a bug on pin locations --- openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml b/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml index 19447dd7e..ad21e6f59 100644 --- a/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml +++ b/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml @@ -107,7 +107,12 @@ - + + + + clb.reset clb.clk clb.O[4:7] clb.I[6:11] + clb.O[0:3] clb.I[0:5] + From ec1ad94d4aeee285380ef32fc5f0c149f0ac9b51 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 25 Jun 2024 13:06:47 -0700 Subject: [PATCH 29/86] [doc] add syntax about internal drivers --- .../manual/file_formats/clock_network.rst | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/docs/source/manual/file_formats/clock_network.rst b/docs/source/manual/file_formats/clock_network.rst index fe6d89b79..d998c63a9 100644 --- a/docs/source/manual/file_formats/clock_network.rst +++ b/docs/source/manual/file_formats/clock_network.rst @@ -25,7 +25,9 @@ Using the clock network description language, users can define multiple clock ne - + + + @@ -175,6 +177,33 @@ For example, where clock spine ``spine0`` will drive another clock spine ``spine1`` at (1, 1). +For each switch point, outputs of neighbouring programmable blocks are allowed to drive the spine at next level, through syntax ``internal_driver``. + +.. option:: tile_pin="" + + Define the pin of a programmable block as an internal driver to a clock network. The pin must be a valid pin defined in the VPR architecture description file. + +For example, + +.. code-block:: xml + + + + + + + +where the clock routing can be driven at (x=1,y=1) by the output pins ``O[0:3]`` of tile ``clb`` in a VPR architecture description file: + +.. code-block:: xml + + + + + + + + .. _file_formats_clock_network_tap_point: Tap Point Settings From 381a8cb53548e5c1402d46606d6cf3c22aa1050d Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 26 Jun 2024 15:41:56 -0700 Subject: [PATCH 30/86] [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"; From 3b25e427205d741dc4e3927555d945b5f5c00014 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 26 Jun 2024 15:51:00 -0700 Subject: [PATCH 31/86] [lib] syntax --- .../libclkarchopenfpga/src/base/clock_network.cpp | 15 +++++++-------- libs/libclkarchopenfpga/src/base/clock_network.h | 4 ++-- .../src/io/read_xml_clock_network.cpp | 12 ++++++------ .../src/io/write_xml_clock_network.cpp | 6 +++++- 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index 69fbed21b..6abb021d8 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -703,8 +703,7 @@ ClockInternalDriverId ClockNetwork::add_spine_switch_point_internal_driver( ClockTapId ClockNetwork::add_tree_tap(const ClockTreeId& tree_id, const std::string& from_port, - const std::string& to_port, - const ) { + const std::string& to_port) { VTR_ASSERT(valid_tree_id(tree_id)); /* TODO: Consider find existing tap template and avoid duplication in storage */ ClockTapId tap_id = ClockTapId(tap_ids_.size()); @@ -712,7 +711,7 @@ ClockTapId ClockNetwork::add_tree_tap(const ClockTreeId& tree_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)); + tap_bb_steps_.emplace_back(vtr::Point(0, 0)); tree_taps_[tree_id].push_back(tap_id); return tap_id; } @@ -720,7 +719,7 @@ ClockTapId ClockNetwork::add_tree_tap(const ClockTreeId& tree_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) { + if (bb.xmax() < bb.xmin() || bb.ymax() < bb.ymin()) { 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; } @@ -728,25 +727,25 @@ bool ClockNetwork::set_tap_bounding_box(const ClockTapId& tap_id, const vtr::Rec return true; } -bool ClockNetwork::set_tap_step_x(const ClockTapId& tap_id, const size_t step) { +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); + tap_bb_steps_[tap_id].set_x(step); return true; } -bool ClockNetwork::set_tap_step_y(const ClockTapId& tap_id, const size_t step) { +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); + tap_bb_steps_[tap_id].set_y(step); return true; } diff --git a/libs/libclkarchopenfpga/src/base/clock_network.h b/libs/libclkarchopenfpga/src/base/clock_network.h index f440c397c..e5236ab10 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.h +++ b/libs/libclkarchopenfpga/src/base/clock_network.h @@ -49,7 +49,7 @@ class ClockNetwork { typedef vtr::Range clock_internal_driver_range; /* Type of tap points */ - enum class : unsigned char { + enum class e_tap_type : unsigned char { ALL = 0, SINGLE, REGION, @@ -284,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_; diff --git a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp index 2c8e8fdfe..fe90cd7f0 100644 --- a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp @@ -67,10 +67,10 @@ static void read_xml_clock_tree_tap_type_single(pugi::xml_node& xml_tap, /* 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) + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_X, loc_data, pugiutil::ReqOpt::REQUIRED) .as_int(); size_t tap_y = - get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_Y, loc_data, pugi::ReqOpt::REQUIRED) + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_Y, loc_data, pugiutil::ReqOpt::REQUIRED) .as_int(); clk_ntwk.set_tap_bounding_box(tap_id, vtr::Rect(tap_x, tap_y, tap_x, tap_y)); } @@ -97,16 +97,16 @@ static void read_xml_clock_tree_tap_type_region(pugi::xml_node& xml_tap, /* 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) + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTX, loc_data, pugiutil::ReqOpt::REQUIRED) .as_int(); size_t tap_start_y = - get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTY, loc_data, pugi::ReqOpt::REQUIRED) + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTY, loc_data, pugiutil::ReqOpt::REQUIRED) .as_int(); size_t tap_end_x = - get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDX, loc_data, pugi::ReqOpt::REQUIRED) + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDX, loc_data, pugiutil::ReqOpt::REQUIRED) .as_int(); size_t tap_end_y = - get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDY, loc_data, pugi::ReqOpt::REQUIRED) + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDY, loc_data, pugiutil::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)); diff --git a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp index addb745ed..cdcc12ecf 100644 --- a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp @@ -30,7 +30,7 @@ static int write_xml_clock_tree_taps(std::fstream& fp, fp << "<" << XML_CLOCK_TREE_TAPS_NODE_NAME << ">\n"; /* Depends on the type */ for (ClockTapId tap_id : clk_ntwk.tree_taps(tree_id)) { - switch clk_ntwk.tap_type(tap_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 << ""; @@ -40,6 +40,7 @@ static int write_xml_clock_tree_taps(std::fstream& fp, clk_ntwk.tap_to_port(tap_id).c_str()); fp << "/>" << "\n"; + break; } case ClockNetwork::e_tap_type::SINGLE: { openfpga::write_tab_to_file(fp, 4); @@ -54,6 +55,7 @@ static int write_xml_clock_tree_taps(std::fstream& fp, clk_ntwk.tap_y(tap_id)); fp << "/>" << "\n"; + break; } case ClockNetwork::e_tap_type::REGION: { openfpga::write_tab_to_file(fp, 4); @@ -76,12 +78,14 @@ static int write_xml_clock_tree_taps(std::fstream& fp, clk_ntwk.tap_step_y(tap_id)); fp << "/>" << "\n"; + break; } default: { VTR_LOG_ERROR("Invalid type of tap point!\n"); return 1; } } + } openfpga::write_tab_to_file(fp, 3); fp << "\n"; From 3efa97b84e34d3de6d979f65df9a953f6dd3a59d Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 26 Jun 2024 17:40:11 -0700 Subject: [PATCH 32/86] [core] support coordinate on clock taps --- .../src/base/clock_network.cpp | 58 ++++++++++++++++++- .../src/base/clock_network.h | 4 +- .../src/annotation/append_clock_rr_graph.cpp | 2 +- 3 files changed, 61 insertions(+), 3 deletions(-) diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index 6abb021d8..488deab6e 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -401,12 +401,68 @@ size_t ClockNetwork::tap_step_y(const ClockTapId& tap_id) const { return tap_bb_steps_[tap_id].y(); } +bool ClockNetwork::valid_tap_coord_in_bb(const ClockTapId& tap_id, const vtr::Point& tap_coord) const { + VTR_ASSERT(valid_tap_id(tap_id)); + if (tap_type(tap_id) == ClockNetwork::e_tap_type::ALL) { + return true; + } + if (tap_type(tap_id) == ClockNetwork::e_tap_type::SINGLE && tap_bbs_[tap_id].strictly_contains(tap_coord)) { + return true; + } + if (tap_type(tap_id) == ClockNetwork::e_tap_type::REGION && tap_bbs_[tap_id].strictly_contains(tap_coord)) { + /* Check if steps are considered, coords still matches */ + bool x_in_bb = false; + for (size_t ix = tap_bbs_[tap_id].xmin(); ix < tap_bbs_[tap_id].xmax(); ix = ix + tap_bb_steps_[tap_id].x()) { + if (tap_coord.x() == ix) { + x_in_bb = true; + break; + } + } + /* Early exit */ + if (!x_in_bb) { + return false; + } + bool y_in_bb = false; + for (size_t iy = tap_bbs_[tap_id].ymin(); iy < tap_bbs_[tap_id].ymax(); iy = iy + tap_bb_steps_[tap_id].y()) { + if (tap_coord.y() == iy) { + y_in_bb = true; + break; + } + } + if (y_in_bb && x_in_bb) { + return true; + } + } + return false; +} + std::vector ClockNetwork::tree_flatten_tap_to_ports( - const ClockTreeId& tree_id, const ClockTreePinId& clk_pin_id) const { + const ClockTreeId& tree_id, const ClockTreePinId& clk_pin_id, const vtr::Point& tap_coord) const { VTR_ASSERT(valid_tree_id(tree_id)); std::vector flatten_taps; for (ClockTapId tap_id : tree_taps_[tree_id]) { VTR_ASSERT(valid_tap_id(tap_id)); + /* Filter out unmatched from ports. Expect [clk_pin_id:clk_pin_id] */ + std::string tap_from_port_name = tap_from_ports_[tap_id]; + PortParser from_port_parser(tap_from_port_name); + BasicPort from_port = from_port_parser.port(); + if (!from_port.is_valid()) { + VTR_LOG_ERROR("Invalid from port name '%s' whose index is not valid\n", + tap_from_port_name.c_str()); + exit(1); + } + if (from_port.get_width() != 1) { + VTR_LOG_ERROR("Invalid from port name '%s' whose width is not 1\n", + tap_from_port_name.c_str()); + exit(1); + } + if (from_port.get_lsb() != size_t(clk_pin_id)) { + continue; + } + /* Filter out unmatched coordinates */ + if (!valid_tap_coord_in_bb(tap_id, tap_coord)) { + continue; + } std::string tap_name = tap_to_ports_[tap_id]; StringToken tokenizer(tap_name); std::vector pin_tokens = tokenizer.split("."); diff --git a/libs/libclkarchopenfpga/src/base/clock_network.h b/libs/libclkarchopenfpga/src/base/clock_network.h index e5236ab10..57ed39cb9 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.h +++ b/libs/libclkarchopenfpga/src/base/clock_network.h @@ -164,7 +164,7 @@ class ClockNetwork { * resource graph Note that the clk_pin_id limits only 1 clock to be accessed */ std::vector tree_flatten_tap_to_ports( - const ClockTreeId& tree_id, const ClockTreePinId& clk_pin_id) const; + const ClockTreeId& tree_id, const ClockTreePinId& clk_pin_id, const vtr::Point& tap_coord) 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; @@ -264,6 +264,8 @@ class ClockNetwork { 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; + /* Check if a given coordinate matches the requirements for a tap point */ + bool valid_tap_coord_in_bb(const ClockTapId& tap_id, const vtr::Point& tap_coord) const; private: /* Private mutators */ /* Build internal links between spines under a given tree */ diff --git a/openfpga/src/annotation/append_clock_rr_graph.cpp b/openfpga/src/annotation/append_clock_rr_graph.cpp index 53cad0453..d5f325ca6 100644 --- a/openfpga/src/annotation/append_clock_rr_graph.cpp +++ b/openfpga/src/annotation/append_clock_rr_graph.cpp @@ -400,7 +400,7 @@ static void try_find_and_add_clock_track2ipin_node( t_physical_tile_type_ptr grid_type = grids.get_physical_type( t_physical_tile_loc(grid_coord.x(), grid_coord.y(), layer)); for (std::string tap_pin_name : - clk_ntwk.tree_flatten_taps(clk_tree, clk_pin)) { + clk_ntwk.tree_flatten_tap_to_ports(clk_tree, clk_pin, grid_coord)) { /* tap pin name could be 'io[5:5].a2f[0]' */ int grid_pin_idx = find_physical_tile_pin_index(grid_type, tap_pin_name); if (grid_pin_idx == grid_type->num_pins) { From 576a861b8d04106389eedfbf8551a966a3a77fab Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 26 Jun 2024 17:54:31 -0700 Subject: [PATCH 33/86] [core] now skip routing any unused clock tree. Only connect to desired clock pin at programmable blocks --- openfpga/src/annotation/route_clock_rr_graph.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index d669304c0..1fa47b836 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -94,6 +94,10 @@ static int route_clock_tree_rr_graph( VTR_LOGV(verbose, "Routing spine '%s'...\n", clk_ntwk.spine_name(ispine).c_str()); for (auto ipin : clk_ntwk.pins(clk_tree)) { + /* Do not route unused clock spines */ + if (tree2clk_pin_map.find(ipin) == tree2clk_pin_map.end()) { + continue; + } /* Route the spine from starting point to ending point */ std::vector> spine_coords = clk_ntwk.spine_coordinates(ispine); @@ -165,6 +169,17 @@ static int route_clock_tree_rr_graph( for (RREdgeId edge : rr_graph.edge_range(src_node)) { RRNodeId des_node = rr_graph.edge_sink_node(edge); if (rr_graph.node_type(des_node) == IPIN) { + /* Check if the IPIN is mapped, if not, do not connect */ + /* if the IPIN is mapped, only connect when net mapping is expected */ + if (tree2clk_pin_map.find(ipin) == tree2clk_pin_map.end()) { + continue; + } + if (!vpr_routing_annotation.rr_node_net(des_node)) { + continue; + } + if (vpr_routing_annotation.rr_node_net(des_node) != tree2clk_pin_map.at(ipin)) { + continue; + } VTR_ASSERT(rr_graph.valid_node(src_node)); VTR_ASSERT(rr_graph.valid_node(des_node)); vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, From 59404e5487ad0d76e299436e3c017ff5a05679d5 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 26 Jun 2024 17:55:23 -0700 Subject: [PATCH 34/86] [core] add verbose output --- openfpga/src/annotation/route_clock_rr_graph.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index 1fa47b836..6e237f482 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -96,6 +96,8 @@ static int route_clock_tree_rr_graph( for (auto ipin : clk_ntwk.pins(clk_tree)) { /* Do not route unused clock spines */ if (tree2clk_pin_map.find(ipin) == tree2clk_pin_map.end()) { + VTR_LOGV(verbose, "Skip routing backbone of unused spine '%s'...\n", + clk_ntwk.spine_name(ispine).c_str()); continue; } /* Route the spine from starting point to ending point */ From 59be95b22751a224c85ab85592f942d94bf07c05 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 26 Jun 2024 17:58:26 -0700 Subject: [PATCH 35/86] [core] code format --- .../src/base/clock_network.cpp | 79 ++++++++++++------- .../src/base/clock_network.h | 39 ++++----- .../src/io/read_xml_clock_network.cpp | 71 +++++++++-------- .../src/annotation/route_clock_rr_graph.cpp | 8 +- 4 files changed, 115 insertions(+), 82 deletions(-) diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index 488deab6e..70fd840f6 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -363,7 +363,8 @@ std::string ClockNetwork::tap_to_port(const ClockTapId& tap_id) const { return tap_to_ports_[tap_id]; } -ClockNetwork::e_tap_type ClockNetwork::tap_type(const ClockTapId& tap_id) const { +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_) { @@ -378,56 +379,62 @@ ClockNetwork::e_tap_type ClockNetwork::tap_type(const ClockTapId& tap_id) const 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(); + 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(); + return tap_bbs_[tap_id].ymin(); } -vtr::Rect ClockNetwork::tap_bounding_box(const ClockTapId& tap_id) const { +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]; + 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(); + 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(); + return tap_bb_steps_[tap_id].y(); } -bool ClockNetwork::valid_tap_coord_in_bb(const ClockTapId& tap_id, const vtr::Point& tap_coord) const { +bool ClockNetwork::valid_tap_coord_in_bb( + const ClockTapId& tap_id, const vtr::Point& tap_coord) const { VTR_ASSERT(valid_tap_id(tap_id)); if (tap_type(tap_id) == ClockNetwork::e_tap_type::ALL) { return true; } - if (tap_type(tap_id) == ClockNetwork::e_tap_type::SINGLE && tap_bbs_[tap_id].strictly_contains(tap_coord)) { + if (tap_type(tap_id) == ClockNetwork::e_tap_type::SINGLE && + tap_bbs_[tap_id].strictly_contains(tap_coord)) { return true; } - if (tap_type(tap_id) == ClockNetwork::e_tap_type::REGION && tap_bbs_[tap_id].strictly_contains(tap_coord)) { + if (tap_type(tap_id) == ClockNetwork::e_tap_type::REGION && + tap_bbs_[tap_id].strictly_contains(tap_coord)) { /* Check if steps are considered, coords still matches */ bool x_in_bb = false; - for (size_t ix = tap_bbs_[tap_id].xmin(); ix < tap_bbs_[tap_id].xmax(); ix = ix + tap_bb_steps_[tap_id].x()) { + for (size_t ix = tap_bbs_[tap_id].xmin(); ix < tap_bbs_[tap_id].xmax(); + ix = ix + tap_bb_steps_[tap_id].x()) { if (tap_coord.x() == ix) { x_in_bb = true; break; - } + } } /* Early exit */ if (!x_in_bb) { return false; } bool y_in_bb = false; - for (size_t iy = tap_bbs_[tap_id].ymin(); iy < tap_bbs_[tap_id].ymax(); iy = iy + tap_bb_steps_[tap_id].y()) { + for (size_t iy = tap_bbs_[tap_id].ymin(); iy < tap_bbs_[tap_id].ymax(); + iy = iy + tap_bb_steps_[tap_id].y()) { if (tap_coord.y() == iy) { y_in_bb = true; break; - } + } } if (y_in_bb && x_in_bb) { return true; @@ -437,7 +444,8 @@ bool ClockNetwork::valid_tap_coord_in_bb(const ClockTapId& tap_id, const vtr::Po } std::vector ClockNetwork::tree_flatten_tap_to_ports( - const ClockTreeId& tree_id, const ClockTreePinId& clk_pin_id, const vtr::Point& tap_coord) const { + const ClockTreeId& tree_id, const ClockTreePinId& clk_pin_id, + const vtr::Point& tap_coord) const { VTR_ASSERT(valid_tree_id(tree_id)); std::vector flatten_taps; for (ClockTapId tap_id : tree_taps_[tree_id]) { @@ -459,7 +467,7 @@ std::vector ClockNetwork::tree_flatten_tap_to_ports( if (from_port.get_lsb() != size_t(clk_pin_id)) { continue; } - /* Filter out unmatched coordinates */ + /* Filter out unmatched coordinates */ if (!valid_tap_coord_in_bb(tap_id, tap_coord)) { continue; } @@ -761,7 +769,8 @@ ClockTapId ClockNetwork::add_tree_tap(const ClockTreeId& tree_id, const std::string& from_port, const std::string& to_port) { VTR_ASSERT(valid_tree_id(tree_id)); - /* TODO: Consider find existing tap template and avoid duplication in storage */ + /* 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); @@ -772,34 +781,46 @@ ClockTapId ClockNetwork::add_tree_tap(const ClockTreeId& tree_id, return tap_id; } -bool ClockNetwork::set_tap_bounding_box(const ClockTapId& tap_id, const vtr::Rect& bb) { +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.xmax() < bb.xmin() || bb.ymax() < bb.ymin()) { - 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; + 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) { +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; + VTR_LOG_ERROR( + "Invalid x-direction step (=%lu) for any bounding box! Expect an integer " + ">= 1!\n", + step); + return false; } tap_bb_steps_[tap_id].set_x(step); return true; } -bool ClockNetwork::set_tap_step_y(const ClockTapId& tap_id, const size_t& step) { +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; + VTR_LOG_ERROR( + "Invalid y-direction step (=%lu) for any bounding box! Expect an integer " + ">= 1!\n", + step); + return false; } tap_bb_steps_[tap_id].set_y(step); return true; @@ -957,10 +978,8 @@ 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_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, diff --git a/libs/libclkarchopenfpga/src/base/clock_network.h b/libs/libclkarchopenfpga/src/base/clock_network.h index 57ed39cb9..25042524a 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.h +++ b/libs/libclkarchopenfpga/src/base/clock_network.h @@ -49,12 +49,7 @@ class ClockNetwork { typedef vtr::Range clock_internal_driver_range; /* Type of tap points */ - enum class e_tap_type : unsigned char { - ALL = 0, - SINGLE, - REGION, - NUM_TYPES - }; + enum class e_tap_type : unsigned char { ALL = 0, SINGLE, REGION, NUM_TYPES }; public: /* Constructors */ ClockNetwork(); @@ -148,23 +143,25 @@ class ClockNetwork { /* 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 + * 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; + 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; + 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; + 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_tap_to_ports( - const ClockTreeId& tree_id, const ClockTreePinId& clk_pin_id, const vtr::Point& tap_coord) const; + const ClockTreeId& tree_id, const ClockTreePinId& clk_pin_id, + const vtr::Point& tap_coord) 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; @@ -218,8 +215,11 @@ class ClockNetwork { ClockInternalDriverId add_spine_switch_point_internal_driver( const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id, const std::string& internal_driver_port); - 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); + 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 @@ -265,7 +265,8 @@ class ClockNetwork { /* Show if the tap id is a valid for data queries */ bool valid_tap_id(const ClockTapId& tap_id) const; /* Check if a given coordinate matches the requirements for a tap point */ - bool valid_tap_coord_in_bb(const ClockTapId& tap_id, const vtr::Point& tap_coord) const; + bool valid_tap_coord_in_bb(const ClockTapId& tap_id, + const vtr::Point& tap_coord) const; private: /* Private mutators */ /* Build internal links between spines under a given tree */ @@ -312,8 +313,10 @@ class ClockNetwork { 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 */ + 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 diff --git a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp index fe90cd7f0..492649788 100644 --- a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp @@ -29,8 +29,8 @@ namespace openfpga { // Begin namespace openfpga *******************************************************************/ 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) { + 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"); @@ -48,10 +48,9 @@ static void read_xml_clock_tree_tap_type_all(pugi::xml_node& xml_tap, /******************************************************************** * 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) { +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"); @@ -63,25 +62,26 @@ static void read_xml_clock_tree_tap_type_single(pugi::xml_node& xml_tap, 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); + 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, pugiutil::ReqOpt::REQUIRED) - .as_int(); - size_t tap_y = - get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_Y, loc_data, pugiutil::ReqOpt::REQUIRED) - .as_int(); - clk_ntwk.set_tap_bounding_box(tap_id, vtr::Rect(tap_x, tap_y, tap_x, tap_y)); + size_t tap_x = get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_X, + loc_data, pugiutil::ReqOpt::REQUIRED) + .as_int(); + size_t tap_y = get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_Y, + loc_data, pugiutil::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) { +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"); @@ -93,22 +93,26 @@ static void read_xml_clock_tree_tap_type_region(pugi::xml_node& xml_tap, 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); + 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, pugiutil::ReqOpt::REQUIRED) + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTX, loc_data, + pugiutil::ReqOpt::REQUIRED) .as_int(); size_t tap_start_y = - get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTY, loc_data, pugiutil::ReqOpt::REQUIRED) + get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_STARTY, loc_data, + pugiutil::ReqOpt::REQUIRED) .as_int(); - size_t tap_end_x = - get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDX, loc_data, pugiutil::ReqOpt::REQUIRED) - .as_int(); - size_t tap_end_y = - get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDY, loc_data, pugiutil::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)); + size_t tap_end_x = get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDX, + loc_data, pugiutil::ReqOpt::REQUIRED) + .as_int(); + size_t tap_end_y = get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_ENDY, + loc_data, pugiutil::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 = @@ -129,12 +133,17 @@ static void read_xml_clock_tree_taps(pugi::xml_node& xml_taps, /* Error out if the XML child has an invalid name! */ 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)) { + } 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)) { + } 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_ALL_NODE_NAME, XML_CLOCK_TREE_TAP_REGION_NODE_NAME, XML_CLOCK_TREE_TAP_SINGLE_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/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index 6e237f482..66d9bb810 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -171,15 +171,17 @@ static int route_clock_tree_rr_graph( for (RREdgeId edge : rr_graph.edge_range(src_node)) { RRNodeId des_node = rr_graph.edge_sink_node(edge); if (rr_graph.node_type(des_node) == IPIN) { - /* Check if the IPIN is mapped, if not, do not connect */ - /* if the IPIN is mapped, only connect when net mapping is expected */ + /* Check if the IPIN is mapped, if not, do not connect */ + /* if the IPIN is mapped, only connect when net mapping is + * expected */ if (tree2clk_pin_map.find(ipin) == tree2clk_pin_map.end()) { continue; } if (!vpr_routing_annotation.rr_node_net(des_node)) { continue; } - if (vpr_routing_annotation.rr_node_net(des_node) != tree2clk_pin_map.at(ipin)) { + if (vpr_routing_annotation.rr_node_net(des_node) != + tree2clk_pin_map.at(ipin)) { continue; } VTR_ASSERT(rr_graph.valid_node(src_node)); From cab649893bdc8e10d21410ad612eb24b5a170452 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 26 Jun 2024 18:06:39 -0700 Subject: [PATCH 36/86] [core] update clock architecture --- libs/libclkarchopenfpga/arch/example.xml | 8 ++++---- .../libclkarchopenfpga/arch/example_internal_drivers.xml | 9 +++++---- .../config/clk_arch_1clk_1rst_2layer.xml | 4 ++-- .../config/clk_arch_1clk_1rst_2layer_int_driver.xml | 4 ++-- .../homo_1clock_2layer/config/clk_arch_1clk_2layer.xml | 2 +- .../config/clk_arch_1clk_2layer.xml | 2 +- .../homo_2clock_2layer/config/clk_arch_2clk_2layer.xml | 4 ++-- 7 files changed, 17 insertions(+), 16 deletions(-) diff --git a/libs/libclkarchopenfpga/arch/example.xml b/libs/libclkarchopenfpga/arch/example.xml index ac251bd3c..9cb31bdc6 100644 --- a/libs/libclkarchopenfpga/arch/example.xml +++ b/libs/libclkarchopenfpga/arch/example.xml @@ -17,10 +17,10 @@ - - - - + + + + diff --git a/libs/libclkarchopenfpga/arch/example_internal_drivers.xml b/libs/libclkarchopenfpga/arch/example_internal_drivers.xml index 2b8a5fe0d..7a46a2094 100644 --- a/libs/libclkarchopenfpga/arch/example_internal_drivers.xml +++ b/libs/libclkarchopenfpga/arch/example_internal_drivers.xml @@ -21,10 +21,11 @@ - - - - + + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/clk_arch_1clk_1rst_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/clk_arch_1clk_1rst_2layer.xml index fde2c515a..6c05921c7 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/clk_arch_1clk_1rst_2layer.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/clk_arch_1clk_1rst_2layer.xml @@ -11,7 +11,7 @@ - + @@ -26,7 +26,7 @@ - + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/clk_arch_1clk_1rst_2layer_int_driver.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/clk_arch_1clk_1rst_2layer_int_driver.xml index 78f156469..ed43a26b5 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/clk_arch_1clk_1rst_2layer_int_driver.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/clk_arch_1clk_1rst_2layer_int_driver.xml @@ -19,7 +19,7 @@ - + @@ -34,7 +34,7 @@ - + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer/config/clk_arch_1clk_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer/config/clk_arch_1clk_2layer.xml index 6aaf1b9b4..7a41f1216 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer/config/clk_arch_1clk_2layer.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer/config/clk_arch_1clk_2layer.xml @@ -11,7 +11,7 @@ - + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer_full_tb/config/clk_arch_1clk_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer_full_tb/config/clk_arch_1clk_2layer.xml index 6aaf1b9b4..7a41f1216 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer_full_tb/config/clk_arch_1clk_2layer.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer_full_tb/config/clk_arch_1clk_2layer.xml @@ -11,7 +11,7 @@ - + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/clk_arch_2clk_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/clk_arch_2clk_2layer.xml index fdf1dc149..8c224318c 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/clk_arch_2clk_2layer.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/clk_arch_2clk_2layer.xml @@ -11,8 +11,8 @@ - - + + From d5d9531eec85e5b02e030739c2267b784d74c8ee Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 26 Jun 2024 21:52:45 -0700 Subject: [PATCH 37/86] [core] comment out buggy codes where global net mapping is not annotated in OpenFPGA --- .../src/annotation/route_clock_rr_graph.cpp | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index 66d9bb810..01a7dbf1c 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -175,15 +175,21 @@ static int route_clock_tree_rr_graph( /* if the IPIN is mapped, only connect when net mapping is * expected */ if (tree2clk_pin_map.find(ipin) == tree2clk_pin_map.end()) { + VTR_LOGV(verbose, "Skip routing clock tap of spine '%s' as the tree is not used\n", + clk_ntwk.spine_name(ispine).c_str()); continue; } - if (!vpr_routing_annotation.rr_node_net(des_node)) { - continue; - } - if (vpr_routing_annotation.rr_node_net(des_node) != - tree2clk_pin_map.at(ipin)) { - continue; - } + //if (!vpr_routing_annotation.rr_node_net(des_node)) { + // VTR_LOGV(verbose, "Skip routing clock tap of spine '%s' as the IPIN is not mapped\n", + // clk_ntwk.spine_name(ispine).c_str()); + // continue; + //} + //if (vpr_routing_annotation.rr_node_net(des_node) != + // tree2clk_pin_map.at(ipin)) { + // VTR_LOGV(verbose, "Skip routing clock tap of spine '%s' as the net mapping does not match clock net\n", + // clk_ntwk.spine_name(ispine).c_str()); + // continue; + //} VTR_ASSERT(rr_graph.valid_node(src_node)); VTR_ASSERT(rr_graph.valid_node(des_node)); vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, From 5d0b0b9a8cbc8e32a50ccd064296805b11d69191 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 26 Jun 2024 22:46:12 -0700 Subject: [PATCH 38/86] [core] now global nets mapping are applied to clock routing --- .../annotation/openfpga_annotate_routing.cpp | 44 +++++++++++++++++++ .../annotation/openfpga_annotate_routing.h | 6 +++ .../src/annotation/route_clock_rr_graph.cpp | 29 +++++++----- .../src/annotation/route_clock_rr_graph.h | 1 + .../src/base/openfpga_link_arch_template.h | 1 + 5 files changed, 69 insertions(+), 12 deletions(-) diff --git a/openfpga/src/annotation/openfpga_annotate_routing.cpp b/openfpga/src/annotation/openfpga_annotate_routing.cpp index 780b1d99d..8c19cd2c7 100644 --- a/openfpga/src/annotation/openfpga_annotate_routing.cpp +++ b/openfpga/src/annotation/openfpga_annotate_routing.cpp @@ -8,10 +8,54 @@ #include "old_traceback.h" #include "vtr_assert.h" #include "vtr_log.h" +#include "vtr_time.h" /* begin namespace openfpga */ namespace openfpga { +/******************************************************************** + * Create a mapping between each rr_node and its mapped nets + * - Only applicable to global nets for dedicated clock routing purpose + * - Note that this function is different than annotate_vpr_rr_nodes() + * Please do not annotate global nets in vpr_routing_annotation! + *******************************************************************/ +vtr::vector annotate_rr_node_global_net(const DeviceContext& device_ctx, + const ClusteredNetlist& cluster_nlist, + const PlacementContext& placement_ctx, + const bool& verbose) { + vtr::vector rr_node_nets; + + size_t counter = 0; + vtr::ScopedStartFinishTimer timer("Annotating rr_node with global nets"); + + const auto& rr_graph = device_ctx.rr_graph; + + rr_node_nets.resize(rr_graph.num_nodes(), ClusterNetId::INVALID()); + + size_t layer = 0; + + for (ClusterNetId net_id : cluster_nlist.nets()) { + if (!cluster_nlist.net_is_ignored(net_id)) { + continue; + } + /* Walk through all the sinks */ + for (ClusterPinId pin_id : cluster_nlist.net_pins(net_id)) { + ClusterBlockId block_id = cluster_nlist.pin_block(pin_id); + t_block_loc blk_loc = get_block_loc(block_id, false); + int phy_pin = placement_ctx.physical_pins[pin_id]; + std::vector curr_rr_nodes = rr_graph.node_lookup().find_nodes_at_all_sides(layer, blk_loc.loc.x, blk_loc.loc.y, IPIN, phy_pin); + for (RRNodeId curr_rr_node : curr_rr_nodes) { + rr_node_nets[curr_rr_node] = net_id; + } + } + } + + VTR_LOGV(verbose, "Done with %d nodes mapping\n", counter); + + + return rr_node_nets; +} + /******************************************************************** * Create a mapping between each rr_node and its mapped nets * based on VPR routing results diff --git a/openfpga/src/annotation/openfpga_annotate_routing.h b/openfpga/src/annotation/openfpga_annotate_routing.h index aa79e69d5..2578e86bd 100644 --- a/openfpga/src/annotation/openfpga_annotate_routing.h +++ b/openfpga/src/annotation/openfpga_annotate_routing.h @@ -15,6 +15,12 @@ /* begin namespace openfpga */ namespace openfpga { +vtr::vector annotate_rr_node_global_net(const DeviceContext& device_ctx, + const ClusteredNetlist& cluster_nlist, + const PlacementContext& placement_ctx, + const bool& verbose); + + void annotate_vpr_rr_node_nets(const DeviceContext& device_ctx, const ClusteringContext& clustering_ctx, const RoutingContext& routing_ctx, diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index 01a7dbf1c..77de0175b 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -6,6 +6,7 @@ #include "vtr_geometry.h" #include "vtr_log.h" #include "vtr_time.h" +#include "openfpga_annotate_routing.h" /* begin namespace openfpga */ namespace openfpga { @@ -87,6 +88,7 @@ static int build_clock_tree_net_map( static int route_clock_tree_rr_graph( VprRoutingAnnotation& vpr_routing_annotation, const RRGraphView& rr_graph, const RRClockSpatialLookup& clk_rr_lookup, + const vtr::vector& rr_node_gnets, const std::map& tree2clk_pin_map, const ClockNetwork& clk_ntwk, const ClockTreeId& clk_tree, const bool& verbose) { @@ -179,17 +181,16 @@ static int route_clock_tree_rr_graph( clk_ntwk.spine_name(ispine).c_str()); continue; } - //if (!vpr_routing_annotation.rr_node_net(des_node)) { - // VTR_LOGV(verbose, "Skip routing clock tap of spine '%s' as the IPIN is not mapped\n", - // clk_ntwk.spine_name(ispine).c_str()); - // continue; - //} - //if (vpr_routing_annotation.rr_node_net(des_node) != - // tree2clk_pin_map.at(ipin)) { - // VTR_LOGV(verbose, "Skip routing clock tap of spine '%s' as the net mapping does not match clock net\n", - // clk_ntwk.spine_name(ispine).c_str()); - // continue; - //} + if (!rr_node_gnets[des_node]) { + VTR_LOGV(verbose, "Skip routing clock tap of spine '%s' as the IPIN is not mapped\n", + clk_ntwk.spine_name(ispine).c_str()); + continue; + } + if (rr_node_gnets[des_node] != tree2clk_pin_map.at(ipin)) { + VTR_LOGV(verbose, "Skip routing clock tap of spine '%s' as the net mapping does not match clock net\n", + clk_ntwk.spine_name(ispine).c_str()); + continue; + } VTR_ASSERT(rr_graph.valid_node(src_node)); VTR_ASSERT(rr_graph.valid_node(des_node)); vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, @@ -219,6 +220,7 @@ int route_clock_rr_graph(VprRoutingAnnotation& vpr_routing_annotation, const DeviceContext& vpr_device_ctx, const AtomContext& atom_ctx, const ClusteredNetlist& cluster_nlist, + const PlacementContext& vpr_place_ctx, const VprNetlistAnnotation& netlist_annotation, const RRClockSpatialLookup& clk_rr_lookup, const ClockNetwork& clk_ntwk, @@ -253,6 +255,9 @@ int route_clock_rr_graph(VprRoutingAnnotation& vpr_routing_annotation, return CMD_EXEC_FATAL_ERROR; } + /* Build rr_node-to-net mapping for global nets */ + vtr::vector rr_node_gnets = annotate_rr_node_global_net(vpr_device_ctx, cluster_nlist, vpr_place_ctx, verbose); + /* Route spines one by one */ for (auto itree : clk_ntwk.trees()) { VTR_LOGV(verbose, "Build clock name to clock tree '%s' pin mapping...\n", @@ -269,7 +274,7 @@ int route_clock_rr_graph(VprRoutingAnnotation& vpr_routing_annotation, VTR_LOGV(verbose, "Routing clock tree '%s'...\n", clk_ntwk.tree_name(itree).c_str()); status = route_clock_tree_rr_graph( - vpr_routing_annotation, vpr_device_ctx.rr_graph, clk_rr_lookup, + vpr_routing_annotation, vpr_device_ctx.rr_graph, clk_rr_lookup, rr_node_gnets, tree2clk_pin_map, clk_ntwk, itree, verbose); if (status == CMD_EXEC_FATAL_ERROR) { return status; diff --git a/openfpga/src/annotation/route_clock_rr_graph.h b/openfpga/src/annotation/route_clock_rr_graph.h index 6a1b2cad4..e12767e9b 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.h +++ b/openfpga/src/annotation/route_clock_rr_graph.h @@ -22,6 +22,7 @@ int route_clock_rr_graph(VprRoutingAnnotation& vpr_routing_annotation, const DeviceContext& vpr_device_ctx, const AtomContext& atom_ctx, const ClusteredNetlist& cluster_nlist, + const PlacementContext& vpr_place_ctx, const VprNetlistAnnotation& netlist_annotation, const RRClockSpatialLookup& clk_rr_lookup, const ClockNetwork& clk_ntwk, diff --git a/openfpga/src/base/openfpga_link_arch_template.h b/openfpga/src/base/openfpga_link_arch_template.h index cb16de224..319c89086 100644 --- a/openfpga/src/base/openfpga_link_arch_template.h +++ b/openfpga/src/base/openfpga_link_arch_template.h @@ -231,6 +231,7 @@ int route_clock_rr_graph_template(T& openfpga_ctx, const Command& cmd, return route_clock_rr_graph( openfpga_ctx.mutable_vpr_routing_annotation(), g_vpr_ctx.device(), g_vpr_ctx.atom(), g_vpr_ctx.clustering().clb_nlist, + g_vpr_ctx.placement(), openfpga_ctx.vpr_netlist_annotation(), openfpga_ctx.clock_rr_lookup(), openfpga_ctx.clock_arch(), pin_constraints, cmd_context.option_enable(cmd, opt_verbose)); From ac1ad527951b8e7dee1e05869812dbe160245152 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 26 Jun 2024 22:47:29 -0700 Subject: [PATCH 39/86] [core] code format --- .../annotation/openfpga_annotate_routing.cpp | 18 ++++----- .../annotation/openfpga_annotate_routing.h | 8 ++-- .../src/annotation/route_clock_rr_graph.cpp | 39 +++++++++++-------- .../src/annotation/route_clock_rr_graph.h | 17 ++++---- .../src/base/openfpga_link_arch_template.h | 3 +- 5 files changed, 42 insertions(+), 43 deletions(-) diff --git a/openfpga/src/annotation/openfpga_annotate_routing.cpp b/openfpga/src/annotation/openfpga_annotate_routing.cpp index 8c19cd2c7..ad84d86e2 100644 --- a/openfpga/src/annotation/openfpga_annotate_routing.cpp +++ b/openfpga/src/annotation/openfpga_annotate_routing.cpp @@ -19,10 +19,9 @@ namespace openfpga { * - Note that this function is different than annotate_vpr_rr_nodes() * Please do not annotate global nets in vpr_routing_annotation! *******************************************************************/ -vtr::vector annotate_rr_node_global_net(const DeviceContext& device_ctx, - const ClusteredNetlist& cluster_nlist, - const PlacementContext& placement_ctx, - const bool& verbose) { +vtr::vector annotate_rr_node_global_net( + const DeviceContext& device_ctx, const ClusteredNetlist& cluster_nlist, + const PlacementContext& placement_ctx, const bool& verbose) { vtr::vector rr_node_nets; size_t counter = 0; @@ -31,7 +30,7 @@ vtr::vector annotate_rr_node_global_net(const DeviceCont const auto& rr_graph = device_ctx.rr_graph; rr_node_nets.resize(rr_graph.num_nodes(), ClusterNetId::INVALID()); - + size_t layer = 0; for (ClusterNetId net_id : cluster_nlist.nets()) { @@ -39,11 +38,13 @@ vtr::vector annotate_rr_node_global_net(const DeviceCont continue; } /* Walk through all the sinks */ - for (ClusterPinId pin_id : cluster_nlist.net_pins(net_id)) { + for (ClusterPinId pin_id : cluster_nlist.net_pins(net_id)) { ClusterBlockId block_id = cluster_nlist.pin_block(pin_id); - t_block_loc blk_loc = get_block_loc(block_id, false); + t_block_loc blk_loc = get_block_loc(block_id, false); int phy_pin = placement_ctx.physical_pins[pin_id]; - std::vector curr_rr_nodes = rr_graph.node_lookup().find_nodes_at_all_sides(layer, blk_loc.loc.x, blk_loc.loc.y, IPIN, phy_pin); + std::vector curr_rr_nodes = + rr_graph.node_lookup().find_nodes_at_all_sides( + layer, blk_loc.loc.x, blk_loc.loc.y, IPIN, phy_pin); for (RRNodeId curr_rr_node : curr_rr_nodes) { rr_node_nets[curr_rr_node] = net_id; } @@ -52,7 +53,6 @@ vtr::vector annotate_rr_node_global_net(const DeviceCont VTR_LOGV(verbose, "Done with %d nodes mapping\n", counter); - return rr_node_nets; } diff --git a/openfpga/src/annotation/openfpga_annotate_routing.h b/openfpga/src/annotation/openfpga_annotate_routing.h index 2578e86bd..dc5d28db3 100644 --- a/openfpga/src/annotation/openfpga_annotate_routing.h +++ b/openfpga/src/annotation/openfpga_annotate_routing.h @@ -15,11 +15,9 @@ /* begin namespace openfpga */ namespace openfpga { -vtr::vector annotate_rr_node_global_net(const DeviceContext& device_ctx, - const ClusteredNetlist& cluster_nlist, - const PlacementContext& placement_ctx, - const bool& verbose); - +vtr::vector annotate_rr_node_global_net( + const DeviceContext& device_ctx, const ClusteredNetlist& cluster_nlist, + const PlacementContext& placement_ctx, const bool& verbose); void annotate_vpr_rr_node_nets(const DeviceContext& device_ctx, const ClusteringContext& clustering_ctx, diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index 77de0175b..327a51f40 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -1,12 +1,12 @@ #include "route_clock_rr_graph.h" #include "command_exit_codes.h" +#include "openfpga_annotate_routing.h" #include "openfpga_atom_netlist_utils.h" #include "vtr_assert.h" #include "vtr_geometry.h" #include "vtr_log.h" #include "vtr_time.h" -#include "openfpga_annotate_routing.h" /* begin namespace openfpga */ namespace openfpga { @@ -177,17 +177,23 @@ static int route_clock_tree_rr_graph( /* if the IPIN is mapped, only connect when net mapping is * expected */ if (tree2clk_pin_map.find(ipin) == tree2clk_pin_map.end()) { - VTR_LOGV(verbose, "Skip routing clock tap of spine '%s' as the tree is not used\n", + VTR_LOGV(verbose, + "Skip routing clock tap of spine '%s' as the tree is " + "not used\n", clk_ntwk.spine_name(ispine).c_str()); continue; } if (!rr_node_gnets[des_node]) { - VTR_LOGV(verbose, "Skip routing clock tap of spine '%s' as the IPIN is not mapped\n", + VTR_LOGV(verbose, + "Skip routing clock tap of spine '%s' as the IPIN is " + "not mapped\n", clk_ntwk.spine_name(ispine).c_str()); continue; } if (rr_node_gnets[des_node] != tree2clk_pin_map.at(ipin)) { - VTR_LOGV(verbose, "Skip routing clock tap of spine '%s' as the net mapping does not match clock net\n", + VTR_LOGV(verbose, + "Skip routing clock tap of spine '%s' as the net " + "mapping does not match clock net\n", clk_ntwk.spine_name(ispine).c_str()); continue; } @@ -216,16 +222,13 @@ static int route_clock_tree_rr_graph( * - configure the routing annotation w.r.t. the clock node connections * - quick check to ensure routing is valid *******************************************************************/ -int route_clock_rr_graph(VprRoutingAnnotation& vpr_routing_annotation, - const DeviceContext& vpr_device_ctx, - const AtomContext& atom_ctx, - const ClusteredNetlist& cluster_nlist, - const PlacementContext& vpr_place_ctx, - const VprNetlistAnnotation& netlist_annotation, - const RRClockSpatialLookup& clk_rr_lookup, - const ClockNetwork& clk_ntwk, - const PinConstraints& pin_constraints, - const bool& verbose) { +int route_clock_rr_graph( + VprRoutingAnnotation& vpr_routing_annotation, + const DeviceContext& vpr_device_ctx, const AtomContext& atom_ctx, + const ClusteredNetlist& cluster_nlist, const PlacementContext& vpr_place_ctx, + const VprNetlistAnnotation& netlist_annotation, + const RRClockSpatialLookup& clk_rr_lookup, const ClockNetwork& clk_ntwk, + const PinConstraints& pin_constraints, const bool& verbose) { vtr::ScopedStartFinishTimer timer( "Route programmable clock network based on routing resource graph"); @@ -256,7 +259,9 @@ int route_clock_rr_graph(VprRoutingAnnotation& vpr_routing_annotation, } /* Build rr_node-to-net mapping for global nets */ - vtr::vector rr_node_gnets = annotate_rr_node_global_net(vpr_device_ctx, cluster_nlist, vpr_place_ctx, verbose); + vtr::vector rr_node_gnets = + annotate_rr_node_global_net(vpr_device_ctx, cluster_nlist, vpr_place_ctx, + verbose); /* Route spines one by one */ for (auto itree : clk_ntwk.trees()) { @@ -274,8 +279,8 @@ int route_clock_rr_graph(VprRoutingAnnotation& vpr_routing_annotation, VTR_LOGV(verbose, "Routing clock tree '%s'...\n", clk_ntwk.tree_name(itree).c_str()); status = route_clock_tree_rr_graph( - vpr_routing_annotation, vpr_device_ctx.rr_graph, clk_rr_lookup, rr_node_gnets, - tree2clk_pin_map, clk_ntwk, itree, verbose); + vpr_routing_annotation, vpr_device_ctx.rr_graph, clk_rr_lookup, + rr_node_gnets, tree2clk_pin_map, clk_ntwk, itree, verbose); if (status == CMD_EXEC_FATAL_ERROR) { return status; } diff --git a/openfpga/src/annotation/route_clock_rr_graph.h b/openfpga/src/annotation/route_clock_rr_graph.h index e12767e9b..f0d60642c 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.h +++ b/openfpga/src/annotation/route_clock_rr_graph.h @@ -18,16 +18,13 @@ /* begin namespace openfpga */ namespace openfpga { -int route_clock_rr_graph(VprRoutingAnnotation& vpr_routing_annotation, - const DeviceContext& vpr_device_ctx, - const AtomContext& atom_ctx, - const ClusteredNetlist& cluster_nlist, - const PlacementContext& vpr_place_ctx, - const VprNetlistAnnotation& netlist_annotation, - const RRClockSpatialLookup& clk_rr_lookup, - const ClockNetwork& clk_ntwk, - const PinConstraints& pin_constraints, - const bool& verbose); +int route_clock_rr_graph( + VprRoutingAnnotation& vpr_routing_annotation, + const DeviceContext& vpr_device_ctx, const AtomContext& atom_ctx, + const ClusteredNetlist& cluster_nlist, const PlacementContext& vpr_place_ctx, + const VprNetlistAnnotation& netlist_annotation, + const RRClockSpatialLookup& clk_rr_lookup, const ClockNetwork& clk_ntwk, + const PinConstraints& pin_constraints, const bool& verbose); } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_link_arch_template.h b/openfpga/src/base/openfpga_link_arch_template.h index 319c89086..2e742742a 100644 --- a/openfpga/src/base/openfpga_link_arch_template.h +++ b/openfpga/src/base/openfpga_link_arch_template.h @@ -230,8 +230,7 @@ int route_clock_rr_graph_template(T& openfpga_ctx, const Command& cmd, return route_clock_rr_graph( openfpga_ctx.mutable_vpr_routing_annotation(), g_vpr_ctx.device(), - g_vpr_ctx.atom(), g_vpr_ctx.clustering().clb_nlist, - g_vpr_ctx.placement(), + g_vpr_ctx.atom(), g_vpr_ctx.clustering().clb_nlist, g_vpr_ctx.placement(), openfpga_ctx.vpr_netlist_annotation(), openfpga_ctx.clock_rr_lookup(), openfpga_ctx.clock_arch(), pin_constraints, cmd_context.option_enable(cmd, opt_verbose)); From 9ce552495ac92790686ce5959cee8ded7f682f4a Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 27 Jun 2024 10:17:08 -0700 Subject: [PATCH 40/86] [core] now internal drivers can be routed in dedicated clock network --- .../src/annotation/route_clock_rr_graph.cpp | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index 327a51f40..9fe0a4ad6 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -147,6 +147,34 @@ static int route_clock_tree_rr_graph( des_spine_level, ipin, des_spine_direction); VTR_ASSERT(rr_graph.valid_node(src_node)); VTR_ASSERT(rr_graph.valid_node(des_node)); + /* Internal drivers may appear at the switch point. Check if there are any defined and related rr_node found as incoming edges. If the global net is mapped to the internal driver, use it as the previous node */ + size_t use_int_driver = 0; + for (!spine_switch_point_internal_drivers(ispine, switch_point_id).empty() && tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) { + for (RREdgeId cand_edge : rr_graph.node_in_edges(des_node)) { + RRNodeId opin_node = rr_graph.edge_src_node(cand_edge); + if (OPIN != rr_graph.node_type(opin_node)) { + continue; + } + if (rr_node_gnets[opin_node] != tree2clk_pin_map.at(ipin)) { + continue; + } + /* This is the opin node we need, use it as the internal driver */ + vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, + opin_node); + vpr_routing_annotation.set_rr_node_net(opin_node, + tree2clk_pin_map.at(ipin)); + vpr_routing_annotation.set_rr_node_net(des_node, + tree2clk_pin_map.at(ipin)); + use_int_driver++; + } + } + if (use_int_driver > 1) { + VTR_LOG_ERROR("Found %lu internal drivers for the switching point (%lu, %lu) for spine '%s'!\n Expect only 1!\n", use_int_driver, src_coord.x(), src_coord.y(), clk_ntwk.spine_name(ispine).c_str()); + return CMD_EXEC_FATAL_ERROR; + } + if (use_int_driver == 1) { + continue; /* Used internal driver, early pass */ + } vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, src_node); /* It could happen that there is no net mapped some clock pin, skip the From 64a7a4ce26f3980c75a799ef717d41d31133e66b Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 27 Jun 2024 10:19:14 -0700 Subject: [PATCH 41/86] [core] syntax --- openfpga/src/annotation/route_clock_rr_graph.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index 9fe0a4ad6..06d9c1d5a 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -149,7 +149,7 @@ static int route_clock_tree_rr_graph( VTR_ASSERT(rr_graph.valid_node(des_node)); /* Internal drivers may appear at the switch point. Check if there are any defined and related rr_node found as incoming edges. If the global net is mapped to the internal driver, use it as the previous node */ size_t use_int_driver = 0; - for (!spine_switch_point_internal_drivers(ispine, switch_point_id).empty() && tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) { + if (!clk_ntwk.spine_switch_point_internal_drivers(ispine, switch_point_id).empty() && tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) { for (RREdgeId cand_edge : rr_graph.node_in_edges(des_node)) { RRNodeId opin_node = rr_graph.edge_src_node(cand_edge); if (OPIN != rr_graph.node_type(opin_node)) { From 6fceb81110bbd46f176f254258765d48778ba13e Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 27 Jun 2024 10:19:40 -0700 Subject: [PATCH 42/86] [core] code format --- openfpga/src/annotation/route_clock_rr_graph.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index 06d9c1d5a..7a540d040 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -147,9 +147,15 @@ static int route_clock_tree_rr_graph( des_spine_level, ipin, des_spine_direction); VTR_ASSERT(rr_graph.valid_node(src_node)); VTR_ASSERT(rr_graph.valid_node(des_node)); - /* Internal drivers may appear at the switch point. Check if there are any defined and related rr_node found as incoming edges. If the global net is mapped to the internal driver, use it as the previous node */ + /* Internal drivers may appear at the switch point. Check if there are + * any defined and related rr_node found as incoming edges. If the + * global net is mapped to the internal driver, use it as the previous + * node */ size_t use_int_driver = 0; - if (!clk_ntwk.spine_switch_point_internal_drivers(ispine, switch_point_id).empty() && tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) { + if (!clk_ntwk + .spine_switch_point_internal_drivers(ispine, switch_point_id) + .empty() && + tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) { for (RREdgeId cand_edge : rr_graph.node_in_edges(des_node)) { RRNodeId opin_node = rr_graph.edge_src_node(cand_edge); if (OPIN != rr_graph.node_type(opin_node)) { @@ -169,7 +175,11 @@ static int route_clock_tree_rr_graph( } } if (use_int_driver > 1) { - VTR_LOG_ERROR("Found %lu internal drivers for the switching point (%lu, %lu) for spine '%s'!\n Expect only 1!\n", use_int_driver, src_coord.x(), src_coord.y(), clk_ntwk.spine_name(ispine).c_str()); + VTR_LOG_ERROR( + "Found %lu internal drivers for the switching point (%lu, %lu) for " + "spine '%s'!\n Expect only 1!\n", + use_int_driver, src_coord.x(), src_coord.y(), + clk_ntwk.spine_name(ispine).c_str()); return CMD_EXEC_FATAL_ERROR; } if (use_int_driver == 1) { From 3fb891094b4c4b2d491e085bf6e285f1764a145c Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 27 Jun 2024 11:02:37 -0700 Subject: [PATCH 43/86] [doc] add new syntax --- .../manual/file_formats/clock_network.rst | 60 ++++++++++++++++--- 1 file changed, 53 insertions(+), 7 deletions(-) diff --git a/docs/source/manual/file_formats/clock_network.rst b/docs/source/manual/file_formats/clock_network.rst index d998c63a9..da359f400 100644 --- a/docs/source/manual/file_formats/clock_network.rst +++ b/docs/source/manual/file_formats/clock_network.rst @@ -30,7 +30,9 @@ Using the clock network description language, users can define multiple clock ne - + + + @@ -209,23 +211,67 @@ where the clock routing can be driven at (x=1,y=1) by the output pins ``O[0:3]`` Tap Point Settings ^^^^^^^^^^^^^^^^^^ -The following syntax are applicable to the XML definition tagged by ``tap``. +The following syntax are applicable to the XML definition tagged by ``all``, ``region`` and ``single``. Note that a number of tap points can be defined under the node ``taps``. -.. option:: tile_pin="" +.. option:: from_pin="" - Define the pin of a programmable block to be tapped by a clock network. The pin must be a valid pin defined in the VPR architecture description file. + Define the source pin of a programmable block to be tapped by a clock network. The pin must be a valid pin of the global ports defined in the tile_annotation part of OpenFPGA architecture description file. + +.. option:: to_pin="" + + Define the destination pin of a programmable block to be tapped by a clock network. The pin must be a valid pin defined in the VPR architecture description file. .. note:: Only the leaf clock spine (not switch points to drive other clock spine) can tap pins of programmable blocks. +.. note:: Each coordinate must be a valid integer within the device height and width that are defined in VPR architecture!!! + +.. warning:: The following syntax are only applicable to ``single`` tap mode. + +.. option:: x="" + + Define the x coordinate of the tap point, which is applied to the destination pin ``to_pin`` + +.. option:: y="" + + Define the y coordinate of the tap point, which is applied to the destination pin ``to_pin`` + +.. warning:: The following syntax are only applicable to ``region`` tap mode. + +.. option:: start_x="" + + Define the starting x coordinate of the tap region, which is applied to the destination pin ``to_pin`` + +.. option:: start_y="" + + Define the starting y coordinate of the tap region, which is applied to the destination pin ``to_pin`` + +.. option:: end_x="" + + Define the ending x coordinate of the tap region, which is applied to the destination pin ``to_pin`` + +.. option:: end_y="" + + Define the ending y coordinate of the tap region, which is applied to the destination pin ``to_pin`` + +.. option:: repeat_x="" + + Define the repeating factor on x coordinate of the tap region, which is applied to the destination pin ``to_pin`` + +.. option:: repeat_y="" + + Define the repeating factor on y coordinate of the tap region, which is applied to the destination pin ``to_pin`` + For example, .. code-block:: xml - + - + + + @@ -235,7 +281,7 @@ where all the clock spines of the clock network ``clk_tree_0`` tap the clock pin - + From 7892c2340c637782191fbf0b5f793d79f1b87dae Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 27 Jun 2024 12:01:54 -0700 Subject: [PATCH 44/86] [core] add a new option 'disable_unused_trees' to route clock rr graph --- openfpga/src/annotation/route_clock_rr_graph.cpp | 12 +++++++++--- openfpga/src/annotation/route_clock_rr_graph.h | 5 ++++- openfpga/src/base/openfpga_link_arch_template.h | 4 ++++ openfpga/src/base/openfpga_setup_command_template.h | 2 ++ 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index 7a540d040..05aaca922 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -91,13 +91,14 @@ static int route_clock_tree_rr_graph( const vtr::vector& rr_node_gnets, const std::map& tree2clk_pin_map, const ClockNetwork& clk_ntwk, const ClockTreeId& clk_tree, + const bool& disable_unused_trees, const bool& verbose) { for (auto ispine : clk_ntwk.spines(clk_tree)) { VTR_LOGV(verbose, "Routing spine '%s'...\n", clk_ntwk.spine_name(ispine).c_str()); for (auto ipin : clk_ntwk.pins(clk_tree)) { /* Do not route unused clock spines */ - if (tree2clk_pin_map.find(ipin) == tree2clk_pin_map.end()) { + if (disable_unused_trees && tree2clk_pin_map.find(ipin) == tree2clk_pin_map.end()) { VTR_LOGV(verbose, "Skip routing backbone of unused spine '%s'...\n", clk_ntwk.spine_name(ispine).c_str()); continue; @@ -172,6 +173,8 @@ static int route_clock_tree_rr_graph( vpr_routing_annotation.set_rr_node_net(des_node, tree2clk_pin_map.at(ipin)); use_int_driver++; + VTR_LOGV(verbose, "Routing switch points of spine '%s' at the switching point (%lu, %lu) using internal driver\n", + clk_ntwk.spine_name(ispine).c_str(), src_coord.x(), src_coord.y()); } } if (use_int_driver > 1) { @@ -266,7 +269,10 @@ int route_clock_rr_graph( const ClusteredNetlist& cluster_nlist, const PlacementContext& vpr_place_ctx, const VprNetlistAnnotation& netlist_annotation, const RRClockSpatialLookup& clk_rr_lookup, const ClockNetwork& clk_ntwk, - const PinConstraints& pin_constraints, const bool& verbose) { + const PinConstraints& pin_constraints, + const bool& disable_unused_trees, + const bool& disable_unused_spines, + const bool& verbose) { vtr::ScopedStartFinishTimer timer( "Route programmable clock network based on routing resource graph"); @@ -318,7 +324,7 @@ int route_clock_rr_graph( clk_ntwk.tree_name(itree).c_str()); status = route_clock_tree_rr_graph( vpr_routing_annotation, vpr_device_ctx.rr_graph, clk_rr_lookup, - rr_node_gnets, tree2clk_pin_map, clk_ntwk, itree, verbose); + rr_node_gnets, tree2clk_pin_map, clk_ntwk, itree, disable_unused_trees, verbose); if (status == CMD_EXEC_FATAL_ERROR) { return status; } diff --git a/openfpga/src/annotation/route_clock_rr_graph.h b/openfpga/src/annotation/route_clock_rr_graph.h index f0d60642c..13bff0eea 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.h +++ b/openfpga/src/annotation/route_clock_rr_graph.h @@ -24,7 +24,10 @@ int route_clock_rr_graph( const ClusteredNetlist& cluster_nlist, const PlacementContext& vpr_place_ctx, const VprNetlistAnnotation& netlist_annotation, const RRClockSpatialLookup& clk_rr_lookup, const ClockNetwork& clk_ntwk, - const PinConstraints& pin_constraints, const bool& verbose); + const PinConstraints& pin_constraints, + const bool& disable_unused_trees, + const bool& disable_unused_spines, + const bool& verbose); } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_link_arch_template.h b/openfpga/src/base/openfpga_link_arch_template.h index 2e742742a..e0fec4742 100644 --- a/openfpga/src/base/openfpga_link_arch_template.h +++ b/openfpga/src/base/openfpga_link_arch_template.h @@ -219,6 +219,8 @@ int route_clock_rr_graph_template(T& openfpga_ctx, const Command& cmd, /* add an option '--pin_constraints_file in short '-pcf' */ CommandOptionId opt_pcf = cmd.option("pin_constraints_file"); + CommandOptionId opt_disable_unused_trees = cmd.option("disable_unused_trees"); + CommandOptionId opt_disable_unused_spines = cmd.option("disable_unused_spines"); CommandOptionId opt_verbose = cmd.option("verbose"); /* If pin constraints are enabled by command options, read the file */ @@ -233,6 +235,8 @@ int route_clock_rr_graph_template(T& openfpga_ctx, const Command& cmd, g_vpr_ctx.atom(), g_vpr_ctx.clustering().clb_nlist, g_vpr_ctx.placement(), openfpga_ctx.vpr_netlist_annotation(), openfpga_ctx.clock_rr_lookup(), openfpga_ctx.clock_arch(), pin_constraints, + cmd_context.option_enable(cmd, opt_disable_unused_trees), + cmd_context.option_enable(cmd, opt_disable_unused_spines), cmd_context.option_enable(cmd, opt_verbose)); } diff --git a/openfpga/src/base/openfpga_setup_command_template.h b/openfpga/src/base/openfpga_setup_command_template.h index 3d178ee17..169d3cf9a 100644 --- a/openfpga/src/base/openfpga_setup_command_template.h +++ b/openfpga/src/base/openfpga_setup_command_template.h @@ -710,6 +710,8 @@ ShellCommandId add_route_clock_rr_graph_command_template( shell_cmd.set_option_short_name(opt_file, "pcf"); shell_cmd.set_option_require_value(opt_file, openfpga::OPT_STRING); + shell_cmd.add_option("disable_unused_trees", false, "Disable entire clock trees when they are not used by any clock nets. Useful to reduce clock power"); + shell_cmd.add_option("disable_unused_spines", false, "Disable part of the clock tree which are used by clock nets. Useful to reduce clock power"); /* Add an option '--verbose' */ shell_cmd.add_option("verbose", false, "Show verbose outputs"); From e75fd57af26f966c202edbc7c240bd8804f5305b Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 27 Jun 2024 12:39:18 -0700 Subject: [PATCH 45/86] [core] refactor codes --- .../src/annotation/route_clock_rr_graph.cpp | 344 ++++++++++-------- 1 file changed, 202 insertions(+), 142 deletions(-) diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index 05aaca922..3c56b6d79 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -78,6 +78,201 @@ static int build_clock_tree_net_map( return CMD_EXEC_SUCCESS; } +/******************************************************************** + * Route a selected clock spine in a staight line + * - route the spine from the starting point to the ending point + *******************************************************************/ +static int route_straight_spines( + VprRoutingAnnotation& vpr_routing_annotation, const RRGraphView& rr_graph, + const RRClockSpatialLookup& clk_rr_lookup, + const ClockNetwork& clk_ntwk, const ClockTreeId& clk_tree, + const ClockSpineId& ispine, const ClockTreePinId& ipin, + const bool& verbose) { + std::vector> spine_coords = + clk_ntwk.spine_coordinates(ispine); + VTR_LOGV(verbose, "Routing backbone of spine '%s'...\n", + clk_ntwk.spine_name(ispine).c_str()); + for (size_t icoord = 0; icoord < spine_coords.size() - 1; ++icoord) { + vtr::Point src_coord = spine_coords[icoord]; + vtr::Point des_coord = spine_coords[icoord + 1]; + Direction src_spine_direction = clk_ntwk.spine_direction(ispine); + Direction des_spine_direction = clk_ntwk.spine_direction(ispine); + ClockLevelId src_spine_level = clk_ntwk.spine_level(ispine); + ClockLevelId des_spine_level = clk_ntwk.spine_level(ispine); + RRNodeId src_node = + clk_rr_lookup.find_node(src_coord.x(), src_coord.y(), clk_tree, + src_spine_level, ipin, src_spine_direction); + RRNodeId des_node = + clk_rr_lookup.find_node(des_coord.x(), des_coord.y(), clk_tree, + des_spine_level, ipin, des_spine_direction); + VTR_ASSERT(rr_graph.valid_node(src_node)); + VTR_ASSERT(rr_graph.valid_node(des_node)); + vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, + src_node); + } + return CMD_EXEC_SUCCESS; +} + +/******************************************************************** + * Route a switching points between spines + * - connect between two routing tracks (left or right turns) + * - connect internal driver to routing track + *******************************************************************/ +static int route_spine_switch_points( + VprRoutingAnnotation& vpr_routing_annotation, const RRGraphView& rr_graph, + const RRClockSpatialLookup& clk_rr_lookup, + const vtr::vector& rr_node_gnets, + const std::map& tree2clk_pin_map, + const ClockNetwork& clk_ntwk, const ClockTreeId& clk_tree, + const ClockSpineId& ispine, const ClockTreePinId& ipin, + const bool& verbose) { + VTR_LOGV(verbose, "Routing switch points of spine '%s'...\n", + clk_ntwk.spine_name(ispine).c_str()); + for (ClockSwitchPointId switch_point_id : + clk_ntwk.spine_switch_points(ispine)) { + vtr::Point src_coord = + clk_ntwk.spine_switch_point(ispine, switch_point_id); + ClockSpineId des_spine = + clk_ntwk.spine_switch_point_tap(ispine, switch_point_id); + vtr::Point des_coord = clk_ntwk.spine_start_point(des_spine); + Direction src_spine_direction = clk_ntwk.spine_direction(ispine); + Direction des_spine_direction = clk_ntwk.spine_direction(des_spine); + ClockLevelId src_spine_level = clk_ntwk.spine_level(ispine); + ClockLevelId des_spine_level = clk_ntwk.spine_level(des_spine); + RRNodeId src_node = + clk_rr_lookup.find_node(src_coord.x(), src_coord.y(), clk_tree, + src_spine_level, ipin, src_spine_direction); + RRNodeId des_node = + clk_rr_lookup.find_node(des_coord.x(), des_coord.y(), clk_tree, + des_spine_level, ipin, des_spine_direction); + VTR_ASSERT(rr_graph.valid_node(src_node)); + VTR_ASSERT(rr_graph.valid_node(des_node)); + /* Internal drivers may appear at the switch point. Check if there are + * any defined and related rr_node found as incoming edges. If the + * global net is mapped to the internal driver, use it as the previous + * node */ + size_t use_int_driver = 0; + if (!clk_ntwk + .spine_switch_point_internal_drivers(ispine, switch_point_id) + .empty() && + tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) { + for (RREdgeId cand_edge : rr_graph.node_in_edges(des_node)) { + RRNodeId opin_node = rr_graph.edge_src_node(cand_edge); + if (OPIN != rr_graph.node_type(opin_node)) { + continue; + } + if (rr_node_gnets[opin_node] != tree2clk_pin_map.at(ipin)) { + continue; + } + /* This is the opin node we need, use it as the internal driver */ + vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, + opin_node); + vpr_routing_annotation.set_rr_node_net(opin_node, + tree2clk_pin_map.at(ipin)); + vpr_routing_annotation.set_rr_node_net(des_node, + tree2clk_pin_map.at(ipin)); + use_int_driver++; + VTR_LOGV(verbose, "Routing switch points of spine '%s' at the switching point (%lu, %lu) using internal driver\n", + clk_ntwk.spine_name(ispine).c_str(), src_coord.x(), src_coord.y()); + } + } + if (use_int_driver > 1) { + VTR_LOG_ERROR( + "Found %lu internal drivers for the switching point (%lu, %lu) for " + "spine '%s'!\n Expect only 1!\n", + use_int_driver, src_coord.x(), src_coord.y(), + clk_ntwk.spine_name(ispine).c_str()); + return CMD_EXEC_FATAL_ERROR; + } + if (use_int_driver == 1) { + continue; /* Used internal driver, early pass */ + } + vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, + src_node); + /* It could happen that there is no net mapped some clock pin, skip the + * net mapping */ + if (tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) { + vpr_routing_annotation.set_rr_node_net(src_node, + tree2clk_pin_map.at(ipin)); + vpr_routing_annotation.set_rr_node_net(des_node, + tree2clk_pin_map.at(ipin)); + } + } + + return CMD_EXEC_SUCCESS; +} + +/******************************************************************** + * Route a spine to its tap points + * - Only connect to tap points which are mapped by a global net + *******************************************************************/ +static int route_spine_taps( + VprRoutingAnnotation& vpr_routing_annotation, const RRGraphView& rr_graph, + const RRClockSpatialLookup& clk_rr_lookup, + const vtr::vector& rr_node_gnets, + const std::map& tree2clk_pin_map, + const ClockNetwork& clk_ntwk, const ClockTreeId& clk_tree, + const ClockSpineId& ispine, const ClockTreePinId& ipin, + const bool& verbose) { + std::vector> spine_coords = + clk_ntwk.spine_coordinates(ispine); + /* Route the spine-to-IPIN connections (only for the last level) */ + if (clk_ntwk.is_last_level(ispine)) { + VTR_LOGV(verbose, "Routing clock taps of spine '%s'...\n", + clk_ntwk.spine_name(ispine).c_str()); + /* Connect to any fan-out node which is IPIN */ + for (size_t icoord = 0; icoord < spine_coords.size(); ++icoord) { + vtr::Point src_coord = spine_coords[icoord]; + Direction src_spine_direction = clk_ntwk.spine_direction(ispine); + ClockLevelId src_spine_level = clk_ntwk.spine_level(ispine); + RRNodeId src_node = + clk_rr_lookup.find_node(src_coord.x(), src_coord.y(), clk_tree, + src_spine_level, ipin, src_spine_direction); + for (RREdgeId edge : rr_graph.edge_range(src_node)) { + RRNodeId des_node = rr_graph.edge_sink_node(edge); + if (rr_graph.node_type(des_node) == IPIN) { + /* Check if the IPIN is mapped, if not, do not connect */ + /* if the IPIN is mapped, only connect when net mapping is + * expected */ + if (tree2clk_pin_map.find(ipin) == tree2clk_pin_map.end()) { + VTR_LOGV(verbose, + "Skip routing clock tap of spine '%s' as the tree is " + "not used\n", + clk_ntwk.spine_name(ispine).c_str()); + continue; + } + if (!rr_node_gnets[des_node]) { + VTR_LOGV(verbose, + "Skip routing clock tap of spine '%s' as the IPIN is " + "not mapped\n", + clk_ntwk.spine_name(ispine).c_str()); + continue; + } + if (rr_node_gnets[des_node] != tree2clk_pin_map.at(ipin)) { + VTR_LOGV(verbose, + "Skip routing clock tap of spine '%s' as the net " + "mapping does not match clock net\n", + clk_ntwk.spine_name(ispine).c_str()); + continue; + } + VTR_ASSERT(rr_graph.valid_node(src_node)); + VTR_ASSERT(rr_graph.valid_node(des_node)); + vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, + src_node); + if (tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) { + vpr_routing_annotation.set_rr_node_net( + src_node, tree2clk_pin_map.at(ipin)); + vpr_routing_annotation.set_rr_node_net( + des_node, tree2clk_pin_map.at(ipin)); + } + } + } + } + } + + return CMD_EXEC_SUCCESS; +} + /******************************************************************** * Route a clock tree on an existing routing resource graph * The strategy is to route spine one by one @@ -106,151 +301,16 @@ static int route_clock_tree_rr_graph( /* Route the spine from starting point to ending point */ std::vector> spine_coords = clk_ntwk.spine_coordinates(ispine); - VTR_LOGV(verbose, "Routing backbone of spine '%s'...\n", - clk_ntwk.spine_name(ispine).c_str()); - for (size_t icoord = 0; icoord < spine_coords.size() - 1; ++icoord) { - vtr::Point src_coord = spine_coords[icoord]; - vtr::Point des_coord = spine_coords[icoord + 1]; - Direction src_spine_direction = clk_ntwk.spine_direction(ispine); - Direction des_spine_direction = clk_ntwk.spine_direction(ispine); - ClockLevelId src_spine_level = clk_ntwk.spine_level(ispine); - ClockLevelId des_spine_level = clk_ntwk.spine_level(ispine); - RRNodeId src_node = - clk_rr_lookup.find_node(src_coord.x(), src_coord.y(), clk_tree, - src_spine_level, ipin, src_spine_direction); - RRNodeId des_node = - clk_rr_lookup.find_node(des_coord.x(), des_coord.y(), clk_tree, - des_spine_level, ipin, des_spine_direction); - VTR_ASSERT(rr_graph.valid_node(src_node)); - VTR_ASSERT(rr_graph.valid_node(des_node)); - vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, - src_node); + if (CMD_EXEC_SUCCESS != route_straight_spines(vpr_routing_annotation, rr_graph, clk_rr_lookup, clk_ntwk, clk_tree, ispine, ipin, verbose)) { + return CMD_EXEC_FATAL_ERROR; } - /* Route the spine-to-spine switching points */ - VTR_LOGV(verbose, "Routing switch points of spine '%s'...\n", - clk_ntwk.spine_name(ispine).c_str()); - for (ClockSwitchPointId switch_point_id : - clk_ntwk.spine_switch_points(ispine)) { - vtr::Point src_coord = - clk_ntwk.spine_switch_point(ispine, switch_point_id); - ClockSpineId des_spine = - clk_ntwk.spine_switch_point_tap(ispine, switch_point_id); - vtr::Point des_coord = clk_ntwk.spine_start_point(des_spine); - Direction src_spine_direction = clk_ntwk.spine_direction(ispine); - Direction des_spine_direction = clk_ntwk.spine_direction(des_spine); - ClockLevelId src_spine_level = clk_ntwk.spine_level(ispine); - ClockLevelId des_spine_level = clk_ntwk.spine_level(des_spine); - RRNodeId src_node = - clk_rr_lookup.find_node(src_coord.x(), src_coord.y(), clk_tree, - src_spine_level, ipin, src_spine_direction); - RRNodeId des_node = - clk_rr_lookup.find_node(des_coord.x(), des_coord.y(), clk_tree, - des_spine_level, ipin, des_spine_direction); - VTR_ASSERT(rr_graph.valid_node(src_node)); - VTR_ASSERT(rr_graph.valid_node(des_node)); - /* Internal drivers may appear at the switch point. Check if there are - * any defined and related rr_node found as incoming edges. If the - * global net is mapped to the internal driver, use it as the previous - * node */ - size_t use_int_driver = 0; - if (!clk_ntwk - .spine_switch_point_internal_drivers(ispine, switch_point_id) - .empty() && - tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) { - for (RREdgeId cand_edge : rr_graph.node_in_edges(des_node)) { - RRNodeId opin_node = rr_graph.edge_src_node(cand_edge); - if (OPIN != rr_graph.node_type(opin_node)) { - continue; - } - if (rr_node_gnets[opin_node] != tree2clk_pin_map.at(ipin)) { - continue; - } - /* This is the opin node we need, use it as the internal driver */ - vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, - opin_node); - vpr_routing_annotation.set_rr_node_net(opin_node, - tree2clk_pin_map.at(ipin)); - vpr_routing_annotation.set_rr_node_net(des_node, - tree2clk_pin_map.at(ipin)); - use_int_driver++; - VTR_LOGV(verbose, "Routing switch points of spine '%s' at the switching point (%lu, %lu) using internal driver\n", - clk_ntwk.spine_name(ispine).c_str(), src_coord.x(), src_coord.y()); - } - } - if (use_int_driver > 1) { - VTR_LOG_ERROR( - "Found %lu internal drivers for the switching point (%lu, %lu) for " - "spine '%s'!\n Expect only 1!\n", - use_int_driver, src_coord.x(), src_coord.y(), - clk_ntwk.spine_name(ispine).c_str()); - return CMD_EXEC_FATAL_ERROR; - } - if (use_int_driver == 1) { - continue; /* Used internal driver, early pass */ - } - vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, - src_node); - /* It could happen that there is no net mapped some clock pin, skip the - * net mapping */ - if (tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) { - vpr_routing_annotation.set_rr_node_net(src_node, - tree2clk_pin_map.at(ipin)); - vpr_routing_annotation.set_rr_node_net(des_node, - tree2clk_pin_map.at(ipin)); - } + /* Route the opin/spine-to-spine switching points */ + if (CMD_EXEC_SUCCESS != route_spine_switch_points(vpr_routing_annotation, rr_graph, clk_rr_lookup, rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, ispine, ipin, verbose)) { + return CMD_EXEC_FATAL_ERROR; } /* Route the spine-to-IPIN connections (only for the last level) */ - if (clk_ntwk.is_last_level(ispine)) { - VTR_LOGV(verbose, "Routing clock taps of spine '%s'...\n", - clk_ntwk.spine_name(ispine).c_str()); - /* Connect to any fan-out node which is IPIN */ - for (size_t icoord = 0; icoord < spine_coords.size(); ++icoord) { - vtr::Point src_coord = spine_coords[icoord]; - Direction src_spine_direction = clk_ntwk.spine_direction(ispine); - ClockLevelId src_spine_level = clk_ntwk.spine_level(ispine); - RRNodeId src_node = - clk_rr_lookup.find_node(src_coord.x(), src_coord.y(), clk_tree, - src_spine_level, ipin, src_spine_direction); - for (RREdgeId edge : rr_graph.edge_range(src_node)) { - RRNodeId des_node = rr_graph.edge_sink_node(edge); - if (rr_graph.node_type(des_node) == IPIN) { - /* Check if the IPIN is mapped, if not, do not connect */ - /* if the IPIN is mapped, only connect when net mapping is - * expected */ - if (tree2clk_pin_map.find(ipin) == tree2clk_pin_map.end()) { - VTR_LOGV(verbose, - "Skip routing clock tap of spine '%s' as the tree is " - "not used\n", - clk_ntwk.spine_name(ispine).c_str()); - continue; - } - if (!rr_node_gnets[des_node]) { - VTR_LOGV(verbose, - "Skip routing clock tap of spine '%s' as the IPIN is " - "not mapped\n", - clk_ntwk.spine_name(ispine).c_str()); - continue; - } - if (rr_node_gnets[des_node] != tree2clk_pin_map.at(ipin)) { - VTR_LOGV(verbose, - "Skip routing clock tap of spine '%s' as the net " - "mapping does not match clock net\n", - clk_ntwk.spine_name(ispine).c_str()); - continue; - } - VTR_ASSERT(rr_graph.valid_node(src_node)); - VTR_ASSERT(rr_graph.valid_node(des_node)); - vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, - src_node); - if (tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) { - vpr_routing_annotation.set_rr_node_net( - src_node, tree2clk_pin_map.at(ipin)); - vpr_routing_annotation.set_rr_node_net( - des_node, tree2clk_pin_map.at(ipin)); - } - } - } - } + if (CMD_EXEC_SUCCESS != route_spine_taps(vpr_routing_annotation, rr_graph, clk_rr_lookup, rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, ispine, ipin, verbose)) { + return CMD_EXEC_FATAL_ERROR; } } } From 4185235a690915bdbe59c4e5aae2dbc8319dc898 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 27 Jun 2024 15:02:20 -0700 Subject: [PATCH 46/86] [core] now clock routing is based on tree expansion. Unused part can be disconnected --- .../src/base/clock_network.cpp | 14 + .../src/base/clock_network.h | 4 + .../src/annotation/route_clock_rr_graph.cpp | 330 +++++++++++------- 3 files changed, 217 insertions(+), 131 deletions(-) diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index 70fd840f6..a34868be5 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -333,6 +333,20 @@ vtr::Point ClockNetwork::spine_switch_point( return spine_switch_coords_[spine_id][size_t(switch_point_id)]; } +std::vector ClockNetwork::find_spine_switch_points_with_coord( + const ClockSpineId& spine_id, + const vtr::Point& coord) const { + VTR_ASSERT(valid_spine_id(spine_id)); + std::vector ret; + for (size_t i = 0; i < spine_switch_points_[spine_id].size(); ++i) { + if (spine_switch_coords_[spine_id][i] == coord) { + ret.push_back(ClockSwitchPointId(i)); + } + } + + return ret; +} + std::vector ClockNetwork::spine_switch_point_internal_drivers( const ClockSpineId& spine_id, diff --git a/libs/libclkarchopenfpga/src/base/clock_network.h b/libs/libclkarchopenfpga/src/base/clock_network.h index 25042524a..0fc15e471 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.h +++ b/libs/libclkarchopenfpga/src/base/clock_network.h @@ -125,6 +125,10 @@ class ClockNetwork { vtr::Point spine_switch_point( const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id) const; + + /* Find all the switching points at a given coordinate */ + std::vector find_spine_switch_points_with_coord(const ClockSpineId& spine_id, const vtr::Point& coord) const; + std::vector spine_switch_point_internal_drivers( const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id) const; diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index 3c56b6d79..cabb763c6 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -78,126 +78,90 @@ static int build_clock_tree_net_map( return CMD_EXEC_SUCCESS; } -/******************************************************************** - * Route a selected clock spine in a staight line - * - route the spine from the starting point to the ending point - *******************************************************************/ -static int route_straight_spines( - VprRoutingAnnotation& vpr_routing_annotation, const RRGraphView& rr_graph, - const RRClockSpatialLookup& clk_rr_lookup, - const ClockNetwork& clk_ntwk, const ClockTreeId& clk_tree, - const ClockSpineId& ispine, const ClockTreePinId& ipin, - const bool& verbose) { - std::vector> spine_coords = - clk_ntwk.spine_coordinates(ispine); - VTR_LOGV(verbose, "Routing backbone of spine '%s'...\n", - clk_ntwk.spine_name(ispine).c_str()); - for (size_t icoord = 0; icoord < spine_coords.size() - 1; ++icoord) { - vtr::Point src_coord = spine_coords[icoord]; - vtr::Point des_coord = spine_coords[icoord + 1]; - Direction src_spine_direction = clk_ntwk.spine_direction(ispine); - Direction des_spine_direction = clk_ntwk.spine_direction(ispine); - ClockLevelId src_spine_level = clk_ntwk.spine_level(ispine); - ClockLevelId des_spine_level = clk_ntwk.spine_level(ispine); - RRNodeId src_node = - clk_rr_lookup.find_node(src_coord.x(), src_coord.y(), clk_tree, - src_spine_level, ipin, src_spine_direction); - RRNodeId des_node = - clk_rr_lookup.find_node(des_coord.x(), des_coord.y(), clk_tree, - des_spine_level, ipin, des_spine_direction); - VTR_ASSERT(rr_graph.valid_node(src_node)); - VTR_ASSERT(rr_graph.valid_node(des_node)); - vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, - src_node); - } - return CMD_EXEC_SUCCESS; -} - /******************************************************************** * Route a switching points between spines * - connect between two routing tracks (left or right turns) * - connect internal driver to routing track *******************************************************************/ -static int route_spine_switch_points( - VprRoutingAnnotation& vpr_routing_annotation, const RRGraphView& rr_graph, +static int route_clock_spine_switch_point( + VprRoutingAnnotation& vpr_routing_annotation, + const RRGraphView& rr_graph, const RRClockSpatialLookup& clk_rr_lookup, const vtr::vector& rr_node_gnets, const std::map& tree2clk_pin_map, const ClockNetwork& clk_ntwk, const ClockTreeId& clk_tree, const ClockSpineId& ispine, const ClockTreePinId& ipin, + const ClockSwitchPointId& switch_point_id, const bool& verbose) { VTR_LOGV(verbose, "Routing switch points of spine '%s'...\n", clk_ntwk.spine_name(ispine).c_str()); - for (ClockSwitchPointId switch_point_id : - clk_ntwk.spine_switch_points(ispine)) { - vtr::Point src_coord = - clk_ntwk.spine_switch_point(ispine, switch_point_id); - ClockSpineId des_spine = - clk_ntwk.spine_switch_point_tap(ispine, switch_point_id); - vtr::Point des_coord = clk_ntwk.spine_start_point(des_spine); - Direction src_spine_direction = clk_ntwk.spine_direction(ispine); - Direction des_spine_direction = clk_ntwk.spine_direction(des_spine); - ClockLevelId src_spine_level = clk_ntwk.spine_level(ispine); - ClockLevelId des_spine_level = clk_ntwk.spine_level(des_spine); - RRNodeId src_node = - clk_rr_lookup.find_node(src_coord.x(), src_coord.y(), clk_tree, - src_spine_level, ipin, src_spine_direction); - RRNodeId des_node = - clk_rr_lookup.find_node(des_coord.x(), des_coord.y(), clk_tree, - des_spine_level, ipin, des_spine_direction); - VTR_ASSERT(rr_graph.valid_node(src_node)); - VTR_ASSERT(rr_graph.valid_node(des_node)); - /* Internal drivers may appear at the switch point. Check if there are - * any defined and related rr_node found as incoming edges. If the - * global net is mapped to the internal driver, use it as the previous - * node */ - size_t use_int_driver = 0; - if (!clk_ntwk - .spine_switch_point_internal_drivers(ispine, switch_point_id) - .empty() && - tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) { - for (RREdgeId cand_edge : rr_graph.node_in_edges(des_node)) { - RRNodeId opin_node = rr_graph.edge_src_node(cand_edge); - if (OPIN != rr_graph.node_type(opin_node)) { - continue; - } - if (rr_node_gnets[opin_node] != tree2clk_pin_map.at(ipin)) { - continue; - } - /* This is the opin node we need, use it as the internal driver */ - vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, - opin_node); - vpr_routing_annotation.set_rr_node_net(opin_node, - tree2clk_pin_map.at(ipin)); - vpr_routing_annotation.set_rr_node_net(des_node, - tree2clk_pin_map.at(ipin)); - use_int_driver++; - VTR_LOGV(verbose, "Routing switch points of spine '%s' at the switching point (%lu, %lu) using internal driver\n", - clk_ntwk.spine_name(ispine).c_str(), src_coord.x(), src_coord.y()); + vtr::Point src_coord = + clk_ntwk.spine_switch_point(ispine, switch_point_id); + ClockSpineId des_spine = + clk_ntwk.spine_switch_point_tap(ispine, switch_point_id); + vtr::Point des_coord = clk_ntwk.spine_start_point(des_spine); + Direction src_spine_direction = clk_ntwk.spine_direction(ispine); + Direction des_spine_direction = clk_ntwk.spine_direction(des_spine); + ClockLevelId src_spine_level = clk_ntwk.spine_level(ispine); + ClockLevelId des_spine_level = clk_ntwk.spine_level(des_spine); + RRNodeId src_node = + clk_rr_lookup.find_node(src_coord.x(), src_coord.y(), clk_tree, + src_spine_level, ipin, src_spine_direction); + RRNodeId des_node = + clk_rr_lookup.find_node(des_coord.x(), des_coord.y(), clk_tree, + des_spine_level, ipin, des_spine_direction); + VTR_ASSERT(rr_graph.valid_node(src_node)); + VTR_ASSERT(rr_graph.valid_node(des_node)); + /* Internal drivers may appear at the switch point. Check if there are + * any defined and related rr_node found as incoming edges. If the + * global net is mapped to the internal driver, use it as the previous + * node */ + size_t use_int_driver = 0; + if (!clk_ntwk + .spine_switch_point_internal_drivers(ispine, switch_point_id) + .empty() && + tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) { + for (RREdgeId cand_edge : rr_graph.node_in_edges(des_node)) { + RRNodeId opin_node = rr_graph.edge_src_node(cand_edge); + if (OPIN != rr_graph.node_type(opin_node)) { + continue; } - } - if (use_int_driver > 1) { - VTR_LOG_ERROR( - "Found %lu internal drivers for the switching point (%lu, %lu) for " - "spine '%s'!\n Expect only 1!\n", - use_int_driver, src_coord.x(), src_coord.y(), - clk_ntwk.spine_name(ispine).c_str()); - return CMD_EXEC_FATAL_ERROR; - } - if (use_int_driver == 1) { - continue; /* Used internal driver, early pass */ - } - vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, - src_node); - /* It could happen that there is no net mapped some clock pin, skip the - * net mapping */ - if (tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) { - vpr_routing_annotation.set_rr_node_net(src_node, + if (rr_node_gnets[opin_node] != tree2clk_pin_map.at(ipin)) { + continue; + } + /* This is the opin node we need, use it as the internal driver */ + vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, + opin_node); + vpr_routing_annotation.set_rr_node_net(opin_node, tree2clk_pin_map.at(ipin)); vpr_routing_annotation.set_rr_node_net(des_node, tree2clk_pin_map.at(ipin)); + use_int_driver++; + VTR_LOGV(verbose, "Routing switch points of spine '%s' at the switching point (%lu, %lu) using internal driver\n", + clk_ntwk.spine_name(ispine).c_str(), src_coord.x(), src_coord.y()); } } + if (use_int_driver > 1) { + VTR_LOG_ERROR( + "Found %lu internal drivers for the switching point (%lu, %lu) for " + "spine '%s'!\n Expect only 1!\n", + use_int_driver, src_coord.x(), src_coord.y(), + clk_ntwk.spine_name(ispine).c_str()); + return CMD_EXEC_FATAL_ERROR; + } + if (use_int_driver == 1) { + continue; /* Used internal driver, early pass */ + } + vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, + src_node); + /* It could happen that there is no net mapped some clock pin, skip the + * net mapping */ + if (tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) { + vpr_routing_annotation.set_rr_node_net(src_node, + tree2clk_pin_map.at(ipin)); + vpr_routing_annotation.set_rr_node_net(des_node, + tree2clk_pin_map.at(ipin)); + } return CMD_EXEC_SUCCESS; } @@ -207,7 +171,9 @@ static int route_spine_switch_points( * - Only connect to tap points which are mapped by a global net *******************************************************************/ static int route_spine_taps( - VprRoutingAnnotation& vpr_routing_annotation, const RRGraphView& rr_graph, + VprRoutingAnnotation& vpr_routing_annotation, + bool& spine_usage, + const RRGraphView& rr_graph, const RRClockSpatialLookup& clk_rr_lookup, const vtr::vector& rr_node_gnets, const std::map& tree2clk_pin_map, @@ -216,6 +182,7 @@ static int route_spine_taps( const bool& verbose) { std::vector> spine_coords = clk_ntwk.spine_coordinates(ispine); + size_t spine_tap_cnt = 0; /* Route the spine-to-IPIN connections (only for the last level) */ if (clk_ntwk.is_last_level(ispine)) { VTR_LOGV(verbose, "Routing clock taps of spine '%s'...\n", @@ -259,16 +226,127 @@ static int route_spine_taps( VTR_ASSERT(rr_graph.valid_node(des_node)); vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, src_node); - if (tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) { - vpr_routing_annotation.set_rr_node_net( - src_node, tree2clk_pin_map.at(ipin)); - vpr_routing_annotation.set_rr_node_net( - des_node, tree2clk_pin_map.at(ipin)); - } + vpr_routing_annotation.set_rr_node_net( + src_node, tree2clk_pin_map.at(ipin)); + vpr_routing_annotation.set_rr_node_net( + des_node, tree2clk_pin_map.at(ipin)); + /* Increment upon any required tap */ + spine_tap_cnt++; } } } } + if (spine_tap_cnt) { + spine_usage = true; + } + + return CMD_EXEC_SUCCESS; +} + +/******************************************************************** + * Recursively route a clock spine on an existing routing resource graph + * The strategy is to route spine one by one + * - route the spine from the ending point to starting point (straight line) + * - for each stops on the staight line, route the spine-to-spine switching points + * - for each switching point (des_spine_top|bottom), go recursively + * - If the downstream spine at any switching point is not used, disconnect + * - If any stop on the spine (straght line) is not used, disconnect + * - route the spine-to-IPIN connections (only for the last level) + * + * des_spine_top[0...N] + * ^ ^ ^ ^ + * | | | | + * spine_start ---->+---->+---->+---->+->spine_end + * | | | | + * v v v v + * des_spine_bottom[0...N] + * + * <-------------------------------------------- direction to walk through + * + *******************************************************************/ +static int rec_expand_and_route_clock_spine( + VprRoutingAnnotation& vpr_routing_annotation, + bool& spine_usage, + const RRGraphView& rr_graph, + const RRClockSpatialLookup& clk_rr_lookup, + const vtr::vector& rr_node_gnets, + const std::map& tree2clk_pin_map, + const ClockNetwork& clk_ntwk, const ClockTreeId& clk_tree, + const ClockSpineId& curr_spine, const ClockTreePinId& curr_pin, + const bool& disable_unused_spines, + const bool& verbose) { + int status = CMD_EXEC_SUCCESS; + bool curr_spine_usage = false; + std::vector> spine_coords = + clk_ntwk.spine_coordinates(curr_spine); + /* We expand from the the ending point to starting point on the straight line. As such, it is easy to turn off spines by any stop */ + std::reverse(spine_coords.begin(), spine_coords.end()); + /* The spine should go in a straight line, connect all the stops on the line */ + for (size_t icoord = 0; icoord < spine_coords.size() - 1; ++icoord) { + vtr::Point src_coord = spine_coords[icoord + 1]; + vtr::Point des_coord = spine_coords[icoord]; + bool curr_stop_usage = false; + /* Expand on the switching point here */ + for (ClockSwitchPointId switch_point_id : + clk_ntwk.find_spine_switch_points_with_coord(curr_spine, src_coord)) { + ClockSpineId des_spine = + clk_ntwk.spine_switch_point_tap(curr_spine, switch_point_id); + /* Go recursively for the destination spine */ + bool curr_branch_usage = false; + status = rec_expand_and_route_clock_spine(vpr_routing_annotation, curr_branch_usage, rr_graph, clk_rr_lookup, rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, des_spine, curr_pin, verbose); + if (CMD_EXEC_SUCCESS != status) { + return CMD_EXEC_FATAL_ERROR; + } + /* Connect only when the destination spine is used */ + if (disable_unused_spines && !curr_branch_usage) { + VTR_LOGV(verbose, "Disconnect switching from spine '%s' to spine '%s' as downstream is not used\n", + clk_ntwk.spine_name(curr_spine).c_str(), clk_ntwk.spine_name(des_spine).c_str()); + continue; + } + curr_stop_usage = true; + /* Now connect to next spine, internal drivers may join */ + status = route_clock_spine_switch_point(vpr_routing_annotation, rr_graph, clk_rr_lookup, rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, curr_spine, curr_pin, switch_point_id, verbose); + if (CMD_EXEC_SUCCESS != status) { + return CMD_EXEC_FATAL_ERROR; + } + } + if (disable_unused_spines && !curr_stop_usage) { + VTR_LOGV(verbose, "Disconnect backbone of spine '%s' from (x=%lu, y=%lu) to (x=%lu, y=%lu) as downstream is not used\n", + clk_ntwk.spine_name(curr_spine).c_str(), src_coord.x(), src_coord.y(), des_coord.x(), des_coord.y()); + continue; + } + /* Connect only when next stop is used */ + Direction src_spine_direction = clk_ntwk.spine_direction(ispine); + Direction des_spine_direction = clk_ntwk.spine_direction(ispine); + ClockLevelId src_spine_level = clk_ntwk.spine_level(ispine); + ClockLevelId des_spine_level = clk_ntwk.spine_level(ispine); + RRNodeId src_node = + clk_rr_lookup.find_node(src_coord.x(), src_coord.y(), clk_tree, + src_spine_level, ipin, src_spine_direction); + RRNodeId des_node = + clk_rr_lookup.find_node(des_coord.x(), des_coord.y(), clk_tree, + des_spine_level, ipin, des_spine_direction); + VTR_ASSERT(rr_graph.valid_node(src_node)); + VTR_ASSERT(rr_graph.valid_node(des_node)); + VTR_LOGV(verbose, "Routing backbone of spine '%s' from (x=%lu, y=%lu) to (x=%lu, y=%lu)...\n", + clk_ntwk.spine_name(curr_spine).c_str(), src_coord.x(), src_coord.y(), des_coord.x(), des_coord.y()); + vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, + src_node); + curr_spine_usage = true; + } + + bool curr_tap_usage = false; + /* For last level, we just connect tap points */ + status = route_spine_taps(vpr_routing_annotation, curr_tap_usage, rr_graph, clk_rr_lookup, rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, curr_spine, curr_pin, verbose); + if (CMD_EXEC_SUCCESS != status) { + return CMD_EXEC_FATAL_ERROR; + } + if (curr_tap_usage) { + curr_spine_usage = true; + } + + /* Update status */ + spine_usage = curr_spine_usage; return CMD_EXEC_SUCCESS; } @@ -287,29 +365,19 @@ static int route_clock_tree_rr_graph( const std::map& tree2clk_pin_map, const ClockNetwork& clk_ntwk, const ClockTreeId& clk_tree, const bool& disable_unused_trees, + const bool& disable_unused_spines, const bool& verbose) { - for (auto ispine : clk_ntwk.spines(clk_tree)) { - VTR_LOGV(verbose, "Routing spine '%s'...\n", - clk_ntwk.spine_name(ispine).c_str()); - for (auto ipin : clk_ntwk.pins(clk_tree)) { - /* Do not route unused clock spines */ - if (disable_unused_trees && tree2clk_pin_map.find(ipin) == tree2clk_pin_map.end()) { - VTR_LOGV(verbose, "Skip routing backbone of unused spine '%s'...\n", - clk_ntwk.spine_name(ispine).c_str()); - continue; - } - /* Route the spine from starting point to ending point */ - std::vector> spine_coords = - clk_ntwk.spine_coordinates(ispine); - if (CMD_EXEC_SUCCESS != route_straight_spines(vpr_routing_annotation, rr_graph, clk_rr_lookup, clk_ntwk, clk_tree, ispine, ipin, verbose)) { - return CMD_EXEC_FATAL_ERROR; - } - /* Route the opin/spine-to-spine switching points */ - if (CMD_EXEC_SUCCESS != route_spine_switch_points(vpr_routing_annotation, rr_graph, clk_rr_lookup, rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, ispine, ipin, verbose)) { - return CMD_EXEC_FATAL_ERROR; - } - /* Route the spine-to-IPIN connections (only for the last level) */ - if (CMD_EXEC_SUCCESS != route_spine_taps(vpr_routing_annotation, rr_graph, clk_rr_lookup, rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, ispine, ipin, verbose)) { + for (auto ipin : clk_ntwk.pins(clk_tree)) { + /* Do not route unused clock spines */ + if (disable_unused_trees && tree2clk_pin_map.find(ipin) == tree2clk_pin_map.end()) { + VTR_LOGV(verbose, "Skip routing unused tree '%s' pin '%lu'...\n", + clk_ntwk.tree_name(clk_tree).c_str(), size_t(ipin)); + continue; + } + /* Start with the top-level spines. Recursively walk through coordinates and expand on switch points */ + for (auto top_spine : clk_ntwk.tree_top_spine(clk_tree)) { + int status = rec_expand_and_route_clock_spine(vpr_routing_annotation, spine_usage, rr_graph, clk_rr_lookup, rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, top_spine, ipin, verbose); + if (CMD_EXEC_SUCCESS != status) { return CMD_EXEC_FATAL_ERROR; } } @@ -384,7 +452,7 @@ int route_clock_rr_graph( clk_ntwk.tree_name(itree).c_str()); status = route_clock_tree_rr_graph( vpr_routing_annotation, vpr_device_ctx.rr_graph, clk_rr_lookup, - rr_node_gnets, tree2clk_pin_map, clk_ntwk, itree, disable_unused_trees, verbose); + rr_node_gnets, tree2clk_pin_map, clk_ntwk, itree, disable_unused_trees, disable_unused_spines, verbose); if (status == CMD_EXEC_FATAL_ERROR) { return status; } From f4f487099d94db4cf855a20c76051b8e9000e254 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 27 Jun 2024 15:07:48 -0700 Subject: [PATCH 47/86] [core] syntax --- .../src/annotation/route_clock_rr_graph.cpp | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index cabb763c6..433de2c7f 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -150,7 +150,7 @@ static int route_clock_spine_switch_point( return CMD_EXEC_FATAL_ERROR; } if (use_int_driver == 1) { - continue; /* Used internal driver, early pass */ + return CMD_EXEC_SUCCESS; /* Used internal driver, early pass */ } vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, src_node); @@ -293,7 +293,7 @@ static int rec_expand_and_route_clock_spine( clk_ntwk.spine_switch_point_tap(curr_spine, switch_point_id); /* Go recursively for the destination spine */ bool curr_branch_usage = false; - status = rec_expand_and_route_clock_spine(vpr_routing_annotation, curr_branch_usage, rr_graph, clk_rr_lookup, rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, des_spine, curr_pin, verbose); + status = rec_expand_and_route_clock_spine(vpr_routing_annotation, curr_branch_usage, rr_graph, clk_rr_lookup, rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, des_spine, curr_pin, disable_unused_spines, verbose); if (CMD_EXEC_SUCCESS != status) { return CMD_EXEC_FATAL_ERROR; } @@ -316,16 +316,16 @@ static int rec_expand_and_route_clock_spine( continue; } /* Connect only when next stop is used */ - Direction src_spine_direction = clk_ntwk.spine_direction(ispine); - Direction des_spine_direction = clk_ntwk.spine_direction(ispine); - ClockLevelId src_spine_level = clk_ntwk.spine_level(ispine); - ClockLevelId des_spine_level = clk_ntwk.spine_level(ispine); + Direction src_spine_direction = clk_ntwk.spine_direction(curr_spine); + Direction des_spine_direction = clk_ntwk.spine_direction(curr_spine); + ClockLevelId src_spine_level = clk_ntwk.spine_level(curr_spine); + ClockLevelId des_spine_level = clk_ntwk.spine_level(curr_spine); RRNodeId src_node = clk_rr_lookup.find_node(src_coord.x(), src_coord.y(), clk_tree, - src_spine_level, ipin, src_spine_direction); + src_spine_level, curr_pin, src_spine_direction); RRNodeId des_node = clk_rr_lookup.find_node(des_coord.x(), des_coord.y(), clk_tree, - des_spine_level, ipin, des_spine_direction); + des_spine_level, curr_pin, des_spine_direction); VTR_ASSERT(rr_graph.valid_node(src_node)); VTR_ASSERT(rr_graph.valid_node(des_node)); VTR_LOGV(verbose, "Routing backbone of spine '%s' from (x=%lu, y=%lu) to (x=%lu, y=%lu)...\n", @@ -375,12 +375,17 @@ static int route_clock_tree_rr_graph( continue; } /* Start with the top-level spines. Recursively walk through coordinates and expand on switch points */ - for (auto top_spine : clk_ntwk.tree_top_spine(clk_tree)) { - int status = rec_expand_and_route_clock_spine(vpr_routing_annotation, spine_usage, rr_graph, clk_rr_lookup, rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, top_spine, ipin, verbose); + bool tree_usage = false; + for (auto top_spine : clk_ntwk.tree_top_spines(clk_tree)) { + int status = rec_expand_and_route_clock_spine(vpr_routing_annotation, tree_usage, rr_graph, clk_rr_lookup, rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, top_spine, ipin, disable_unused_spines, verbose); if (CMD_EXEC_SUCCESS != status) { return CMD_EXEC_FATAL_ERROR; } } + if (!tree_usage) { + VTR_LOGV(verbose, "Detect unused tree '%s' pin '%lu'...\n", + clk_ntwk.tree_name(clk_tree).c_str(), size_t(ipin)); + } } return CMD_EXEC_SUCCESS; } From 5a7f618f297f7ef5529f39279710e430f4f90a16 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 27 Jun 2024 15:44:17 -0700 Subject: [PATCH 48/86] [core] debugging --- .../src/annotation/route_clock_rr_graph.cpp | 58 +++++++++++-------- 1 file changed, 35 insertions(+), 23 deletions(-) diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index 433de2c7f..d401e3e90 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -137,7 +137,7 @@ static int route_clock_spine_switch_point( vpr_routing_annotation.set_rr_node_net(des_node, tree2clk_pin_map.at(ipin)); use_int_driver++; - VTR_LOGV(verbose, "Routing switch points of spine '%s' at the switching point (%lu, %lu) using internal driver\n", + VTR_LOGV(verbose, "Routed switch points of spine '%s' at the switching point (%lu, %lu) using internal driver\n", clk_ntwk.spine_name(ispine).c_str(), src_coord.x(), src_coord.y()); } } @@ -152,6 +152,9 @@ static int route_clock_spine_switch_point( if (use_int_driver == 1) { return CMD_EXEC_SUCCESS; /* Used internal driver, early pass */ } + VTR_LOGV(verbose, "Routed switch points of spine '%s' from (x=%lu, y=%lu) to spine '%s' at (x=%lu, y=%lu)\n", + clk_ntwk.spine_name(ispine).c_str(), src_coord.x(), src_coord.y(), + clk_ntwk.spine_name(des_spine).c_str(), des_coord.x(), des_coord.y()); vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, src_node); /* It could happen that there is no net mapped some clock pin, skip the @@ -224,6 +227,9 @@ static int route_spine_taps( } VTR_ASSERT(rr_graph.valid_node(src_node)); VTR_ASSERT(rr_graph.valid_node(des_node)); + VTR_LOGV(verbose, + "Routed clock tap of spine '%s'\n", + clk_ntwk.spine_name(ispine).c_str()); vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, src_node); vpr_routing_annotation.set_rr_node_net( @@ -277,18 +283,28 @@ static int rec_expand_and_route_clock_spine( const bool& verbose) { int status = CMD_EXEC_SUCCESS; bool curr_spine_usage = false; + bool curr_tap_usage = false; + /* For last level, we just connect tap points */ + status = route_spine_taps(vpr_routing_annotation, curr_tap_usage, rr_graph, clk_rr_lookup, rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, curr_spine, curr_pin, verbose); + if (CMD_EXEC_SUCCESS != status) { + return CMD_EXEC_FATAL_ERROR; + } + if (curr_tap_usage) { + curr_spine_usage = true; + } + std::vector> spine_coords = clk_ntwk.spine_coordinates(curr_spine); - /* We expand from the the ending point to starting point on the straight line. As such, it is easy to turn off spines by any stop */ - std::reverse(spine_coords.begin(), spine_coords.end()); - /* The spine should go in a straight line, connect all the stops on the line */ - for (size_t icoord = 0; icoord < spine_coords.size() - 1; ++icoord) { - vtr::Point src_coord = spine_coords[icoord + 1]; - vtr::Point des_coord = spine_coords[icoord]; + /* We expand from the the ending point to starting point on the straight line. + * As such, it is easy to turn off spines by any stop. + * The spine should go in a straight line, connect all the stops on the line */ + bool prev_stop_usage = false; + for (size_t icoord = spine_coords.size() - 1; icoord >= 0; --icoord) { + vtr::Point switch_point_coord = spine_coords[icoord]; bool curr_stop_usage = false; /* Expand on the switching point here */ for (ClockSwitchPointId switch_point_id : - clk_ntwk.find_spine_switch_points_with_coord(curr_spine, src_coord)) { + clk_ntwk.find_spine_switch_points_with_coord(curr_spine, switch_point_coord)) { ClockSpineId des_spine = clk_ntwk.spine_switch_point_tap(curr_spine, switch_point_id); /* Go recursively for the destination spine */ @@ -310,12 +326,18 @@ static int rec_expand_and_route_clock_spine( return CMD_EXEC_FATAL_ERROR; } } - if (disable_unused_spines && !curr_stop_usage) { - VTR_LOGV(verbose, "Disconnect backbone of spine '%s' from (x=%lu, y=%lu) to (x=%lu, y=%lu) as downstream is not used\n", - clk_ntwk.spine_name(curr_spine).c_str(), src_coord.x(), src_coord.y(), des_coord.x(), des_coord.y()); + if (disable_unused_spines && !curr_stop_usage && !prev_stop_usage) { + VTR_LOGV(verbose, "Disconnect backbone of spine '%s' at (x=%lu, y=%lu) as downstream is not used\n", + clk_ntwk.spine_name(curr_spine).c_str(), switch_point_coord.x(), switch_point_coord.y()); continue; } + /* Skip the first stop */ + if (icoord == 0) { + continue; + } /* Connect only when next stop is used */ + vtr::Point src_coord = spine_coords[icoord - 1]; + vtr::Point des_coord = spine_coords[icoord]; Direction src_spine_direction = clk_ntwk.spine_direction(curr_spine); Direction des_spine_direction = clk_ntwk.spine_direction(curr_spine); ClockLevelId src_spine_level = clk_ntwk.spine_level(curr_spine); @@ -328,23 +350,13 @@ static int rec_expand_and_route_clock_spine( des_spine_level, curr_pin, des_spine_direction); VTR_ASSERT(rr_graph.valid_node(src_node)); VTR_ASSERT(rr_graph.valid_node(des_node)); - VTR_LOGV(verbose, "Routing backbone of spine '%s' from (x=%lu, y=%lu) to (x=%lu, y=%lu)...\n", + VTR_LOGV(verbose, "Routed backbone of spine '%s' from (x=%lu, y=%lu) to (x=%lu, y=%lu)...\n", clk_ntwk.spine_name(curr_spine).c_str(), src_coord.x(), src_coord.y(), des_coord.x(), des_coord.y()); vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, src_node); + prev_stop_usage = true; curr_spine_usage = true; } - - bool curr_tap_usage = false; - /* For last level, we just connect tap points */ - status = route_spine_taps(vpr_routing_annotation, curr_tap_usage, rr_graph, clk_rr_lookup, rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, curr_spine, curr_pin, verbose); - if (CMD_EXEC_SUCCESS != status) { - return CMD_EXEC_FATAL_ERROR; - } - if (curr_tap_usage) { - curr_spine_usage = true; - } - /* Update status */ spine_usage = curr_spine_usage; From 53ba2f0c295eef7ed15f8215bafe2cccb0bbae76 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 27 Jun 2024 15:53:17 -0700 Subject: [PATCH 49/86] [core] fixed a critical bug where some switching points are missing --- openfpga/src/annotation/route_clock_rr_graph.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index d401e3e90..ad80d520a 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -299,7 +299,8 @@ static int rec_expand_and_route_clock_spine( * As such, it is easy to turn off spines by any stop. * The spine should go in a straight line, connect all the stops on the line */ bool prev_stop_usage = false; - for (size_t icoord = spine_coords.size() - 1; icoord >= 0; --icoord) { + std::reverse(spine_coords.begin(), spine_coords.end()); + for (size_t icoord = 0; icoord < spine_coords.size(); ++icoord) { vtr::Point switch_point_coord = spine_coords[icoord]; bool curr_stop_usage = false; /* Expand on the switching point here */ @@ -332,12 +333,14 @@ static int rec_expand_and_route_clock_spine( continue; } /* Skip the first stop */ - if (icoord == 0) { + if (icoord == spine_coords.size() - 1) { continue; } /* Connect only when next stop is used */ - vtr::Point src_coord = spine_coords[icoord - 1]; + vtr::Point src_coord = spine_coords[icoord + 1]; vtr::Point des_coord = spine_coords[icoord]; + VTR_LOGV(verbose, "(icoord=%lu) Expanding on backbone of spine '%s' from (x=%lu, y=%lu) to (x=%lu, y=%lu)...\n", + icoord, clk_ntwk.spine_name(curr_spine).c_str(), src_coord.x(), src_coord.y(), des_coord.x(), des_coord.y()); Direction src_spine_direction = clk_ntwk.spine_direction(curr_spine); Direction des_spine_direction = clk_ntwk.spine_direction(curr_spine); ClockLevelId src_spine_level = clk_ntwk.spine_level(curr_spine); From f5b6774eb0c1cfba6631730b6961602389869d8f Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 28 Jun 2024 12:21:33 -0700 Subject: [PATCH 50/86] [core] add code comments and fixed some bugs --- .../src/annotation/route_clock_rr_graph.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index ad80d520a..393740309 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -268,6 +268,21 @@ static int route_spine_taps( * des_spine_bottom[0...N] * * <-------------------------------------------- direction to walk through + * + * + * On each stop, we expand the spine to switch points and tap points + * - If the previous stop is used (connection to des_spines are required), then the current stop should be connected to the previous stop + * - If previous stop is not used, while the des_spines are required to connect, then the current stop should be connected to the previous stop + * - Only when previous stops and des_spines are not used, the current stop will be NOT connected to the previous stop + * + * des_spine_top[i] + * ^ + * | + * spine_curr_stop ---->+->spine_prev_stop + * | + * v + * des_spine_bottom[i] + * *******************************************************************/ static int rec_expand_and_route_clock_spine( @@ -303,6 +318,9 @@ static int rec_expand_and_route_clock_spine( for (size_t icoord = 0; icoord < spine_coords.size(); ++icoord) { vtr::Point switch_point_coord = spine_coords[icoord]; bool curr_stop_usage = false; + if (icoord == 0) { + prev_stop_usage = true; /* The first stop is always used */ + } /* Expand on the switching point here */ for (ClockSwitchPointId switch_point_id : clk_ntwk.find_spine_switch_points_with_coord(curr_spine, switch_point_coord)) { From 1094af9f7331e2010ae05d2d3390c97eb86ba3d6 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 28 Jun 2024 12:38:40 -0700 Subject: [PATCH 51/86] [doc] add new options to route clock graph --- .../openfpga_commands/setup_commands.rst | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/docs/source/manual/openfpga_shell/openfpga_commands/setup_commands.rst b/docs/source/manual/openfpga_shell/openfpga_commands/setup_commands.rst index ea2a20723..2bf9e4ccb 100644 --- a/docs/source/manual/openfpga_shell/openfpga_commands/setup_commands.rst +++ b/docs/source/manual/openfpga_shell/openfpga_commands/setup_commands.rst @@ -130,8 +130,17 @@ Clock signals will be auto-detected and routed based on pin constraints which ar .. option:: --pin_constraints_file or -pcf - Specify the *Pin Constraints File* (PCF) when the clock network contains multiple clock pins. For example, ``-pin_constraints_file pin_constraints.xml`` - Strongly recommend for multi-clock network. See detailed file format about :ref:`file_format_pin_constraints_file`. + Specify the *Pin Constraints File* (PCF) when the clock network contains multiple clock pins. For example, ``-pin_constraints_file pin_constraints.xml``. Strongly recommend for multi-clock network. See detailed file format about :ref:`file_format_pin_constraints_file`. + +.. note:: If there is a global net, e.g., ``clk`` or ``reset``, which will be driven by an internal resource, it should also be defined in the PCF file. + + .. option:: --disable_unused_trees + + Disable entire clock trees when they are not used by any clock nets. Useful to reduce clock power + + .. option:: --disable_unused_spines + + Disable part of the clock tree which are used by clock nets. Useful to reduce clock power .. option:: --verbose From ad5795bece97f75ccd9860c8048507d3d7b9d29a Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 28 Jun 2024 13:39:41 -0700 Subject: [PATCH 52/86] [test] add extra options to route clock rr_graph command in examples --- .../example_clkntwk_full_tb_script.openfpga | 2 +- .../example_clkntwk_no_ace_script.openfpga | 2 +- .../openfpga_shell_scripts/example_clkntwk_script.openfpga | 2 +- .../clock_network/homo_1clock_1reset_2layer/config/task.conf | 1 + .../homo_1clock_1reset_2layer_internal_driver/config/task.conf | 1 + .../clock_network/homo_1clock_2layer/config/task.conf | 1 + .../clock_network/homo_1clock_2layer_full_tb/config/task.conf | 1 + .../clock_network/homo_2clock_2layer/config/task.conf | 1 + 8 files changed, 8 insertions(+), 3 deletions(-) diff --git a/openfpga_flow/openfpga_shell_scripts/example_clkntwk_full_tb_script.openfpga b/openfpga_flow/openfpga_shell_scripts/example_clkntwk_full_tb_script.openfpga index 92cd639ca..24821bc91 100644 --- a/openfpga_flow/openfpga_shell_scripts/example_clkntwk_full_tb_script.openfpga +++ b/openfpga_flow/openfpga_shell_scripts/example_clkntwk_full_tb_script.openfpga @@ -22,7 +22,7 @@ append_clock_rr_graph link_openfpga_arch --activity_file ${ACTIVITY_FILE} --sort_gsb_chan_node_in_edges # Route clock based on clock network definition -route_clock_rr_graph +route_clock_rr_graph ${OPENFPGA_ROUTE_CLOCK_OPTIONS} # Check and correct any naming conflicts in the BLIF netlist check_netlist_naming_conflict --fix --report ./netlist_renaming.xml diff --git a/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga b/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga index f62d62ecc..f48be422f 100644 --- a/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga +++ b/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga @@ -22,7 +22,7 @@ append_clock_rr_graph link_openfpga_arch --sort_gsb_chan_node_in_edges # Route clock based on clock network definition -route_clock_rr_graph --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} +route_clock_rr_graph ${OPENFPGA_ROUTE_CLOCK_OPTIONS} --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} # Check and correct any naming conflicts in the BLIF netlist check_netlist_naming_conflict --fix --report ./netlist_renaming.xml diff --git a/openfpga_flow/openfpga_shell_scripts/example_clkntwk_script.openfpga b/openfpga_flow/openfpga_shell_scripts/example_clkntwk_script.openfpga index 83cc44860..4d9b21770 100644 --- a/openfpga_flow/openfpga_shell_scripts/example_clkntwk_script.openfpga +++ b/openfpga_flow/openfpga_shell_scripts/example_clkntwk_script.openfpga @@ -22,7 +22,7 @@ append_clock_rr_graph link_openfpga_arch --activity_file ${ACTIVITY_FILE} --sort_gsb_chan_node_in_edges # Route clock based on clock network definition -route_clock_rr_graph --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} +route_clock_rr_graph ${OPENFPGA_ROUTE_CLOCK_OPTIONS} --pin_constraints_file ${OPENFPGA_PIN_CONSTRAINTS_FILE} # Check and correct any naming conflicts in the BLIF netlist check_netlist_naming_conflict --fix --report ./netlist_renaming.xml diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/task.conf b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/task.conf index d47ef31c7..e6204e15a 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/task.conf +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/task.conf @@ -24,6 +24,7 @@ openfpga_vpr_device_layout=2x2 openfpga_vpr_route_chan_width=40 openfpga_clock_arch_file=${PATH:TASK_DIR}/config/clk_arch_1clk_1rst_2layer.xml openfpga_verilog_testbench_port_mapping=--explicit_port_mapping +openfpga_route_clock_options= [ARCHITECTURES] arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/task.conf b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/task.conf index 6bc568fb0..a88b6c9b1 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/task.conf +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/task.conf @@ -24,6 +24,7 @@ openfpga_vpr_device_layout=2x2 openfpga_vpr_route_chan_width=40 openfpga_clock_arch_file=${PATH:TASK_DIR}/config/clk_arch_1clk_1rst_2layer_int_driver.xml openfpga_verilog_testbench_port_mapping=--explicit_port_mapping +openfpga_route_clock_options= [ARCHITECTURES] arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer/config/task.conf b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer/config/task.conf index b05af260f..295943e3e 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer/config/task.conf +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer/config/task.conf @@ -24,6 +24,7 @@ openfpga_vpr_device_layout=2x2 openfpga_vpr_route_chan_width=24 openfpga_repack_constraints_file=${PATH:TASK_DIR}/config/dummy_repack_constraints.xml openfpga_pin_constraints_file=${PATH:TASK_DIR}/config/dummy_pin_constraints.xml +openfpga_route_clock_options= [ARCHITECTURES] arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_Ntwk1clk2lvl_40nm.xml diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer_full_tb/config/task.conf b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer_full_tb/config/task.conf index ef0ce93fd..f42445c51 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer_full_tb/config/task.conf +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer_full_tb/config/task.conf @@ -22,6 +22,7 @@ openfpga_clock_arch_file=${PATH:TASK_DIR}/config/clk_arch_1clk_2layer.xml openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml openfpga_vpr_device_layout=2x2 openfpga_vpr_route_chan_width=24 +openfpga_route_clock_options= [ARCHITECTURES] arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_Ntwk1clk2lvl_40nm.xml diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/task.conf b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/task.conf index 190ff11e0..d75606c31 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/task.conf +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/task.conf @@ -24,6 +24,7 @@ openfpga_vpr_device_layout=2x2 openfpga_vpr_route_chan_width=24 openfpga_repack_constraints_file=${PATH:TASK_DIR}/config/repack_constraints.xml openfpga_pin_constraints_file=${PATH:TASK_DIR}/config/pin_constraints.xml +openfpga_route_clock_options= [ARCHITECTURES] arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_Ntwk2clk2lvl_40nm.xml From f1a4304ee75cecaf635b3e190364d0bdb8171923 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 28 Jun 2024 13:43:53 -0700 Subject: [PATCH 53/86] [test] add new testcases for validate clock tree disable functions --- .../config/clk_arch_1clk_1rst_2layer.xml | 32 +++++++++++ .../config/pin_constraints_reset.xml | 7 +++ .../config/pin_constraints_resetb.xml | 7 +++ .../config/repack_pin_constraints.xml | 4 ++ .../config/task.conf | 54 +++++++++++++++++++ .../config/clk_arch_2clk_2layer.xml | 18 +++++++ .../config/pin_constraints.xml | 4 ++ .../config/repack_constraints.xml | 5 ++ .../config/task.conf | 41 ++++++++++++++ .../config/clk_arch_2clk_2layer.xml | 18 +++++++ .../config/pin_constraints.xml | 4 ++ .../config/repack_constraints.xml | 5 ++ .../config/task.conf | 41 ++++++++++++++ 13 files changed, 240 insertions(+) create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/clk_arch_1clk_1rst_2layer.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/pin_constraints_reset.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/pin_constraints_resetb.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/repack_pin_constraints.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/task.conf create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/clk_arch_2clk_2layer.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/pin_constraints.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/repack_constraints.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/task.conf create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/clk_arch_2clk_2layer.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/pin_constraints.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/repack_constraints.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/task.conf diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/clk_arch_1clk_1rst_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/clk_arch_1clk_1rst_2layer.xml new file mode 100644 index 000000000..6c05921c7 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/clk_arch_1clk_1rst_2layer.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/pin_constraints_reset.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/pin_constraints_reset.xml new file mode 100644 index 000000000..abcf209f6 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/pin_constraints_reset.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/pin_constraints_resetb.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/pin_constraints_resetb.xml new file mode 100644 index 000000000..cdef2ad86 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/pin_constraints_resetb.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/repack_pin_constraints.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/repack_pin_constraints.xml new file mode 100644 index 000000000..06a125111 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/repack_pin_constraints.xml @@ -0,0 +1,4 @@ + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/task.conf b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/task.conf new file mode 100644 index 000000000..50f4280f3 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/task.conf @@ -0,0 +1,54 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# Configuration file for running experiments +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs +# Each job execute fpga_flow script on combination of architecture & benchmark +# timeout_each_job is timeout for each job +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + +[GENERAL] +run_engine=openfpga_shell +power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml +power_analysis = false +spice_output=false +verilog_output=true +timeout_each_job = 3*60 +fpga_flow=yosys_vpr + +[OpenFPGA_SHELL] +openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_Ntwk1clk1rst2lvl_cc_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml +openfpga_repack_constraints_file=${PATH:TASK_DIR}/config/repack_pin_constraints.xml +openfpga_vpr_device_layout=2x2 +openfpga_vpr_route_chan_width=40 +openfpga_clock_arch_file=${PATH:TASK_DIR}/config/clk_arch_1clk_1rst_2layer.xml +openfpga_verilog_testbench_port_mapping=--explicit_port_mapping +openfpga_route_clock_options=--disable_unused_spines + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_reset/counter.v +bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_resetb/counter.v + +[SYNTHESIS_PARAM] +# Yosys script parameters +bench_yosys_cell_sim_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/openfpga_dff_sim.v +bench_yosys_dff_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/openfpga_dff_map.v +bench_read_verilog_options_common = -nolatches +bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dff_flow.ys +bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys;${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_rewrite_flow.ys + +bench0_top = counter +bench0_openfpga_pin_constraints_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/pin_constraints_reset.xml +bench0_openfpga_verilog_testbench_port_mapping= + +bench1_top = counter +bench1_openfpga_pin_constraints_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/pin_constraints_resetb.xml +bench1_openfpga_verilog_testbench_port_mapping= + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= +vpr_fpga_verilog_formal_verification_top_netlist= diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/clk_arch_2clk_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/clk_arch_2clk_2layer.xml new file mode 100644 index 000000000..8c224318c --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/clk_arch_2clk_2layer.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/pin_constraints.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/pin_constraints.xml new file mode 100644 index 000000000..1989d1eea --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/pin_constraints.xml @@ -0,0 +1,4 @@ + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/repack_constraints.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/repack_constraints.xml new file mode 100644 index 000000000..eb0c4435a --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/repack_constraints.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/task.conf b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/task.conf new file mode 100644 index 000000000..d08fcf15a --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/task.conf @@ -0,0 +1,41 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# Configuration file for running experiments +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs +# Each job execute fpga_flow script on combination of architecture & benchmark +# timeout_each_job is timeout for each job +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + +[GENERAL] +run_engine=openfpga_shell +power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml +power_analysis = true +spice_output=false +verilog_output=true +timeout_each_job = 20*60 +fpga_flow=yosys_vpr + +[OpenFPGA_SHELL] +openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/example_clkntwk_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_Ntwk2clk2lvl_cc_openfpga.xml +openfpga_clock_arch_file=${PATH:TASK_DIR}/config/clk_arch_2clk_2layer.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml +openfpga_vpr_device_layout=2x2 +openfpga_vpr_route_chan_width=24 +openfpga_repack_constraints_file=${PATH:TASK_DIR}/config/repack_constraints.xml +openfpga_pin_constraints_file=${PATH:TASK_DIR}/config/pin_constraints.xml +openfpga_route_clock_options=--disable_unused_trees --disable_unused_spines + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_Ntwk2clk2lvl_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch/and2_latch.v + +[SYNTHESIS_PARAM] +bench_read_verilog_options_common = -nolatches +bench0_top = and2_latch + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= +vpr_fpga_verilog_formal_verification_top_netlist= diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/clk_arch_2clk_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/clk_arch_2clk_2layer.xml new file mode 100644 index 000000000..8c224318c --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/clk_arch_2clk_2layer.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/pin_constraints.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/pin_constraints.xml new file mode 100644 index 000000000..1989d1eea --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/pin_constraints.xml @@ -0,0 +1,4 @@ + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/repack_constraints.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/repack_constraints.xml new file mode 100644 index 000000000..eb0c4435a --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/repack_constraints.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/task.conf b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/task.conf new file mode 100644 index 000000000..8e58aec0c --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/task.conf @@ -0,0 +1,41 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# Configuration file for running experiments +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs +# Each job execute fpga_flow script on combination of architecture & benchmark +# timeout_each_job is timeout for each job +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + +[GENERAL] +run_engine=openfpga_shell +power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml +power_analysis = true +spice_output=false +verilog_output=true +timeout_each_job = 20*60 +fpga_flow=yosys_vpr + +[OpenFPGA_SHELL] +openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/example_clkntwk_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_Ntwk2clk2lvl_cc_openfpga.xml +openfpga_clock_arch_file=${PATH:TASK_DIR}/config/clk_arch_2clk_2layer.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml +openfpga_vpr_device_layout=2x2 +openfpga_vpr_route_chan_width=24 +openfpga_repack_constraints_file=${PATH:TASK_DIR}/config/repack_constraints.xml +openfpga_pin_constraints_file=${PATH:TASK_DIR}/config/pin_constraints.xml +openfpga_route_clock_options=--disable_unused_trees + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_Ntwk2clk2lvl_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch/and2_latch.v + +[SYNTHESIS_PARAM] +bench_read_verilog_options_common = -nolatches +bench0_top = and2_latch + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= +vpr_fpga_verilog_formal_verification_top_netlist= From f4dd222c47299604993cc00a4fbd476319b25123 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 28 Jun 2024 13:45:36 -0700 Subject: [PATCH 54/86] [test] deploy new testcases to basic reg tests --- openfpga_flow/regression_test_scripts/basic_reg_test.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/openfpga_flow/regression_test_scripts/basic_reg_test.sh b/openfpga_flow/regression_test_scripts/basic_reg_test.sh index 20b2e3bf0..476e8c010 100755 --- a/openfpga_flow/regression_test_scripts/basic_reg_test.sh +++ b/openfpga_flow/regression_test_scripts/basic_reg_test.sh @@ -232,7 +232,10 @@ echo -e "Testing programmable clock architecture"; run-task basic_tests/clock_network/homo_1clock_2layer $@ run-task basic_tests/clock_network/homo_1clock_2layer_full_tb $@ run-task basic_tests/clock_network/homo_2clock_2layer $@ +run-task basic_tests/clock_network/homo_2clock_2layer_disable_unused $@ +run-task basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree $@ run-task basic_tests/clock_network/homo_1clock_1_reset_2layer $@ +run-task basic_tests/clock_network/homo_1clock_1_reset_2layer_disable_unused_spines $@ run-task basic_tests/clock_network/homo_1clock_1_reset_2layer_internal_driver $@ echo -e "Testing configuration chain of a K4N4 FPGA using .blif generated by yosys+verific"; From 5cfd23747ba0d2c21c053cd20d769766202b7d20 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 28 Jun 2024 13:47:03 -0700 Subject: [PATCH 55/86] [core] code format --- .../src/base/clock_network.cpp | 6 +- .../src/base/clock_network.h | 3 +- .../src/annotation/route_clock_rr_graph.cpp | 157 ++++++++++-------- .../src/annotation/route_clock_rr_graph.h | 6 +- .../src/base/openfpga_link_arch_template.h | 3 +- .../base/openfpga_setup_command_template.h | 8 +- 6 files changed, 104 insertions(+), 79 deletions(-) diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index a34868be5..ed8e050e7 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -333,9 +333,9 @@ vtr::Point ClockNetwork::spine_switch_point( return spine_switch_coords_[spine_id][size_t(switch_point_id)]; } -std::vector ClockNetwork::find_spine_switch_points_with_coord( - const ClockSpineId& spine_id, - const vtr::Point& coord) const { +std::vector +ClockNetwork::find_spine_switch_points_with_coord( + const ClockSpineId& spine_id, const vtr::Point& coord) const { VTR_ASSERT(valid_spine_id(spine_id)); std::vector ret; for (size_t i = 0; i < spine_switch_points_[spine_id].size(); ++i) { diff --git a/libs/libclkarchopenfpga/src/base/clock_network.h b/libs/libclkarchopenfpga/src/base/clock_network.h index 0fc15e471..2921340fd 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.h +++ b/libs/libclkarchopenfpga/src/base/clock_network.h @@ -127,7 +127,8 @@ class ClockNetwork { const ClockSwitchPointId& switch_point_id) const; /* Find all the switching points at a given coordinate */ - std::vector find_spine_switch_points_with_coord(const ClockSpineId& spine_id, const vtr::Point& coord) const; + std::vector find_spine_switch_points_with_coord( + const ClockSpineId& spine_id, const vtr::Point& coord) const; std::vector spine_switch_point_internal_drivers( const ClockSpineId& spine_id, diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index 393740309..9fbc55747 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -84,15 +84,13 @@ static int build_clock_tree_net_map( * - connect internal driver to routing track *******************************************************************/ static int route_clock_spine_switch_point( - VprRoutingAnnotation& vpr_routing_annotation, - const RRGraphView& rr_graph, + VprRoutingAnnotation& vpr_routing_annotation, const RRGraphView& rr_graph, const RRClockSpatialLookup& clk_rr_lookup, const vtr::vector& rr_node_gnets, const std::map& tree2clk_pin_map, const ClockNetwork& clk_ntwk, const ClockTreeId& clk_tree, const ClockSpineId& ispine, const ClockTreePinId& ipin, - const ClockSwitchPointId& switch_point_id, - const bool& verbose) { + const ClockSwitchPointId& switch_point_id, const bool& verbose) { VTR_LOGV(verbose, "Routing switch points of spine '%s'...\n", clk_ntwk.spine_name(ispine).c_str()); vtr::Point src_coord = @@ -117,8 +115,7 @@ static int route_clock_spine_switch_point( * global net is mapped to the internal driver, use it as the previous * node */ size_t use_int_driver = 0; - if (!clk_ntwk - .spine_switch_point_internal_drivers(ispine, switch_point_id) + if (!clk_ntwk.spine_switch_point_internal_drivers(ispine, switch_point_id) .empty() && tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) { for (RREdgeId cand_edge : rr_graph.node_in_edges(des_node)) { @@ -137,8 +134,11 @@ static int route_clock_spine_switch_point( vpr_routing_annotation.set_rr_node_net(des_node, tree2clk_pin_map.at(ipin)); use_int_driver++; - VTR_LOGV(verbose, "Routed switch points of spine '%s' at the switching point (%lu, %lu) using internal driver\n", - clk_ntwk.spine_name(ispine).c_str(), src_coord.x(), src_coord.y()); + VTR_LOGV(verbose, + "Routed switch points of spine '%s' at the switching point " + "(%lu, %lu) using internal driver\n", + clk_ntwk.spine_name(ispine).c_str(), src_coord.x(), + src_coord.y()); } } if (use_int_driver > 1) { @@ -152,18 +152,18 @@ static int route_clock_spine_switch_point( if (use_int_driver == 1) { return CMD_EXEC_SUCCESS; /* Used internal driver, early pass */ } - VTR_LOGV(verbose, "Routed switch points of spine '%s' from (x=%lu, y=%lu) to spine '%s' at (x=%lu, y=%lu)\n", + VTR_LOGV(verbose, + "Routed switch points of spine '%s' from (x=%lu, y=%lu) to spine " + "'%s' at (x=%lu, y=%lu)\n", clk_ntwk.spine_name(ispine).c_str(), src_coord.x(), src_coord.y(), - clk_ntwk.spine_name(des_spine).c_str(), des_coord.x(), des_coord.y()); - vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, - src_node); + clk_ntwk.spine_name(des_spine).c_str(), des_coord.x(), + des_coord.y()); + vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, src_node); /* It could happen that there is no net mapped some clock pin, skip the * net mapping */ if (tree2clk_pin_map.find(ipin) != tree2clk_pin_map.end()) { - vpr_routing_annotation.set_rr_node_net(src_node, - tree2clk_pin_map.at(ipin)); - vpr_routing_annotation.set_rr_node_net(des_node, - tree2clk_pin_map.at(ipin)); + vpr_routing_annotation.set_rr_node_net(src_node, tree2clk_pin_map.at(ipin)); + vpr_routing_annotation.set_rr_node_net(des_node, tree2clk_pin_map.at(ipin)); } return CMD_EXEC_SUCCESS; @@ -174,15 +174,12 @@ static int route_clock_spine_switch_point( * - Only connect to tap points which are mapped by a global net *******************************************************************/ static int route_spine_taps( - VprRoutingAnnotation& vpr_routing_annotation, - bool& spine_usage, - const RRGraphView& rr_graph, - const RRClockSpatialLookup& clk_rr_lookup, + VprRoutingAnnotation& vpr_routing_annotation, bool& spine_usage, + const RRGraphView& rr_graph, const RRClockSpatialLookup& clk_rr_lookup, const vtr::vector& rr_node_gnets, const std::map& tree2clk_pin_map, const ClockNetwork& clk_ntwk, const ClockTreeId& clk_tree, - const ClockSpineId& ispine, const ClockTreePinId& ipin, - const bool& verbose) { + const ClockSpineId& ispine, const ClockTreePinId& ipin, const bool& verbose) { std::vector> spine_coords = clk_ntwk.spine_coordinates(ispine); size_t spine_tap_cnt = 0; @@ -227,15 +224,14 @@ static int route_spine_taps( } VTR_ASSERT(rr_graph.valid_node(src_node)); VTR_ASSERT(rr_graph.valid_node(des_node)); - VTR_LOGV(verbose, - "Routed clock tap of spine '%s'\n", + VTR_LOGV(verbose, "Routed clock tap of spine '%s'\n", clk_ntwk.spine_name(ispine).c_str()); vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, src_node); - vpr_routing_annotation.set_rr_node_net( - src_node, tree2clk_pin_map.at(ipin)); - vpr_routing_annotation.set_rr_node_net( - des_node, tree2clk_pin_map.at(ipin)); + vpr_routing_annotation.set_rr_node_net(src_node, + tree2clk_pin_map.at(ipin)); + vpr_routing_annotation.set_rr_node_net(des_node, + tree2clk_pin_map.at(ipin)); /* Increment upon any required tap */ spine_tap_cnt++; } @@ -253,12 +249,13 @@ static int route_spine_taps( * Recursively route a clock spine on an existing routing resource graph * The strategy is to route spine one by one * - route the spine from the ending point to starting point (straight line) - * - for each stops on the staight line, route the spine-to-spine switching points + * - for each stops on the staight line, route the spine-to-spine switching + points * - for each switching point (des_spine_top|bottom), go recursively * - If the downstream spine at any switching point is not used, disconnect * - If any stop on the spine (straght line) is not used, disconnect * - route the spine-to-IPIN connections (only for the last level) - * + * * des_spine_top[0...N] * ^ ^ ^ ^ * | | | | @@ -271,10 +268,13 @@ static int route_spine_taps( * * * On each stop, we expand the spine to switch points and tap points - * - If the previous stop is used (connection to des_spines are required), then the current stop should be connected to the previous stop - * - If previous stop is not used, while the des_spines are required to connect, then the current stop should be connected to the previous stop - * - Only when previous stops and des_spines are not used, the current stop will be NOT connected to the previous stop - * + * - If the previous stop is used (connection to des_spines are required), then + the current stop should be connected to the previous stop + * - If previous stop is not used, while the des_spines are required to + connect, then the current stop should be connected to the previous stop + * - Only when previous stops and des_spines are not used, the current stop + will be NOT connected to the previous stop + * * des_spine_top[i] * ^ * | @@ -286,21 +286,20 @@ static int route_spine_taps( * *******************************************************************/ static int rec_expand_and_route_clock_spine( - VprRoutingAnnotation& vpr_routing_annotation, - bool& spine_usage, - const RRGraphView& rr_graph, - const RRClockSpatialLookup& clk_rr_lookup, + VprRoutingAnnotation& vpr_routing_annotation, bool& spine_usage, + const RRGraphView& rr_graph, const RRClockSpatialLookup& clk_rr_lookup, const vtr::vector& rr_node_gnets, const std::map& tree2clk_pin_map, const ClockNetwork& clk_ntwk, const ClockTreeId& clk_tree, const ClockSpineId& curr_spine, const ClockTreePinId& curr_pin, - const bool& disable_unused_spines, - const bool& verbose) { + const bool& disable_unused_spines, const bool& verbose) { int status = CMD_EXEC_SUCCESS; bool curr_spine_usage = false; bool curr_tap_usage = false; /* For last level, we just connect tap points */ - status = route_spine_taps(vpr_routing_annotation, curr_tap_usage, rr_graph, clk_rr_lookup, rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, curr_spine, curr_pin, verbose); + status = route_spine_taps(vpr_routing_annotation, curr_tap_usage, rr_graph, + clk_rr_lookup, rr_node_gnets, tree2clk_pin_map, + clk_ntwk, clk_tree, curr_spine, curr_pin, verbose); if (CMD_EXEC_SUCCESS != status) { return CMD_EXEC_FATAL_ERROR; } @@ -312,7 +311,8 @@ static int rec_expand_and_route_clock_spine( clk_ntwk.spine_coordinates(curr_spine); /* We expand from the the ending point to starting point on the straight line. * As such, it is easy to turn off spines by any stop. - * The spine should go in a straight line, connect all the stops on the line */ + * The spine should go in a straight line, connect all the stops on the line + */ bool prev_stop_usage = false; std::reverse(spine_coords.begin(), spine_coords.end()); for (size_t icoord = 0; icoord < spine_coords.size(); ++icoord) { @@ -323,33 +323,46 @@ static int rec_expand_and_route_clock_spine( } /* Expand on the switching point here */ for (ClockSwitchPointId switch_point_id : - clk_ntwk.find_spine_switch_points_with_coord(curr_spine, switch_point_coord)) { + clk_ntwk.find_spine_switch_points_with_coord(curr_spine, + switch_point_coord)) { ClockSpineId des_spine = clk_ntwk.spine_switch_point_tap(curr_spine, switch_point_id); /* Go recursively for the destination spine */ bool curr_branch_usage = false; - status = rec_expand_and_route_clock_spine(vpr_routing_annotation, curr_branch_usage, rr_graph, clk_rr_lookup, rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, des_spine, curr_pin, disable_unused_spines, verbose); + status = rec_expand_and_route_clock_spine( + vpr_routing_annotation, curr_branch_usage, rr_graph, clk_rr_lookup, + rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, des_spine, + curr_pin, disable_unused_spines, verbose); if (CMD_EXEC_SUCCESS != status) { return CMD_EXEC_FATAL_ERROR; } /* Connect only when the destination spine is used */ if (disable_unused_spines && !curr_branch_usage) { - VTR_LOGV(verbose, "Disconnect switching from spine '%s' to spine '%s' as downstream is not used\n", - clk_ntwk.spine_name(curr_spine).c_str(), clk_ntwk.spine_name(des_spine).c_str()); + VTR_LOGV(verbose, + "Disconnect switching from spine '%s' to spine '%s' as " + "downstream is not used\n", + clk_ntwk.spine_name(curr_spine).c_str(), + clk_ntwk.spine_name(des_spine).c_str()); continue; - } + } curr_stop_usage = true; /* Now connect to next spine, internal drivers may join */ - status = route_clock_spine_switch_point(vpr_routing_annotation, rr_graph, clk_rr_lookup, rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, curr_spine, curr_pin, switch_point_id, verbose); + status = route_clock_spine_switch_point( + vpr_routing_annotation, rr_graph, clk_rr_lookup, rr_node_gnets, + tree2clk_pin_map, clk_ntwk, clk_tree, curr_spine, curr_pin, + switch_point_id, verbose); if (CMD_EXEC_SUCCESS != status) { return CMD_EXEC_FATAL_ERROR; } } if (disable_unused_spines && !curr_stop_usage && !prev_stop_usage) { - VTR_LOGV(verbose, "Disconnect backbone of spine '%s' at (x=%lu, y=%lu) as downstream is not used\n", - clk_ntwk.spine_name(curr_spine).c_str(), switch_point_coord.x(), switch_point_coord.y()); + VTR_LOGV(verbose, + "Disconnect backbone of spine '%s' at (x=%lu, y=%lu) as " + "downstream is not used\n", + clk_ntwk.spine_name(curr_spine).c_str(), switch_point_coord.x(), + switch_point_coord.y()); continue; - } + } /* Skip the first stop */ if (icoord == spine_coords.size() - 1) { continue; @@ -357,8 +370,11 @@ static int rec_expand_and_route_clock_spine( /* Connect only when next stop is used */ vtr::Point src_coord = spine_coords[icoord + 1]; vtr::Point des_coord = spine_coords[icoord]; - VTR_LOGV(verbose, "(icoord=%lu) Expanding on backbone of spine '%s' from (x=%lu, y=%lu) to (x=%lu, y=%lu)...\n", - icoord, clk_ntwk.spine_name(curr_spine).c_str(), src_coord.x(), src_coord.y(), des_coord.x(), des_coord.y()); + VTR_LOGV(verbose, + "(icoord=%lu) Expanding on backbone of spine '%s' from (x=%lu, " + "y=%lu) to (x=%lu, y=%lu)...\n", + icoord, clk_ntwk.spine_name(curr_spine).c_str(), src_coord.x(), + src_coord.y(), des_coord.x(), des_coord.y()); Direction src_spine_direction = clk_ntwk.spine_direction(curr_spine); Direction des_spine_direction = clk_ntwk.spine_direction(curr_spine); ClockLevelId src_spine_level = clk_ntwk.spine_level(curr_spine); @@ -371,15 +387,17 @@ static int rec_expand_and_route_clock_spine( des_spine_level, curr_pin, des_spine_direction); VTR_ASSERT(rr_graph.valid_node(src_node)); VTR_ASSERT(rr_graph.valid_node(des_node)); - VTR_LOGV(verbose, "Routed backbone of spine '%s' from (x=%lu, y=%lu) to (x=%lu, y=%lu)...\n", - clk_ntwk.spine_name(curr_spine).c_str(), src_coord.x(), src_coord.y(), des_coord.x(), des_coord.y()); - vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, - src_node); + VTR_LOGV(verbose, + "Routed backbone of spine '%s' from (x=%lu, y=%lu) to (x=%lu, " + "y=%lu)...\n", + clk_ntwk.spine_name(curr_spine).c_str(), src_coord.x(), + src_coord.y(), des_coord.x(), des_coord.y()); + vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, src_node); prev_stop_usage = true; curr_spine_usage = true; } /* Update status */ - spine_usage = curr_spine_usage; + spine_usage = curr_spine_usage; return CMD_EXEC_SUCCESS; } @@ -397,20 +415,24 @@ static int route_clock_tree_rr_graph( const vtr::vector& rr_node_gnets, const std::map& tree2clk_pin_map, const ClockNetwork& clk_ntwk, const ClockTreeId& clk_tree, - const bool& disable_unused_trees, - const bool& disable_unused_spines, + const bool& disable_unused_trees, const bool& disable_unused_spines, const bool& verbose) { for (auto ipin : clk_ntwk.pins(clk_tree)) { /* Do not route unused clock spines */ - if (disable_unused_trees && tree2clk_pin_map.find(ipin) == tree2clk_pin_map.end()) { + if (disable_unused_trees && + tree2clk_pin_map.find(ipin) == tree2clk_pin_map.end()) { VTR_LOGV(verbose, "Skip routing unused tree '%s' pin '%lu'...\n", clk_ntwk.tree_name(clk_tree).c_str(), size_t(ipin)); continue; } - /* Start with the top-level spines. Recursively walk through coordinates and expand on switch points */ + /* Start with the top-level spines. Recursively walk through coordinates and + * expand on switch points */ bool tree_usage = false; for (auto top_spine : clk_ntwk.tree_top_spines(clk_tree)) { - int status = rec_expand_and_route_clock_spine(vpr_routing_annotation, tree_usage, rr_graph, clk_rr_lookup, rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, top_spine, ipin, disable_unused_spines, verbose); + int status = rec_expand_and_route_clock_spine( + vpr_routing_annotation, tree_usage, rr_graph, clk_rr_lookup, + rr_node_gnets, tree2clk_pin_map, clk_ntwk, clk_tree, top_spine, ipin, + disable_unused_spines, verbose); if (CMD_EXEC_SUCCESS != status) { return CMD_EXEC_FATAL_ERROR; } @@ -435,10 +457,8 @@ int route_clock_rr_graph( const ClusteredNetlist& cluster_nlist, const PlacementContext& vpr_place_ctx, const VprNetlistAnnotation& netlist_annotation, const RRClockSpatialLookup& clk_rr_lookup, const ClockNetwork& clk_ntwk, - const PinConstraints& pin_constraints, - const bool& disable_unused_trees, - const bool& disable_unused_spines, - const bool& verbose) { + const PinConstraints& pin_constraints, const bool& disable_unused_trees, + const bool& disable_unused_spines, const bool& verbose) { vtr::ScopedStartFinishTimer timer( "Route programmable clock network based on routing resource graph"); @@ -490,7 +510,8 @@ int route_clock_rr_graph( clk_ntwk.tree_name(itree).c_str()); status = route_clock_tree_rr_graph( vpr_routing_annotation, vpr_device_ctx.rr_graph, clk_rr_lookup, - rr_node_gnets, tree2clk_pin_map, clk_ntwk, itree, disable_unused_trees, disable_unused_spines, verbose); + rr_node_gnets, tree2clk_pin_map, clk_ntwk, itree, disable_unused_trees, + disable_unused_spines, verbose); if (status == CMD_EXEC_FATAL_ERROR) { return status; } diff --git a/openfpga/src/annotation/route_clock_rr_graph.h b/openfpga/src/annotation/route_clock_rr_graph.h index 13bff0eea..ee962d6d4 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.h +++ b/openfpga/src/annotation/route_clock_rr_graph.h @@ -24,10 +24,8 @@ int route_clock_rr_graph( const ClusteredNetlist& cluster_nlist, const PlacementContext& vpr_place_ctx, const VprNetlistAnnotation& netlist_annotation, const RRClockSpatialLookup& clk_rr_lookup, const ClockNetwork& clk_ntwk, - const PinConstraints& pin_constraints, - const bool& disable_unused_trees, - const bool& disable_unused_spines, - const bool& verbose); + const PinConstraints& pin_constraints, const bool& disable_unused_trees, + const bool& disable_unused_spines, const bool& verbose); } /* end namespace openfpga */ diff --git a/openfpga/src/base/openfpga_link_arch_template.h b/openfpga/src/base/openfpga_link_arch_template.h index e0fec4742..24971105c 100644 --- a/openfpga/src/base/openfpga_link_arch_template.h +++ b/openfpga/src/base/openfpga_link_arch_template.h @@ -220,7 +220,8 @@ int route_clock_rr_graph_template(T& openfpga_ctx, const Command& cmd, /* add an option '--pin_constraints_file in short '-pcf' */ CommandOptionId opt_pcf = cmd.option("pin_constraints_file"); CommandOptionId opt_disable_unused_trees = cmd.option("disable_unused_trees"); - CommandOptionId opt_disable_unused_spines = cmd.option("disable_unused_spines"); + CommandOptionId opt_disable_unused_spines = + cmd.option("disable_unused_spines"); CommandOptionId opt_verbose = cmd.option("verbose"); /* If pin constraints are enabled by command options, read the file */ diff --git a/openfpga/src/base/openfpga_setup_command_template.h b/openfpga/src/base/openfpga_setup_command_template.h index 169d3cf9a..53e43f00f 100644 --- a/openfpga/src/base/openfpga_setup_command_template.h +++ b/openfpga/src/base/openfpga_setup_command_template.h @@ -710,8 +710,12 @@ ShellCommandId add_route_clock_rr_graph_command_template( shell_cmd.set_option_short_name(opt_file, "pcf"); shell_cmd.set_option_require_value(opt_file, openfpga::OPT_STRING); - shell_cmd.add_option("disable_unused_trees", false, "Disable entire clock trees when they are not used by any clock nets. Useful to reduce clock power"); - shell_cmd.add_option("disable_unused_spines", false, "Disable part of the clock tree which are used by clock nets. Useful to reduce clock power"); + shell_cmd.add_option("disable_unused_trees", false, + "Disable entire clock trees when they are not used by " + "any clock nets. Useful to reduce clock power"); + shell_cmd.add_option("disable_unused_spines", false, + "Disable part of the clock tree which are used by clock " + "nets. Useful to reduce clock power"); /* Add an option '--verbose' */ shell_cmd.add_option("verbose", false, "Show verbose outputs"); From e0b9f7860b0dc7b7c4aa1ea79c341b54b02af792 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 28 Jun 2024 14:10:14 -0700 Subject: [PATCH 56/86] [core] fixed a bug where counter for gnets are not activated --- openfpga/src/annotation/openfpga_annotate_routing.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/openfpga/src/annotation/openfpga_annotate_routing.cpp b/openfpga/src/annotation/openfpga_annotate_routing.cpp index ad84d86e2..cfbb064ef 100644 --- a/openfpga/src/annotation/openfpga_annotate_routing.cpp +++ b/openfpga/src/annotation/openfpga_annotate_routing.cpp @@ -47,6 +47,7 @@ vtr::vector annotate_rr_node_global_net( layer, blk_loc.loc.x, blk_loc.loc.y, IPIN, phy_pin); for (RRNodeId curr_rr_node : curr_rr_nodes) { rr_node_nets[curr_rr_node] = net_id; + counter++; } } } From 0de3ff3eb8e7bad68ce6fea76778cb95ab97f3f6 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 28 Jun 2024 17:16:33 -0700 Subject: [PATCH 57/86] [core] debugging --- openfpga/src/annotation/route_clock_rr_graph.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index 9fbc55747..f380fed6a 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -185,8 +185,8 @@ static int route_spine_taps( size_t spine_tap_cnt = 0; /* Route the spine-to-IPIN connections (only for the last level) */ if (clk_ntwk.is_last_level(ispine)) { - VTR_LOGV(verbose, "Routing clock taps of spine '%s'...\n", - clk_ntwk.spine_name(ispine).c_str()); + VTR_LOGV(verbose, "Routing clock taps of spine '%s' for pin '%d' of tree '%s'...\n", + clk_ntwk.spine_name(ispine).c_str(), size_t(ipin), clk_ntwk.tree_name(clk_tree).c_str()); /* Connect to any fan-out node which is IPIN */ for (size_t icoord = 0; icoord < spine_coords.size(); ++icoord) { vtr::Point src_coord = spine_coords[icoord]; @@ -198,6 +198,8 @@ static int route_spine_taps( for (RREdgeId edge : rr_graph.edge_range(src_node)) { RRNodeId des_node = rr_graph.edge_sink_node(edge); if (rr_graph.node_type(des_node) == IPIN) { + VTR_LOGV(verbose, "Trying to route to IPIN '%s'\n", + rr_graph.node_coordinate_to_string(des_node).c_str()); /* Check if the IPIN is mapped, if not, do not connect */ /* if the IPIN is mapped, only connect when net mapping is * expected */ @@ -393,6 +395,13 @@ static int rec_expand_and_route_clock_spine( clk_ntwk.spine_name(curr_spine).c_str(), src_coord.x(), src_coord.y(), des_coord.x(), des_coord.y()); vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, src_node); + /* It could happen that there is no net mapped some clock pin, skip the + * net mapping */ + if (tree2clk_pin_map.find(curr_pin) != tree2clk_pin_map.end()) { + vpr_routing_annotation.set_rr_node_net(src_node, tree2clk_pin_map.at(curr_pin)); + vpr_routing_annotation.set_rr_node_net(des_node, tree2clk_pin_map.at(curr_pin)); + } + prev_stop_usage = true; curr_spine_usage = true; } From 1c693659386840055821a351bbf31a3e8abce762 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 28 Jun 2024 18:17:38 -0700 Subject: [PATCH 58/86] [core] debugging --- .../src/annotation/route_clock_rr_graph.cpp | 58 ++++++++----------- .../src/annotation/route_clock_rr_graph.h | 4 +- .../src/base/openfpga_link_arch_template.h | 4 +- .../openfpga_clustered_netlist_utils.cpp | 35 +++++++++++ .../utils/openfpga_clustered_netlist_utils.h | 24 ++++++++ .../config/pin_constraints_reset.xml | 1 + .../config/pin_constraints_resetb.xml | 1 + 7 files changed, 88 insertions(+), 39 deletions(-) create mode 100644 openfpga/src/utils/openfpga_clustered_netlist_utils.cpp create mode 100644 openfpga/src/utils/openfpga_clustered_netlist_utils.h diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index f380fed6a..7b10262fa 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -2,7 +2,7 @@ #include "command_exit_codes.h" #include "openfpga_annotate_routing.h" -#include "openfpga_atom_netlist_utils.h" +#include "openfpga_clustered_netlist_utils.h" #include "vtr_assert.h" #include "vtr_geometry.h" #include "vtr_log.h" @@ -22,27 +22,26 @@ namespace openfpga { static int build_clock_tree_net_map( std::map& tree2clk_pin_map, const ClusteredNetlist& cluster_nlist, const PinConstraints& pin_constraints, - const std::vector& clk_names, const ClockNetwork& clk_ntwk, + const std::vector& gnets, const ClockNetwork& clk_ntwk, const ClockTreeId clk_tree, const bool& verbose) { /* Find the pin id for each clock name, error out if there is any mismatch */ - if (clk_names.size() == 1 && clk_ntwk.tree_width(clk_tree) == 1) { + if (clk_ntwk.num_trees() == 1 && gnets.size() == 1 && clk_ntwk.tree_width(clk_tree) == 1) { /* Find cluster net id */ - ClusterNetId clk_net = cluster_nlist.find_net(clk_names[0]); - if (!cluster_nlist.valid_net_id(clk_net)) { - VTR_LOG_ERROR("Invalid clock name '%s'! Cannot found from netlists!\n", - clk_names[0].c_str()); + if (!cluster_nlist.valid_net_id(gnets[0])) { + VTR_LOG_ERROR("Invalid clock name '%s'! Cannot be found from netlists!\n", + cluster_nlist.net_name(gnets[0]).c_str()); return CMD_EXEC_FATAL_ERROR; } - tree2clk_pin_map[ClockTreePinId(0)] = clk_net; + tree2clk_pin_map[ClockTreePinId(0)] = gnets[0]; } else { - for (std::string clk_name : clk_names) { + for (ClusterNetId gnet : gnets) { /* Find the pin information that the net should be mapped to */ - BasicPort tree_pin = pin_constraints.net_pin(clk_name); + std::string gnet_name = cluster_nlist.net_name(gnet); + BasicPort tree_pin = pin_constraints.net_pin(gnet_name); if (!tree_pin.is_valid()) { VTR_LOG_ERROR( - "Invalid tree pin for clock '%s'! Clock name may not be valid " - "(mismatched with netlists)!\n", - clk_name.c_str()); + "Global net '%s' is not mapped to a valid pin '%s' in pin constraints!\n", + gnet_name.c_str(), tree_pin.to_verilog_string().c_str()); return CMD_EXEC_FATAL_ERROR; } if (tree_pin.get_width() != 1) { @@ -50,7 +49,7 @@ static int build_clock_tree_net_map( "Invalid tree pin %s[%lu:%lu] for clock '%s'! Clock pin must have " "only a width of 1!\n", tree_pin.get_name().c_str(), tree_pin.get_lsb(), tree_pin.get_msb(), - clk_name.c_str()); + gnet_name.c_str()); return CMD_EXEC_FATAL_ERROR; } if (tree_pin.get_lsb() >= clk_ntwk.tree_width(clk_tree)) { @@ -60,15 +59,8 @@ static int build_clock_tree_net_map( clk_ntwk.tree_width(clk_tree)); return CMD_EXEC_FATAL_ERROR; } - /* Find cluster net id */ - ClusterNetId clk_net = cluster_nlist.find_net(clk_name); - if (!cluster_nlist.valid_net_id(clk_net)) { - VTR_LOG_ERROR("Invalid clock name '%s'! Cannot found from netlists!\n", - clk_name.c_str()); - return CMD_EXEC_FATAL_ERROR; - } /* Register the pin mapping */ - tree2clk_pin_map[ClockTreePinId(tree_pin.get_lsb())] = clk_net; + tree2clk_pin_map[ClockTreePinId(tree_pin.get_lsb())] = gnet; } } @@ -462,9 +454,8 @@ static int route_clock_tree_rr_graph( *******************************************************************/ int route_clock_rr_graph( VprRoutingAnnotation& vpr_routing_annotation, - const DeviceContext& vpr_device_ctx, const AtomContext& atom_ctx, + const DeviceContext& vpr_device_ctx, const ClusteredNetlist& cluster_nlist, const PlacementContext& vpr_place_ctx, - const VprNetlistAnnotation& netlist_annotation, const RRClockSpatialLookup& clk_rr_lookup, const ClockNetwork& clk_ntwk, const PinConstraints& pin_constraints, const bool& disable_unused_trees, const bool& disable_unused_spines, const bool& verbose) { @@ -479,21 +470,20 @@ int route_clock_rr_graph( return CMD_EXEC_SUCCESS; } - /* If there are multiple clock signals from the netlist, require pin + /* If there are multiple global signals from the netlist, require pin * constraints */ - std::vector clock_net_names = - find_atom_netlist_clock_port_names(atom_ctx.nlist, netlist_annotation); - if (clock_net_names.empty()) { + std::vector gnets = find_clustered_netlist_global_nets(cluster_nlist); + if (gnets.empty()) { VTR_LOG( - "Skip due to 0 clocks found from netlist\nDouble check your HDL design " + "Skip due to 0 global nets found from netlist\nDouble check your HDL design " "if this is unexpected\n"); return CMD_EXEC_SUCCESS; } - if (clock_net_names.size() > 1 && pin_constraints.empty()) { + if (gnets.size() > 1 && pin_constraints.empty()) { VTR_LOG( - "There is %lu clock nets (more than 1). Require pin constraints to be " + "There is %lu global nets (more than 1). Require pin constraints to be " "specified\n", - clock_net_names.size()); + gnets.size()); return CMD_EXEC_FATAL_ERROR; } @@ -504,13 +494,13 @@ int route_clock_rr_graph( /* Route spines one by one */ for (auto itree : clk_ntwk.trees()) { - VTR_LOGV(verbose, "Build clock name to clock tree '%s' pin mapping...\n", + VTR_LOGV(verbose, "Build global net name to clock tree '%s' pin mapping...\n", clk_ntwk.tree_name(itree).c_str()); std::map tree2clk_pin_map; int status = CMD_EXEC_SUCCESS; status = build_clock_tree_net_map(tree2clk_pin_map, cluster_nlist, pin_constraints, - clock_net_names, clk_ntwk, itree, verbose); + gnets, clk_ntwk, itree, verbose); if (status == CMD_EXEC_FATAL_ERROR) { return status; } diff --git a/openfpga/src/annotation/route_clock_rr_graph.h b/openfpga/src/annotation/route_clock_rr_graph.h index ee962d6d4..443e3d11b 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.h +++ b/openfpga/src/annotation/route_clock_rr_graph.h @@ -8,7 +8,6 @@ #include "pin_constraints.h" #include "rr_clock_spatial_lookup.h" #include "vpr_context.h" -#include "vpr_netlist_annotation.h" #include "vpr_routing_annotation.h" /******************************************************************** @@ -20,9 +19,8 @@ namespace openfpga { int route_clock_rr_graph( VprRoutingAnnotation& vpr_routing_annotation, - const DeviceContext& vpr_device_ctx, const AtomContext& atom_ctx, + const DeviceContext& vpr_device_ctx, const ClusteredNetlist& cluster_nlist, const PlacementContext& vpr_place_ctx, - const VprNetlistAnnotation& netlist_annotation, const RRClockSpatialLookup& clk_rr_lookup, const ClockNetwork& clk_ntwk, const PinConstraints& pin_constraints, const bool& disable_unused_trees, const bool& disable_unused_spines, const bool& verbose); diff --git a/openfpga/src/base/openfpga_link_arch_template.h b/openfpga/src/base/openfpga_link_arch_template.h index 24971105c..cfb5b430f 100644 --- a/openfpga/src/base/openfpga_link_arch_template.h +++ b/openfpga/src/base/openfpga_link_arch_template.h @@ -233,8 +233,8 @@ int route_clock_rr_graph_template(T& openfpga_ctx, const Command& cmd, return route_clock_rr_graph( openfpga_ctx.mutable_vpr_routing_annotation(), g_vpr_ctx.device(), - g_vpr_ctx.atom(), g_vpr_ctx.clustering().clb_nlist, g_vpr_ctx.placement(), - openfpga_ctx.vpr_netlist_annotation(), openfpga_ctx.clock_rr_lookup(), + g_vpr_ctx.clustering().clb_nlist, g_vpr_ctx.placement(), + openfpga_ctx.clock_rr_lookup(), openfpga_ctx.clock_arch(), pin_constraints, cmd_context.option_enable(cmd, opt_disable_unused_trees), cmd_context.option_enable(cmd, opt_disable_unused_spines), diff --git a/openfpga/src/utils/openfpga_clustered_netlist_utils.cpp b/openfpga/src/utils/openfpga_clustered_netlist_utils.cpp new file mode 100644 index 000000000..e4823b873 --- /dev/null +++ b/openfpga/src/utils/openfpga_clustered_netlist_utils.cpp @@ -0,0 +1,35 @@ +/*************************************************************************************** + * This file includes most utilized functions that are used to acquire data from + * VPR clustered netlist (post-packing netlist) + ***************************************************************************************/ + +/* Headers from vtrutil library */ +#include "vtr_assert.h" +#include "vtr_log.h" +#include "vtr_time.h" + +/* Headers from vtrutil library */ +#include "openfpga_clustered_netlist_utils.h" + +/* begin namespace openfpga */ +namespace openfpga { + +/*************************************************************************************** + * Find the names of all the atom blocks that drive clock nets + * This function will find if the block has been renamed due to contain + *sensitive characters that violates the Verilog syntax + ***************************************************************************************/ +std::vector find_clustered_netlist_global_nets( + const ClusteredNetlist& clb_nlist) { + std::vector gnets; + + for (ClusterNetId net_id : clb_nlist.nets()) { + if (clb_nlist.net_is_ignored(net_id)) { + gnets.push_back(net_id); + } + } + + return gnets; +} + +} /* end namespace openfpga */ diff --git a/openfpga/src/utils/openfpga_clustered_netlist_utils.h b/openfpga/src/utils/openfpga_clustered_netlist_utils.h new file mode 100644 index 000000000..252bd99f4 --- /dev/null +++ b/openfpga/src/utils/openfpga_clustered_netlist_utils.h @@ -0,0 +1,24 @@ +#ifndef OPENFPGA_CLUSTERED_NETLIST_UTILS_H +#define OPENFPGA_CLUSTERED_NETLIST_UTILS_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include +#include + +#include "clustered_netlist.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ + +/* begin namespace openfpga */ +namespace openfpga { + +std::vector find_clustered_netlist_global_nets( + const ClusteredNetlist& clb_nlist); + +} /* end namespace openfpga */ + +#endif diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/pin_constraints_reset.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/pin_constraints_reset.xml index abcf209f6..3788a1411 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/pin_constraints_reset.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/pin_constraints_reset.xml @@ -3,5 +3,6 @@ - the reset signal to the op_reset[0] port of the FPGA fabric --> + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/pin_constraints_resetb.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/pin_constraints_resetb.xml index cdef2ad86..1311926f5 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/pin_constraints_resetb.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/pin_constraints_resetb.xml @@ -3,5 +3,6 @@ - the reset signal to the op_reset[0] port of the FPGA fabric --> + From 8bc37080fa492047b4231b21bafc71e62a9ab89e Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 28 Jun 2024 23:06:21 -0700 Subject: [PATCH 59/86] [core] debuggging --- openfpga/src/annotation/route_clock_rr_graph.cpp | 4 +++- .../clock_network/homo_1clock_1reset_2layer/config/task.conf | 4 ++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index 7b10262fa..01b780ed5 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -59,6 +59,7 @@ static int build_clock_tree_net_map( clk_ntwk.tree_width(clk_tree)); return CMD_EXEC_FATAL_ERROR; } + /* TODO: Check the tree_pin.get_name(), see if matches the tree from ports */ /* Register the pin mapping */ tree2clk_pin_map[ClockTreePinId(tree_pin.get_lsb())] = gnet; } @@ -457,7 +458,8 @@ int route_clock_rr_graph( const DeviceContext& vpr_device_ctx, const ClusteredNetlist& cluster_nlist, const PlacementContext& vpr_place_ctx, const RRClockSpatialLookup& clk_rr_lookup, const ClockNetwork& clk_ntwk, - const PinConstraints& pin_constraints, const bool& disable_unused_trees, + const PinConstraints& pin_constraints, + const bool& disable_unused_trees, const bool& disable_unused_spines, const bool& verbose) { vtr::ScopedStartFinishTimer timer( "Route programmable clock network based on routing resource graph"); diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/task.conf b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/task.conf index e6204e15a..04489c15e 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/task.conf +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/task.conf @@ -42,11 +42,11 @@ bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_df bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys;${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_rewrite_flow.ys bench0_top = counter -bench0_openfpga_pin_constraints_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/pin_constraints_reset.xml +bench0_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/pin_constraints_reset.xml bench0_openfpga_verilog_testbench_port_mapping= bench1_top = counter -bench1_openfpga_pin_constraints_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/pin_constraints_resetb.xml +bench1_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/pin_constraints_resetb.xml bench1_openfpga_verilog_testbench_port_mapping= [SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] From 67554cb8d84c0760b15c75ff93fc2ad4232c9918 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 29 Jun 2024 10:04:03 -0700 Subject: [PATCH 60/86] [test] now use correct pcf for clock network testcases --- .../config/pin_constraints_reset.xml | 1 + .../config/pin_constraints_resetb.xml | 1 + .../config/task.conf | 4 ++-- .../config/pin_constraints_reset.xml | 1 + .../config/pin_constraints_resetb.xml | 1 + .../config/task.conf | 4 ++-- 6 files changed, 8 insertions(+), 4 deletions(-) diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/pin_constraints_reset.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/pin_constraints_reset.xml index abcf209f6..3788a1411 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/pin_constraints_reset.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/pin_constraints_reset.xml @@ -3,5 +3,6 @@ - the reset signal to the op_reset[0] port of the FPGA fabric --> + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/pin_constraints_resetb.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/pin_constraints_resetb.xml index cdef2ad86..1311926f5 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/pin_constraints_resetb.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/pin_constraints_resetb.xml @@ -3,5 +3,6 @@ - the reset signal to the op_reset[0] port of the FPGA fabric --> + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/task.conf b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/task.conf index 50f4280f3..f0fe1b077 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/task.conf +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/task.conf @@ -42,11 +42,11 @@ bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_df bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys;${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_rewrite_flow.ys bench0_top = counter -bench0_openfpga_pin_constraints_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/pin_constraints_reset.xml +bench0_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/pin_constraints_reset.xml bench0_openfpga_verilog_testbench_port_mapping= bench1_top = counter -bench1_openfpga_pin_constraints_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/pin_constraints_resetb.xml +bench1_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/pin_constraints_resetb.xml bench1_openfpga_verilog_testbench_port_mapping= [SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/pin_constraints_reset.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/pin_constraints_reset.xml index abcf209f6..3788a1411 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/pin_constraints_reset.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/pin_constraints_reset.xml @@ -3,5 +3,6 @@ - the reset signal to the op_reset[0] port of the FPGA fabric --> + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/pin_constraints_resetb.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/pin_constraints_resetb.xml index cdef2ad86..1311926f5 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/pin_constraints_resetb.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/pin_constraints_resetb.xml @@ -3,5 +3,6 @@ - the reset signal to the op_reset[0] port of the FPGA fabric --> + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/task.conf b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/task.conf index a88b6c9b1..70565880f 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/task.conf +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/task.conf @@ -42,11 +42,11 @@ bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_df bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys;${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_rewrite_flow.ys bench0_top = counter -bench0_openfpga_pin_constraints_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/pin_constraints_reset.xml +bench0_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/pin_constraints_reset.xml bench0_openfpga_verilog_testbench_port_mapping= bench1_top = counter -bench1_openfpga_pin_constraints_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tasks/basic_tests/k4_series/k4n4_fracff/config/pin_constraints_resetb.xml +bench1_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/pin_constraints_resetb.xml bench1_openfpga_verilog_testbench_port_mapping= [SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] From 34fb00391116b68808385bf0f6b7bd3d81b4ba8e Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 29 Jun 2024 10:46:00 -0700 Subject: [PATCH 61/86] [core] replace width syntax with global port name --- libs/libclkarchopenfpga/arch/example.xml | 2 +- .../arch/example_internal_drivers.xml | 2 +- .../src/base/clock_network.cpp | 19 +++++++++++++++---- .../src/base/clock_network.h | 6 ++++-- .../src/io/clock_network_xml_constants.h | 2 +- .../src/io/read_xml_clock_network.cpp | 11 ++++++----- .../src/io/write_xml_clock_network.cpp | 4 ++-- 7 files changed, 30 insertions(+), 16 deletions(-) diff --git a/libs/libclkarchopenfpga/arch/example.xml b/libs/libclkarchopenfpga/arch/example.xml index 9cb31bdc6..9ba53a2f7 100644 --- a/libs/libclkarchopenfpga/arch/example.xml +++ b/libs/libclkarchopenfpga/arch/example.xml @@ -1,5 +1,5 @@ - + diff --git a/libs/libclkarchopenfpga/arch/example_internal_drivers.xml b/libs/libclkarchopenfpga/arch/example_internal_drivers.xml index 7a46a2094..6215ba443 100644 --- a/libs/libclkarchopenfpga/arch/example_internal_drivers.xml +++ b/libs/libclkarchopenfpga/arch/example_internal_drivers.xml @@ -1,5 +1,5 @@ - + diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index ed8e050e7..1d3ab5b47 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -217,9 +217,14 @@ size_t ClockNetwork::max_tree_depth() const { return max_size; } +BasicPort ClockNetwork::tree_global_port(const ClockTreeId& tree_id) const { + VTR_ASSERT(valid_tree_id(tree_id)); + return tree_global_ports_[tree_id]; +} + size_t ClockNetwork::tree_width(const ClockTreeId& tree_id) const { VTR_ASSERT(valid_tree_id(tree_id)); - return tree_widths_[tree_id]; + return tree_global_ports_[tree_id].get_width(); } size_t ClockNetwork::tree_depth(const ClockTreeId& tree_id) const { @@ -606,7 +611,7 @@ void ClockNetwork::reserve_spines(const size_t& num_spines) { void ClockNetwork::reserve_trees(const size_t& num_trees) { tree_ids_.reserve(num_trees); tree_names_.reserve(num_trees); - tree_widths_.reserve(num_trees); + tree_global_ports_.reserve(num_trees); tree_top_spines_.reserve(num_trees); tree_taps_.reserve(num_trees); } @@ -635,13 +640,19 @@ void ClockNetwork::set_default_driver_switch_name(const std::string& name) { default_driver_switch_name_ = name; } -ClockTreeId ClockNetwork::create_tree(const std::string& name, size_t width) { +ClockTreeId ClockNetwork::create_tree(const std::string& name, const BasicPort& global_port) { + /* Sanity checks */ + if (!global_port.is_valid()) { + VTR_LOG_ERROR("Invalid global port '%s' for clock tree name '%s'\n", + global_port.to_verilog_string().c_str(), name.c_str()); + exit(1); + } /* Create a new id */ ClockTreeId tree_id = ClockTreeId(tree_ids_.size()); tree_ids_.push_back(tree_id); tree_names_.push_back(name); - tree_widths_.push_back(width); + tree_global_ports_.push_back(global_port); tree_depths_.emplace_back(); tree_taps_.emplace_back(); tree_top_spines_.emplace_back(); diff --git a/libs/libclkarchopenfpga/src/base/clock_network.h b/libs/libclkarchopenfpga/src/base/clock_network.h index 2921340fd..7775b6fbf 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.h +++ b/libs/libclkarchopenfpga/src/base/clock_network.h @@ -16,6 +16,7 @@ #include "clock_network_fwd.h" #include "rr_graph_fwd.h" #include "rr_node_types.h" +#include "openfpga_port.h" namespace openfpga { // Begin namespace openfpga @@ -87,6 +88,7 @@ class ClockNetwork { RRSwitchId default_driver_switch() const; std::string default_driver_switch_name() const; std::string tree_name(const ClockTreeId& tree_id) const; + BasicPort tree_global_port(const ClockTreeId& tree_id) const; size_t tree_width(const ClockTreeId& tree_id) const; size_t tree_depth(const ClockTreeId& tree_id) const; size_t max_tree_width() const; @@ -196,7 +198,7 @@ class ClockNetwork { void set_default_driver_switch_name(const std::string& name); /* 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, size_t width = 1); + ClockTreeId create_tree(const std::string& name, const BasicPort& global_port); /* Create a new spine, if the spine is already created, return an invalid id */ ClockSpineId create_spine(const std::string& name); @@ -289,7 +291,7 @@ class ClockNetwork { /* Basic information of each tree */ vtr::vector tree_ids_; vtr::vector tree_names_; - vtr::vector tree_widths_; + vtr::vector tree_global_ports_; vtr::vector tree_depths_; vtr::vector> tree_top_spines_; vtr::vector> tree_taps_; diff --git a/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h b/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h index cfa5c306d..a63141870 100644 --- a/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h +++ b/libs/libclkarchopenfpga/src/io/clock_network_xml_constants.h @@ -12,7 +12,7 @@ constexpr const char* XML_CLOCK_NETWORK_ATTRIBUTE_DEFAULT_DRIVER_SWITCH = "default_driver_switch"; constexpr const char* XML_CLOCK_TREE_NODE_NAME = "clock_network"; constexpr const char* XML_CLOCK_TREE_ATTRIBUTE_NAME = "name"; -constexpr const char* XML_CLOCK_TREE_ATTRIBUTE_WIDTH = "width"; +constexpr const char* XML_CLOCK_TREE_ATTRIBUTE_GLOBAL_PORT = "global_port"; constexpr const char* XML_CLOCK_SPINE_NODE_NAME = "spine"; constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_NAME = "name"; constexpr const char* XML_CLOCK_SPINE_ATTRIBUTE_START_X = "start_x"; diff --git a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp index 492649788..84aea0587 100644 --- a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp @@ -338,14 +338,15 @@ static void read_xml_clock_tree(pugi::xml_node& xml_clk_tree, const pugiutil::loc_data& loc_data, ClockNetwork& clk_ntwk) { std::string clk_tree_name = - get_attribute(xml_clk_tree, XML_CLOCK_TREE_ATTRIBUTE_NAME, loc_data) + get_attribute(xml_clk_tree, XML_CLOCK_TREE_ATTRIBUTE_NAME, loc_data, pugiutil::ReqOpt::REQUIRED) + .as_string(); + std::string clk_global_port_str = + get_attribute(xml_clk_tree, XML_CLOCK_TREE_ATTRIBUTE_GLOBAL_PORT, loc_data, pugiutil::ReqOpt::REQUIRED) .as_string(); - int clk_tree_width = - get_attribute(xml_clk_tree, XML_CLOCK_TREE_ATTRIBUTE_WIDTH, loc_data) - .as_int(); /* Create a new tree in the storage */ - ClockTreeId tree_id = clk_ntwk.create_tree(clk_tree_name, clk_tree_width); + PortParser gport_parser(clk_global_port_str); + ClockTreeId tree_id = clk_ntwk.create_tree(clk_tree_name, gport_parser.port()); if (false == clk_ntwk.valid_tree_id(tree_id)) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_clk_tree), diff --git a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp index cdcc12ecf..5ef8e4d3d 100644 --- a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp @@ -194,8 +194,8 @@ static int write_xml_clock_tree(std::fstream& fp, const ClockNetwork& clk_ntwk, 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)); + write_xml_attribute(fp, XML_CLOCK_TREE_ATTRIBUTE_GLOBAL_PORT, + clk_ntwk.tree_global_port(tree_id).to_verilog_string().c_str()); fp << ">" << "\n"; From 5fa674be24157bed2d88bb2f8f764914994b61ff Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 29 Jun 2024 10:51:45 -0700 Subject: [PATCH 62/86] [core] fixed the bug on matching global net from pcf --- openfpga/src/annotation/route_clock_rr_graph.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index 01b780ed5..8918f0b2b 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -24,6 +24,7 @@ static int build_clock_tree_net_map( const ClusteredNetlist& cluster_nlist, const PinConstraints& pin_constraints, const std::vector& gnets, const ClockNetwork& clk_ntwk, const ClockTreeId clk_tree, const bool& verbose) { + BasicPort tree_gport = clk_ntwk.tree_global_port(clk_tree); /* Find the pin id for each clock name, error out if there is any mismatch */ if (clk_ntwk.num_trees() == 1 && gnets.size() == 1 && clk_ntwk.tree_width(clk_tree) == 1) { /* Find cluster net id */ @@ -37,6 +38,7 @@ static int build_clock_tree_net_map( for (ClusterNetId gnet : gnets) { /* Find the pin information that the net should be mapped to */ std::string gnet_name = cluster_nlist.net_name(gnet); + /* The pin should match be global port name of the tree */ BasicPort tree_pin = pin_constraints.net_pin(gnet_name); if (!tree_pin.is_valid()) { VTR_LOG_ERROR( @@ -52,11 +54,15 @@ static int build_clock_tree_net_map( gnet_name.c_str()); return CMD_EXEC_FATAL_ERROR; } - if (tree_pin.get_lsb() >= clk_ntwk.tree_width(clk_tree)) { + if (tree_gport.get_name() != tree_pin.get_name()) { + continue; + } + if (!tree_gport.contained(tree_pin)) { VTR_LOG_ERROR( - "Invalid tree pin %s[%lu] is out of range of clock tree size '%lu'\n", - tree_pin.get_name().c_str(), tree_pin.get_lsb(), - clk_ntwk.tree_width(clk_tree)); + "Invalid pin constraint port '%s' which is out of range of the global port '%s' of clock tree '%s'\n", + tree_pin.to_verilog_string().c_str(), + tree_gport.to_verilog_string().c_str(), + clk_ntwk.tree_name(clk_tree).c_str()); return CMD_EXEC_FATAL_ERROR; } /* TODO: Check the tree_pin.get_name(), see if matches the tree from ports */ From 4f787a5cfc5545539d62fb591c93357069299f92 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 29 Jun 2024 10:54:08 -0700 Subject: [PATCH 63/86] [core] add more debugging message --- openfpga/src/annotation/route_clock_rr_graph.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index 8918f0b2b..fb4afda93 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -68,6 +68,8 @@ static int build_clock_tree_net_map( /* TODO: Check the tree_pin.get_name(), see if matches the tree from ports */ /* Register the pin mapping */ tree2clk_pin_map[ClockTreePinId(tree_pin.get_lsb())] = gnet; + VTR_LOGV(verbose, "Mapped net '%s' to pin '%s' of clock tree '%s'.\n", + gnet_name.c_str(), tree_pin.to_verilog_string().c_str(), clk_ntwk.tree_name(clk_tree).c_str()); } } From 286df309471a73934e1b6b778f5a33fe1a20c218 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 29 Jun 2024 11:02:17 -0700 Subject: [PATCH 64/86] [test] update clock arch xml syntax --- .../config/clk_arch_1clk_1rst_2layer.xml | 8 ++++---- .../config/clk_arch_1clk_1rst_2layer.xml | 8 ++++---- .../config/clk_arch_1clk_1rst_2layer_int_driver.xml | 8 ++++---- .../homo_1clock_2layer/config/clk_arch_1clk_2layer.xml | 2 +- .../config/clk_arch_1clk_2layer.xml | 2 +- .../homo_2clock_2layer/config/clk_arch_2clk_2layer.xml | 2 +- .../config/clk_arch_2clk_2layer.xml | 2 +- .../config/clk_arch_2clk_2layer.xml | 2 +- 8 files changed, 17 insertions(+), 17 deletions(-) diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/clk_arch_1clk_1rst_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/clk_arch_1clk_1rst_2layer.xml index 6c05921c7..3f499fedf 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/clk_arch_1clk_1rst_2layer.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/clk_arch_1clk_1rst_2layer.xml @@ -1,5 +1,5 @@ - + @@ -11,10 +11,10 @@ - + - + @@ -26,7 +26,7 @@ - + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/clk_arch_1clk_1rst_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/clk_arch_1clk_1rst_2layer.xml index 6c05921c7..3f499fedf 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/clk_arch_1clk_1rst_2layer.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines/config/clk_arch_1clk_1rst_2layer.xml @@ -1,5 +1,5 @@ - + @@ -11,10 +11,10 @@ - + - + @@ -26,7 +26,7 @@ - + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/clk_arch_1clk_1rst_2layer_int_driver.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/clk_arch_1clk_1rst_2layer_int_driver.xml index ed43a26b5..c88e8ccd4 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/clk_arch_1clk_1rst_2layer_int_driver.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver/config/clk_arch_1clk_1rst_2layer_int_driver.xml @@ -1,5 +1,5 @@ - + @@ -19,10 +19,10 @@ - + - + @@ -34,7 +34,7 @@ - + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer/config/clk_arch_1clk_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer/config/clk_arch_1clk_2layer.xml index 7a41f1216..6f289dbf4 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer/config/clk_arch_1clk_2layer.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer/config/clk_arch_1clk_2layer.xml @@ -1,5 +1,5 @@ - + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer_full_tb/config/clk_arch_1clk_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer_full_tb/config/clk_arch_1clk_2layer.xml index 7a41f1216..6f289dbf4 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer_full_tb/config/clk_arch_1clk_2layer.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_2layer_full_tb/config/clk_arch_1clk_2layer.xml @@ -1,5 +1,5 @@ - + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/clk_arch_2clk_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/clk_arch_2clk_2layer.xml index 8c224318c..98e91d27a 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/clk_arch_2clk_2layer.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/clk_arch_2clk_2layer.xml @@ -1,5 +1,5 @@ - + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/clk_arch_2clk_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/clk_arch_2clk_2layer.xml index 8c224318c..98e91d27a 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/clk_arch_2clk_2layer.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/clk_arch_2clk_2layer.xml @@ -1,5 +1,5 @@ - + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/clk_arch_2clk_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/clk_arch_2clk_2layer.xml index 8c224318c..98e91d27a 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/clk_arch_2clk_2layer.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/clk_arch_2clk_2layer.xml @@ -1,5 +1,5 @@ - + From bc2f02866d056aa6dea27260d98c26a2d75a3cd2 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 29 Jun 2024 17:17:05 -0700 Subject: [PATCH 65/86] [test] update testcase for 2-clk on programmable clock network --- .../openfpga_arch/k4_N4_40nm_Ntwk2clk2lvl_cc_openfpga.xml | 4 ++-- .../homo_2clock_2layer/config/clk_arch_2clk_2layer.xml | 4 ++-- openfpga_flow/vpr_arch/k4_N4_tileable_Ntwk2clk2lvl_40nm.xml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_Ntwk2clk2lvl_cc_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_Ntwk2clk2lvl_cc_openfpga.xml index 90109d00b..66aa9b4b3 100644 --- a/openfpga_flow/openfpga_arch/k4_N4_40nm_Ntwk2clk2lvl_cc_openfpga.xml +++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_Ntwk2clk2lvl_cc_openfpga.xml @@ -173,8 +173,8 @@ - - + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/clk_arch_2clk_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/clk_arch_2clk_2layer.xml index 98e91d27a..ff5734d10 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/clk_arch_2clk_2layer.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/clk_arch_2clk_2layer.xml @@ -11,8 +11,8 @@ - - + + diff --git a/openfpga_flow/vpr_arch/k4_N4_tileable_Ntwk2clk2lvl_40nm.xml b/openfpga_flow/vpr_arch/k4_N4_tileable_Ntwk2clk2lvl_40nm.xml index f4e40b275..231aef08b 100644 --- a/openfpga_flow/vpr_arch/k4_N4_tileable_Ntwk2clk2lvl_40nm.xml +++ b/openfpga_flow/vpr_arch/k4_N4_tileable_Ntwk2clk2lvl_40nm.xml @@ -59,7 +59,7 @@ - + @@ -250,7 +250,7 @@ - + From 5dd0549aed60c162dc1150aa270821104f995a12 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 29 Jun 2024 17:17:54 -0700 Subject: [PATCH 66/86] [core] typo --- .../homo_2clock_2layer/config/clk_arch_2clk_2layer.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/clk_arch_2clk_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/clk_arch_2clk_2layer.xml index ff5734d10..3ef33c270 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/clk_arch_2clk_2layer.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/clk_arch_2clk_2layer.xml @@ -11,8 +11,8 @@ - - + + From 1fd974d544ef421a1cc087c889031e0ab84600f9 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 29 Jun 2024 17:35:47 -0700 Subject: [PATCH 67/86] [core] fixed a bug where clock network size cannot impact global port on top module --- libs/libarchopenfpga/src/tile_annotation.cpp | 6 +++++ libs/libarchopenfpga/src/tile_annotation.h | 2 ++ .../fabric/build_top_module_connection.cpp | 24 ++++++++++++------- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/libs/libarchopenfpga/src/tile_annotation.cpp b/libs/libarchopenfpga/src/tile_annotation.cpp index 2ffacd1d0..c6c71c4b2 100644 --- a/libs/libarchopenfpga/src/tile_annotation.cpp +++ b/libs/libarchopenfpga/src/tile_annotation.cpp @@ -96,6 +96,12 @@ size_t TileAnnotation::global_port_default_value( return global_port_default_values_[global_port_id]; } +bool TileAnnotation::global_port_thru_dedicated_network( + const TileGlobalPortId& global_port_id) const { + return !global_port_clock_arch_tree_name(global_port_id).empty(); +} + + std::string TileAnnotation::global_port_clock_arch_tree_name( const TileGlobalPortId& global_port_id) const { VTR_ASSERT(valid_global_port_id(global_port_id)); diff --git a/libs/libarchopenfpga/src/tile_annotation.h b/libs/libarchopenfpga/src/tile_annotation.h index 36af8a9b4..f2f3f3d75 100644 --- a/libs/libarchopenfpga/src/tile_annotation.h +++ b/libs/libarchopenfpga/src/tile_annotation.h @@ -54,6 +54,8 @@ class TileAnnotation { bool global_port_is_clock(const TileGlobalPortId& global_port_id) const; bool global_port_is_set(const TileGlobalPortId& global_port_id) const; bool global_port_is_reset(const TileGlobalPortId& global_port_id) const; + bool global_port_thru_dedicated_network( + const TileGlobalPortId& global_port_id) const; std::string global_port_clock_arch_tree_name( const TileGlobalPortId& global_port_id) const; size_t global_port_default_value( diff --git a/openfpga/src/fabric/build_top_module_connection.cpp b/openfpga/src/fabric/build_top_module_connection.cpp index 84c901945..e0c86ab17 100644 --- a/openfpga/src/fabric/build_top_module_connection.cpp +++ b/openfpga/src/fabric/build_top_module_connection.cpp @@ -1242,11 +1242,11 @@ static int build_top_module_global_net_from_clock_arch_tree( if (clk_ntwk.tree_width(clk_tree) != module_manager.module_port(top_module, top_module_port).get_width()) { VTR_LOG( - "Clock tree '%s' does not have the same width '%lu' as the port '%'s of " + "Clock tree '%s' does not have the same width '%lu' as the port '%s' of " "FPGA top module", clk_tree_name.c_str(), clk_ntwk.tree_width(clk_tree), module_manager.module_port(top_module, top_module_port) - .get_name() + .to_verilog_string() .c_str()); return CMD_EXEC_FATAL_ERROR; } @@ -1323,12 +1323,19 @@ int add_top_module_global_ports_from_grid_modules( BasicPort global_port_to_add; global_port_to_add.set_name( tile_annotation.global_port_name(tile_global_port)); - size_t max_port_size = 0; - for (const BasicPort& tile_port : - tile_annotation.global_port_tile_ports(tile_global_port)) { - max_port_size = std::max(tile_port.get_width(), max_port_size); + /* Dedicated network has their own sizes of port */ + if (tile_annotation.global_port_thru_dedicated_network(tile_global_port)) { + std::string clk_tree_name = tile_annotation.global_port_clock_arch_tree_name(tile_global_port); + ClockTreeId clk_tree = clk_ntwk.find_tree(clk_tree_name); + global_port_to_add.set_width(clk_ntwk.tree_width(clk_tree)); + } else { + size_t max_port_size = 0; + for (const BasicPort& tile_port : + tile_annotation.global_port_tile_ports(tile_global_port)) { + max_port_size = std::max(tile_port.get_width(), max_port_size); + } + global_port_to_add.set_width(max_port_size); } - global_port_to_add.set_width(max_port_size); global_ports_to_add.push_back(global_port_to_add); } } @@ -1352,8 +1359,7 @@ int add_top_module_global_ports_from_grid_modules( * - If the net will be directly wired to tiles, the net will drive an input * of a tile */ - if (!tile_annotation.global_port_clock_arch_tree_name(tile_global_port) - .empty()) { + if (tile_annotation.global_port_thru_dedicated_network(tile_global_port)) { status = build_top_module_global_net_from_clock_arch_tree( module_manager, top_module, top_module_port, rr_graph, device_rr_gsb, cb_instance_ids, clk_ntwk, From 12c9686c27d99fb460bfd9ad9bd3bac6b33a42ab Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 29 Jun 2024 17:38:34 -0700 Subject: [PATCH 68/86] [test] fixed some bugs on arch --- .../openfpga_arch/k4_N4_40nm_Ntwk2clk2lvl_cc_openfpga.xml | 2 +- .../homo_2clock_2layer/config/repack_constraints.xml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_Ntwk2clk2lvl_cc_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_Ntwk2clk2lvl_cc_openfpga.xml index 66aa9b4b3..91dd34815 100644 --- a/openfpga_flow/openfpga_arch/k4_N4_40nm_Ntwk2clk2lvl_cc_openfpga.xml +++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_Ntwk2clk2lvl_cc_openfpga.xml @@ -173,7 +173,7 @@ - + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/repack_constraints.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/repack_constraints.xml index eb0c4435a..f32f6afde 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/repack_constraints.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer/config/repack_constraints.xml @@ -1,5 +1,4 @@ - From 28e3cb799e3b2eaa2a429b3148686f0ddb5c42cf Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 29 Jun 2024 17:40:20 -0700 Subject: [PATCH 69/86] [test] update 2-clock arch and pcf --- .../config/clk_arch_2clk_2layer.xml | 2 +- .../config/repack_constraints.xml | 1 - .../config/clk_arch_2clk_2layer.xml | 2 +- .../config/repack_constraints.xml | 1 - 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/clk_arch_2clk_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/clk_arch_2clk_2layer.xml index 98e91d27a..3ef33c270 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/clk_arch_2clk_2layer.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/clk_arch_2clk_2layer.xml @@ -12,7 +12,7 @@ - + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/repack_constraints.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/repack_constraints.xml index eb0c4435a..f32f6afde 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/repack_constraints.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused/config/repack_constraints.xml @@ -1,5 +1,4 @@ - diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/clk_arch_2clk_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/clk_arch_2clk_2layer.xml index 98e91d27a..3ef33c270 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/clk_arch_2clk_2layer.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/clk_arch_2clk_2layer.xml @@ -12,7 +12,7 @@ - + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/repack_constraints.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/repack_constraints.xml index eb0c4435a..f32f6afde 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/repack_constraints.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree/config/repack_constraints.xml @@ -1,5 +1,4 @@ - From 3afb92d6a5f5c92294fbdf0481eb732086473f9a Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 30 Jun 2024 22:48:15 -0700 Subject: [PATCH 70/86] [core] code format --- libs/libarchopenfpga/src/tile_annotation.cpp | 1 - .../src/base/clock_network.cpp | 3 +- .../src/base/clock_network.h | 5 +- .../src/io/read_xml_clock_network.cpp | 11 +++-- .../src/io/write_xml_clock_network.cpp | 5 +- .../src/annotation/route_clock_rr_graph.cpp | 49 ++++++++++++------- .../src/annotation/route_clock_rr_graph.h | 4 +- .../src/base/openfpga_link_arch_template.h | 3 +- .../fabric/build_top_module_connection.cpp | 6 ++- 9 files changed, 52 insertions(+), 35 deletions(-) diff --git a/libs/libarchopenfpga/src/tile_annotation.cpp b/libs/libarchopenfpga/src/tile_annotation.cpp index c6c71c4b2..77adcff18 100644 --- a/libs/libarchopenfpga/src/tile_annotation.cpp +++ b/libs/libarchopenfpga/src/tile_annotation.cpp @@ -101,7 +101,6 @@ bool TileAnnotation::global_port_thru_dedicated_network( return !global_port_clock_arch_tree_name(global_port_id).empty(); } - std::string TileAnnotation::global_port_clock_arch_tree_name( const TileGlobalPortId& global_port_id) const { VTR_ASSERT(valid_global_port_id(global_port_id)); diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index 1d3ab5b47..6f254530b 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -640,7 +640,8 @@ void ClockNetwork::set_default_driver_switch_name(const std::string& name) { default_driver_switch_name_ = name; } -ClockTreeId ClockNetwork::create_tree(const std::string& name, const BasicPort& global_port) { +ClockTreeId ClockNetwork::create_tree(const std::string& name, + const BasicPort& global_port) { /* Sanity checks */ if (!global_port.is_valid()) { VTR_LOG_ERROR("Invalid global port '%s' for clock tree name '%s'\n", diff --git a/libs/libclkarchopenfpga/src/base/clock_network.h b/libs/libclkarchopenfpga/src/base/clock_network.h index 7775b6fbf..242720dce 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.h +++ b/libs/libclkarchopenfpga/src/base/clock_network.h @@ -14,9 +14,9 @@ /* Headers from openfpgautil library */ #include "clock_network_fwd.h" +#include "openfpga_port.h" #include "rr_graph_fwd.h" #include "rr_node_types.h" -#include "openfpga_port.h" namespace openfpga { // Begin namespace openfpga @@ -198,7 +198,8 @@ class ClockNetwork { void set_default_driver_switch_name(const std::string& name); /* 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 BasicPort& global_port); + ClockTreeId create_tree(const std::string& name, + const BasicPort& global_port); /* Create a new spine, if the spine is already created, return an invalid id */ ClockSpineId create_spine(const std::string& name); diff --git a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp index 84aea0587..4d47ad18e 100644 --- a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp @@ -338,15 +338,18 @@ static void read_xml_clock_tree(pugi::xml_node& xml_clk_tree, const pugiutil::loc_data& loc_data, ClockNetwork& clk_ntwk) { std::string clk_tree_name = - get_attribute(xml_clk_tree, XML_CLOCK_TREE_ATTRIBUTE_NAME, loc_data, pugiutil::ReqOpt::REQUIRED) + get_attribute(xml_clk_tree, XML_CLOCK_TREE_ATTRIBUTE_NAME, loc_data, + pugiutil::ReqOpt::REQUIRED) .as_string(); std::string clk_global_port_str = - get_attribute(xml_clk_tree, XML_CLOCK_TREE_ATTRIBUTE_GLOBAL_PORT, loc_data, pugiutil::ReqOpt::REQUIRED) + get_attribute(xml_clk_tree, XML_CLOCK_TREE_ATTRIBUTE_GLOBAL_PORT, loc_data, + pugiutil::ReqOpt::REQUIRED) .as_string(); /* Create a new tree in the storage */ - PortParser gport_parser(clk_global_port_str); - ClockTreeId tree_id = clk_ntwk.create_tree(clk_tree_name, gport_parser.port()); + PortParser gport_parser(clk_global_port_str); + ClockTreeId tree_id = + clk_ntwk.create_tree(clk_tree_name, gport_parser.port()); if (false == clk_ntwk.valid_tree_id(tree_id)) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_clk_tree), diff --git a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp index 5ef8e4d3d..3473a6350 100644 --- a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp @@ -194,8 +194,9 @@ static int write_xml_clock_tree(std::fstream& fp, const ClockNetwork& clk_ntwk, 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_GLOBAL_PORT, - clk_ntwk.tree_global_port(tree_id).to_verilog_string().c_str()); + write_xml_attribute( + fp, XML_CLOCK_TREE_ATTRIBUTE_GLOBAL_PORT, + clk_ntwk.tree_global_port(tree_id).to_verilog_string().c_str()); fp << ">" << "\n"; diff --git a/openfpga/src/annotation/route_clock_rr_graph.cpp b/openfpga/src/annotation/route_clock_rr_graph.cpp index fb4afda93..0be7cdf84 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.cpp +++ b/openfpga/src/annotation/route_clock_rr_graph.cpp @@ -26,7 +26,8 @@ static int build_clock_tree_net_map( const ClockTreeId clk_tree, const bool& verbose) { BasicPort tree_gport = clk_ntwk.tree_global_port(clk_tree); /* Find the pin id for each clock name, error out if there is any mismatch */ - if (clk_ntwk.num_trees() == 1 && gnets.size() == 1 && clk_ntwk.tree_width(clk_tree) == 1) { + if (clk_ntwk.num_trees() == 1 && gnets.size() == 1 && + clk_ntwk.tree_width(clk_tree) == 1) { /* Find cluster net id */ if (!cluster_nlist.valid_net_id(gnets[0])) { VTR_LOG_ERROR("Invalid clock name '%s'! Cannot be found from netlists!\n", @@ -42,7 +43,8 @@ static int build_clock_tree_net_map( BasicPort tree_pin = pin_constraints.net_pin(gnet_name); if (!tree_pin.is_valid()) { VTR_LOG_ERROR( - "Global net '%s' is not mapped to a valid pin '%s' in pin constraints!\n", + "Global net '%s' is not mapped to a valid pin '%s' in pin " + "constraints!\n", gnet_name.c_str(), tree_pin.to_verilog_string().c_str()); return CMD_EXEC_FATAL_ERROR; } @@ -59,17 +61,20 @@ static int build_clock_tree_net_map( } if (!tree_gport.contained(tree_pin)) { VTR_LOG_ERROR( - "Invalid pin constraint port '%s' which is out of range of the global port '%s' of clock tree '%s'\n", + "Invalid pin constraint port '%s' which is out of range of the " + "global port '%s' of clock tree '%s'\n", tree_pin.to_verilog_string().c_str(), tree_gport.to_verilog_string().c_str(), clk_ntwk.tree_name(clk_tree).c_str()); return CMD_EXEC_FATAL_ERROR; } - /* TODO: Check the tree_pin.get_name(), see if matches the tree from ports */ + /* TODO: Check the tree_pin.get_name(), see if matches the tree from ports + */ /* Register the pin mapping */ tree2clk_pin_map[ClockTreePinId(tree_pin.get_lsb())] = gnet; VTR_LOGV(verbose, "Mapped net '%s' to pin '%s' of clock tree '%s'.\n", - gnet_name.c_str(), tree_pin.to_verilog_string().c_str(), clk_ntwk.tree_name(clk_tree).c_str()); + gnet_name.c_str(), tree_pin.to_verilog_string().c_str(), + clk_ntwk.tree_name(clk_tree).c_str()); } } @@ -186,8 +191,10 @@ static int route_spine_taps( size_t spine_tap_cnt = 0; /* Route the spine-to-IPIN connections (only for the last level) */ if (clk_ntwk.is_last_level(ispine)) { - VTR_LOGV(verbose, "Routing clock taps of spine '%s' for pin '%d' of tree '%s'...\n", - clk_ntwk.spine_name(ispine).c_str(), size_t(ipin), clk_ntwk.tree_name(clk_tree).c_str()); + VTR_LOGV(verbose, + "Routing clock taps of spine '%s' for pin '%d' of tree '%s'...\n", + clk_ntwk.spine_name(ispine).c_str(), size_t(ipin), + clk_ntwk.tree_name(clk_tree).c_str()); /* Connect to any fan-out node which is IPIN */ for (size_t icoord = 0; icoord < spine_coords.size(); ++icoord) { vtr::Point src_coord = spine_coords[icoord]; @@ -397,11 +404,13 @@ static int rec_expand_and_route_clock_spine( src_coord.y(), des_coord.x(), des_coord.y()); vpr_routing_annotation.set_rr_node_prev_node(rr_graph, des_node, src_node); /* It could happen that there is no net mapped some clock pin, skip the - * net mapping */ - if (tree2clk_pin_map.find(curr_pin) != tree2clk_pin_map.end()) { - vpr_routing_annotation.set_rr_node_net(src_node, tree2clk_pin_map.at(curr_pin)); - vpr_routing_annotation.set_rr_node_net(des_node, tree2clk_pin_map.at(curr_pin)); - } + * net mapping */ + if (tree2clk_pin_map.find(curr_pin) != tree2clk_pin_map.end()) { + vpr_routing_annotation.set_rr_node_net(src_node, + tree2clk_pin_map.at(curr_pin)); + vpr_routing_annotation.set_rr_node_net(des_node, + tree2clk_pin_map.at(curr_pin)); + } prev_stop_usage = true; curr_spine_usage = true; @@ -463,11 +472,10 @@ static int route_clock_tree_rr_graph( *******************************************************************/ int route_clock_rr_graph( VprRoutingAnnotation& vpr_routing_annotation, - const DeviceContext& vpr_device_ctx, - const ClusteredNetlist& cluster_nlist, const PlacementContext& vpr_place_ctx, + const DeviceContext& vpr_device_ctx, const ClusteredNetlist& cluster_nlist, + const PlacementContext& vpr_place_ctx, const RRClockSpatialLookup& clk_rr_lookup, const ClockNetwork& clk_ntwk, - const PinConstraints& pin_constraints, - const bool& disable_unused_trees, + const PinConstraints& pin_constraints, const bool& disable_unused_trees, const bool& disable_unused_spines, const bool& verbose) { vtr::ScopedStartFinishTimer timer( "Route programmable clock network based on routing resource graph"); @@ -482,10 +490,12 @@ int route_clock_rr_graph( /* If there are multiple global signals from the netlist, require pin * constraints */ - std::vector gnets = find_clustered_netlist_global_nets(cluster_nlist); + std::vector gnets = + find_clustered_netlist_global_nets(cluster_nlist); if (gnets.empty()) { VTR_LOG( - "Skip due to 0 global nets found from netlist\nDouble check your HDL design " + "Skip due to 0 global nets found from netlist\nDouble check your HDL " + "design " "if this is unexpected\n"); return CMD_EXEC_SUCCESS; } @@ -504,7 +514,8 @@ int route_clock_rr_graph( /* Route spines one by one */ for (auto itree : clk_ntwk.trees()) { - VTR_LOGV(verbose, "Build global net name to clock tree '%s' pin mapping...\n", + VTR_LOGV(verbose, + "Build global net name to clock tree '%s' pin mapping...\n", clk_ntwk.tree_name(itree).c_str()); std::map tree2clk_pin_map; int status = CMD_EXEC_SUCCESS; diff --git a/openfpga/src/annotation/route_clock_rr_graph.h b/openfpga/src/annotation/route_clock_rr_graph.h index 443e3d11b..2bd4ec178 100644 --- a/openfpga/src/annotation/route_clock_rr_graph.h +++ b/openfpga/src/annotation/route_clock_rr_graph.h @@ -19,8 +19,8 @@ namespace openfpga { int route_clock_rr_graph( VprRoutingAnnotation& vpr_routing_annotation, - const DeviceContext& vpr_device_ctx, - const ClusteredNetlist& cluster_nlist, const PlacementContext& vpr_place_ctx, + const DeviceContext& vpr_device_ctx, const ClusteredNetlist& cluster_nlist, + const PlacementContext& vpr_place_ctx, const RRClockSpatialLookup& clk_rr_lookup, const ClockNetwork& clk_ntwk, const PinConstraints& pin_constraints, const bool& disable_unused_trees, const bool& disable_unused_spines, const bool& verbose); diff --git a/openfpga/src/base/openfpga_link_arch_template.h b/openfpga/src/base/openfpga_link_arch_template.h index cfb5b430f..bb061de09 100644 --- a/openfpga/src/base/openfpga_link_arch_template.h +++ b/openfpga/src/base/openfpga_link_arch_template.h @@ -234,8 +234,7 @@ int route_clock_rr_graph_template(T& openfpga_ctx, const Command& cmd, return route_clock_rr_graph( openfpga_ctx.mutable_vpr_routing_annotation(), g_vpr_ctx.device(), g_vpr_ctx.clustering().clb_nlist, g_vpr_ctx.placement(), - openfpga_ctx.clock_rr_lookup(), - openfpga_ctx.clock_arch(), pin_constraints, + openfpga_ctx.clock_rr_lookup(), openfpga_ctx.clock_arch(), pin_constraints, cmd_context.option_enable(cmd, opt_disable_unused_trees), cmd_context.option_enable(cmd, opt_disable_unused_spines), cmd_context.option_enable(cmd, opt_verbose)); diff --git a/openfpga/src/fabric/build_top_module_connection.cpp b/openfpga/src/fabric/build_top_module_connection.cpp index e0c86ab17..e6a98cd46 100644 --- a/openfpga/src/fabric/build_top_module_connection.cpp +++ b/openfpga/src/fabric/build_top_module_connection.cpp @@ -1324,8 +1324,10 @@ int add_top_module_global_ports_from_grid_modules( global_port_to_add.set_name( tile_annotation.global_port_name(tile_global_port)); /* Dedicated network has their own sizes of port */ - if (tile_annotation.global_port_thru_dedicated_network(tile_global_port)) { - std::string clk_tree_name = tile_annotation.global_port_clock_arch_tree_name(tile_global_port); + if (tile_annotation.global_port_thru_dedicated_network( + tile_global_port)) { + std::string clk_tree_name = + tile_annotation.global_port_clock_arch_tree_name(tile_global_port); ClockTreeId clk_tree = clk_ntwk.find_tree(clk_tree_name); global_port_to_add.set_width(clk_ntwk.tree_width(clk_tree)); } else { From 18e2b994ac88497ba568ddf156c2cb8bb87b1aab Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 30 Jun 2024 22:56:31 -0700 Subject: [PATCH 71/86] [doc] update syntax on clock network file --- docs/source/manual/arch_lang/annotate_vpr_arch.rst | 3 +++ docs/source/manual/file_formats/clock_network.rst | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/docs/source/manual/arch_lang/annotate_vpr_arch.rst b/docs/source/manual/arch_lang/annotate_vpr_arch.rst index 9fd1024a7..cd119f69a 100644 --- a/docs/source/manual/arch_lang/annotate_vpr_arch.rst +++ b/docs/source/manual/arch_lang/annotate_vpr_arch.rst @@ -79,6 +79,7 @@ For subtile port merge support (see an illustrative example in :numref:`fig_subt .. note:: When defined, the given port of all the subtiles of a tile will be merged into one port. For example, a tile consists of 8 subtile ``A`` and 6 subtile ``B`` and all the subtiles have a port ``clk``, in the FPGA fabric, all the ``clk`` of the subtiles ``A`` and ``B`` will be wired to a common port ``clk`` at tile level. +.. note:: Note that when a dedicated clock network is defined, the size of the global port will follow the ``global_port`` defined in the clock network description file (See details in :ref:`file_formats_clock_network`) .. note:: When merged, the port will have a default side of ``TOP`` and index of ``0`` on all the attributes, such as width, height etc. @@ -99,6 +100,8 @@ For global port support: - ``clock_arch_tree_name=""`` defines the name of the programmable clock network, which the global port will drive. The name of the programmable clock network must be a valid name (See details in :ref:`file_formats_clock_network`) +.. note:: ``clock_arch_tree_name`` is applicable to clock, reset and set signals. + - ``is_reset=""`` define if the global port is a reset port at the top-level FPGA fabric. An operating reset port will be driven by proper signals in testbenches. - ``is_set=""`` define if the global port is a set port at the top-level FPGA fabric. An operating set port will be driven by proper signals in testbenches. diff --git a/docs/source/manual/file_formats/clock_network.rst b/docs/source/manual/file_formats/clock_network.rst index da359f400..5979c2f24 100644 --- a/docs/source/manual/file_formats/clock_network.rst +++ b/docs/source/manual/file_formats/clock_network.rst @@ -23,7 +23,7 @@ Using the clock network description language, users can define multiple clock ne .. code-block:: xml - + @@ -107,9 +107,9 @@ where the clock network is used to drive the global clock pin ``clk0`` in OpenFP -.. option:: width="" +.. option:: global_port="" - The maximum number of clock pins that a clock network can drive. + Define the source port of the clock network. For example, ``clk[0:7]``. Note that the global port name should match the ``from_pin`` when defining the tap points (See details in :ref:`file_formats_clock_network_clock_tap_point`). .. _file_formats_clock_network_clock_spine: From 7c487eadc90a38381cef980326154b315e4403f9 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 1 Jul 2024 16:58:23 -0700 Subject: [PATCH 72/86] [core] now clock network keep port info in a native data structure --- libs/libclkarchopenfpga/src/base/clock_network.cpp | 12 +++++------- libs/libclkarchopenfpga/src/base/clock_network.h | 6 +++--- .../src/io/read_xml_clock_network.cpp | 9 ++++++--- .../src/io/write_xml_clock_network.cpp | 6 +++--- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index 6f254530b..e95df9f68 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -372,7 +372,7 @@ std::vector ClockNetwork::tree_taps( return tree_taps_[tree_id]; } -std::string ClockNetwork::tap_from_port(const ClockTapId& tap_id) const { +BasicPort ClockNetwork::tap_from_port(const ClockTapId& tap_id) const { VTR_ASSERT(valid_tap_id(tap_id)); return tap_from_ports_[tap_id]; } @@ -470,17 +470,15 @@ std::vector ClockNetwork::tree_flatten_tap_to_ports( for (ClockTapId tap_id : tree_taps_[tree_id]) { VTR_ASSERT(valid_tap_id(tap_id)); /* Filter out unmatched from ports. Expect [clk_pin_id:clk_pin_id] */ - std::string tap_from_port_name = tap_from_ports_[tap_id]; - PortParser from_port_parser(tap_from_port_name); - BasicPort from_port = from_port_parser.port(); + BasicPort from_port = tap_from_ports_[tap_id]; if (!from_port.is_valid()) { VTR_LOG_ERROR("Invalid from port name '%s' whose index is not valid\n", - tap_from_port_name.c_str()); + from_port.to_verilog_string().c_str()); exit(1); } if (from_port.get_width() != 1) { VTR_LOG_ERROR("Invalid from port name '%s' whose width is not 1\n", - tap_from_port_name.c_str()); + from_port.to_verilog_string().c_str()); exit(1); } if (from_port.get_lsb() != size_t(clk_pin_id)) { @@ -792,7 +790,7 @@ ClockInternalDriverId ClockNetwork::add_spine_switch_point_internal_driver( } ClockTapId ClockNetwork::add_tree_tap(const ClockTreeId& tree_id, - const std::string& from_port, + const BasicPort& from_port, const std::string& to_port) { VTR_ASSERT(valid_tree_id(tree_id)); /* TODO: Consider find existing tap template and avoid duplication in storage diff --git a/libs/libclkarchopenfpga/src/base/clock_network.h b/libs/libclkarchopenfpga/src/base/clock_network.h index 242720dce..ebfcbf038 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.h +++ b/libs/libclkarchopenfpga/src/base/clock_network.h @@ -144,7 +144,7 @@ class ClockNetwork { */ 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; + BasicPort 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: @@ -224,7 +224,7 @@ class ClockNetwork { const ClockSpineId& spine_id, const ClockSwitchPointId& switch_point_id, const std::string& internal_driver_port); ClockTapId add_tree_tap(const ClockTreeId& tree_id, - const std::string& from_port, + const BasicPort& from_port, const std::string& to_port); bool set_tap_bounding_box(const ClockTapId& tap_id, const vtr::Rect& bb); @@ -319,7 +319,7 @@ class ClockNetwork { vtr::vector internal_driver_ports_; /* Basic information about tap */ vtr::vector tap_ids_; - vtr::vector tap_from_ports_; + vtr::vector tap_from_ports_; vtr::vector tap_to_ports_; vtr::vector> tap_bbs_; /* Bounding box for tap points, (xlow, ylow) -> (xhigh, yhigh) */ diff --git a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp index 4d47ad18e..c56b152fd 100644 --- a/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/read_xml_clock_network.cpp @@ -42,7 +42,8 @@ static void read_xml_clock_tree_tap_type_all(pugi::xml_node& xml_tap, 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); + PortParser from_port_parser(from_pin_name); + clk_ntwk.add_tree_tap(tree_id, from_port_parser.port(), to_pin_name); } /******************************************************************** @@ -62,8 +63,9 @@ static void read_xml_clock_tree_tap_type_single( std::string to_pin_name = get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN, loc_data) .as_string(); + PortParser from_port_parser(from_pin_name); ClockTapId tap_id = - clk_ntwk.add_tree_tap(tree_id, from_pin_name, to_pin_name); + clk_ntwk.add_tree_tap(tree_id, from_port_parser.port(), to_pin_name); /* Single tap only require a coordinate */ size_t tap_x = get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_X, @@ -93,8 +95,9 @@ static void read_xml_clock_tree_tap_type_region( std::string to_pin_name = get_attribute(xml_tap, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN, loc_data) .as_string(); + PortParser from_port_parser(from_pin_name); ClockTapId tap_id = - clk_ntwk.add_tree_tap(tree_id, from_pin_name, to_pin_name); + clk_ntwk.add_tree_tap(tree_id, from_port_parser.port(), to_pin_name); /* Region require a bounding box */ size_t tap_start_x = diff --git a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp index 3473a6350..fbdea521d 100644 --- a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp @@ -35,7 +35,7 @@ static int write_xml_clock_tree_taps(std::fstream& fp, 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()); + clk_ntwk.tap_from_port(tap_id).to_verilog_string().c_str()); write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN, clk_ntwk.tap_to_port(tap_id).c_str()); fp << "/>" @@ -46,7 +46,7 @@ static int write_xml_clock_tree_taps(std::fstream& fp, 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()); + clk_ntwk.tap_from_port(tap_id).to_verilog_string().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, @@ -61,7 +61,7 @@ static int write_xml_clock_tree_taps(std::fstream& fp, 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()); + clk_ntwk.tap_from_port(tap_id).to_verilog_string().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, From df23daf0265eb318494da155e1a8b3dfb8bbef61 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 1 Jul 2024 17:37:16 -0700 Subject: [PATCH 73/86] [lib] sanity check on global port name and from pin name of tap points --- .../src/base/clock_network.cpp | 19 ++++++++++++++++++- .../src/base/clock_network.h | 1 + 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index e95df9f68..440870f29 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -859,6 +859,23 @@ bool ClockNetwork::link() { return true; } +bool ClockNetwork::validate_tree_taps() const { + for (ClockTreeId tree_id : trees()) { + for (ClockTapId tap_id : tree_taps(tree_id)) { + /* The from pin name should match the global port */ + if (!tree_global_port(tree_id).mergeable(tap_from_port(tap_id)) || !tree_global_port(tree_id).contained(tap_from_port(tap_id))) { + VTR_LOG_ERROR( + "Tap point from_port '%s' is not part of the global port '%s' of tree '%s'\n", + tap_from_port(tap_id).to_verilog_string().c_str(), + tree_global_port(tree_id).to_verilog_string().c_str(), + tree_name(tree_id).c_str()); + return false; + } + } + } + return true; +} + bool ClockNetwork::validate_tree() const { for (ClockTreeId tree_id : trees()) { for (ClockSpineId spine_id : spines(tree_id)) { @@ -920,7 +937,7 @@ bool ClockNetwork::validate_tree() const { bool ClockNetwork::validate() const { is_dirty_ = true; if (default_segment_id_ && default_tap_switch_id_ && - default_driver_switch_id_ && validate_tree()) { + default_driver_switch_id_ && validate_tree() && validate_tree_taps()) { is_dirty_ = false; } return true; diff --git a/libs/libclkarchopenfpga/src/base/clock_network.h b/libs/libclkarchopenfpga/src/base/clock_network.h index ebfcbf038..ffec611df 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.h +++ b/libs/libclkarchopenfpga/src/base/clock_network.h @@ -266,6 +266,7 @@ class ClockNetwork { private: /* Public invalidators/validators */ /* Ensure tree data is clean. All the spines are valid, and switch points are * valid */ + bool validate_tree_taps() const; bool validate_tree() const; /* Show if the internal driver id is a valid for data queries */ bool valid_internal_driver_id( From 70428fd969c57016203bf797b183632be17482e8 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 1 Jul 2024 17:56:29 -0700 Subject: [PATCH 74/86] [lib] add sanity checks on global port name and clock network's global port name --- .../src/utils/clock_network_utils.cpp | 26 +++++++++++++++++++ .../src/utils/clock_network_utils.h | 4 +++ .../src/base/openfpga_read_arch_template.h | 6 +++++ 3 files changed, 36 insertions(+) diff --git a/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp b/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp index 3d82f9c23..449352403 100644 --- a/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp +++ b/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp @@ -96,4 +96,30 @@ int link_clock_network_rr_graph(ClockNetwork& clk_ntwk, return status; } +/** Check for each global ports in tile annotation + * If a clock tree is required for a global port, the global port name define in the tile annotation should match the one in clock clock + */ +int check_clock_network_tile_annotation(const ClockNetwork& clk_ntwk, + const TileAnnotation& tile_annotation) { + for (const TileGlobalPortId& gport_id : tile_annotation.global_ports()) { + if (!tile_annotation.global_port_thru_dedicated_network(gport_id)) { + continue; + } + std::string gport_name = tile_annotation.global_port_name(gport_id); + std::string clk_tree_name = tile_annotation.global_port_clock_arch_tree_name(gport_id); + ClockTreeId clk_tree_id = clk_ntwk.find_tree(clk_tree_name); + if (!clk_ntwk.valid_tree_id(clk_tree_id)) { + VTR_LOG_ERROR("Invalid clock tree name '%s' defined for global port '%s' in tile annotation! Must be a valid name defined in the clock network description!\n", + clk_tree_name.c_str(), gport_name.c_str()); + return CMD_EXEC_FATAL_ERROR; + } + if (clk_ntwk.tree_global_port(clk_tree_id).get_name() != gport_name) { + VTR_LOG_ERROR("Global port '%s' of clock tree name '%s' must match the name of assoicated global port '%s' in tile annotation! Must be a valid name defined in the clock network description!\n", + clk_ntwk.tree_global_port(clk_tree_id).to_verilog_string().c_str(), clk_tree_name.c_str(), gport_name.c_str()); + return CMD_EXEC_FATAL_ERROR; + } + } + return CMD_EXEC_SUCCESS; +} + } // End of namespace openfpga diff --git a/libs/libclkarchopenfpga/src/utils/clock_network_utils.h b/libs/libclkarchopenfpga/src/utils/clock_network_utils.h index 0a266c188..f87c80a53 100644 --- a/libs/libclkarchopenfpga/src/utils/clock_network_utils.h +++ b/libs/libclkarchopenfpga/src/utils/clock_network_utils.h @@ -6,6 +6,7 @@ *******************************************************************/ #include "clock_network.h" #include "rr_graph_view.h" +#include "tile_annotation.h" /******************************************************************** * Function declaration @@ -16,6 +17,9 @@ namespace openfpga { // Begin namespace openfpga int link_clock_network_rr_graph(ClockNetwork& clk_ntwk, const RRGraphView& rr_graph); +int check_clock_network_tile_annotation(const ClockNetwork& clk_ntwk, + const TileAnnotation& tile_annotation); + } // End of namespace openfpga #endif diff --git a/openfpga/src/base/openfpga_read_arch_template.h b/openfpga/src/base/openfpga_read_arch_template.h index 4ee895977..e0dd9dd34 100644 --- a/openfpga/src/base/openfpga_read_arch_template.h +++ b/openfpga/src/base/openfpga_read_arch_template.h @@ -246,6 +246,12 @@ int read_openfpga_clock_arch_template(T& openfpga_context, const Command& cmd, VTR_LOG_ERROR("Link clock network to routing architecture failed!"); return CMD_EXEC_FATAL_ERROR; } + if (CMD_EXEC_SUCCESS != + check_clock_network_tile_annotation(openfpga_context.clock_arch(), + openfpga_context.arch().tile_annotations)) { + VTR_LOG_ERROR("Check clock network consistency with tile annotation failed!"); + return CMD_EXEC_FATAL_ERROR; + } /* Ensure clean data */ openfpga_context.clock_arch().validate(); if (!openfpga_context.clock_arch().is_valid()) { From a85a6f1674171909caceb485295f7a2cd7f10380 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 1 Jul 2024 17:57:10 -0700 Subject: [PATCH 75/86] [core] code format --- .../src/base/clock_network.cpp | 6 ++++-- .../src/io/write_xml_clock_network.cpp | 15 +++++++------ .../src/utils/clock_network_utils.cpp | 21 +++++++++++++------ .../src/base/openfpga_read_arch_template.h | 9 ++++---- 4 files changed, 33 insertions(+), 18 deletions(-) diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index 440870f29..2889876ab 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -863,9 +863,11 @@ bool ClockNetwork::validate_tree_taps() const { for (ClockTreeId tree_id : trees()) { for (ClockTapId tap_id : tree_taps(tree_id)) { /* The from pin name should match the global port */ - if (!tree_global_port(tree_id).mergeable(tap_from_port(tap_id)) || !tree_global_port(tree_id).contained(tap_from_port(tap_id))) { + if (!tree_global_port(tree_id).mergeable(tap_from_port(tap_id)) || + !tree_global_port(tree_id).contained(tap_from_port(tap_id))) { VTR_LOG_ERROR( - "Tap point from_port '%s' is not part of the global port '%s' of tree '%s'\n", + "Tap point from_port '%s' is not part of the global port '%s' of " + "tree '%s'\n", tap_from_port(tap_id).to_verilog_string().c_str(), tree_global_port(tree_id).to_verilog_string().c_str(), tree_name(tree_id).c_str()); diff --git a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp index fbdea521d..1e03bc0ba 100644 --- a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp @@ -34,8 +34,9 @@ static int write_xml_clock_tree_taps(std::fstream& fp, 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).to_verilog_string().c_str()); + write_xml_attribute( + fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN, + clk_ntwk.tap_from_port(tap_id).to_verilog_string().c_str()); write_xml_attribute(fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_TO_PIN, clk_ntwk.tap_to_port(tap_id).c_str()); fp << "/>" @@ -45,8 +46,9 @@ static int write_xml_clock_tree_taps(std::fstream& fp, 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).to_verilog_string().c_str()); + write_xml_attribute( + fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN, + clk_ntwk.tap_from_port(tap_id).to_verilog_string().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, @@ -60,8 +62,9 @@ static int write_xml_clock_tree_taps(std::fstream& fp, 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).to_verilog_string().c_str()); + write_xml_attribute( + fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN, + clk_ntwk.tap_from_port(tap_id).to_verilog_string().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, diff --git a/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp b/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp index 449352403..6f78b26fe 100644 --- a/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp +++ b/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp @@ -97,7 +97,8 @@ int link_clock_network_rr_graph(ClockNetwork& clk_ntwk, } /** Check for each global ports in tile annotation - * If a clock tree is required for a global port, the global port name define in the tile annotation should match the one in clock clock + * If a clock tree is required for a global port, the global port name define + * in the tile annotation should match the one in clock clock */ int check_clock_network_tile_annotation(const ClockNetwork& clk_ntwk, const TileAnnotation& tile_annotation) { @@ -106,16 +107,24 @@ int check_clock_network_tile_annotation(const ClockNetwork& clk_ntwk, continue; } std::string gport_name = tile_annotation.global_port_name(gport_id); - std::string clk_tree_name = tile_annotation.global_port_clock_arch_tree_name(gport_id); + std::string clk_tree_name = + tile_annotation.global_port_clock_arch_tree_name(gport_id); ClockTreeId clk_tree_id = clk_ntwk.find_tree(clk_tree_name); if (!clk_ntwk.valid_tree_id(clk_tree_id)) { - VTR_LOG_ERROR("Invalid clock tree name '%s' defined for global port '%s' in tile annotation! Must be a valid name defined in the clock network description!\n", - clk_tree_name.c_str(), gport_name.c_str()); + VTR_LOG_ERROR( + "Invalid clock tree name '%s' defined for global port '%s' in tile " + "annotation! Must be a valid name defined in the clock network " + "description!\n", + clk_tree_name.c_str(), gport_name.c_str()); return CMD_EXEC_FATAL_ERROR; } if (clk_ntwk.tree_global_port(clk_tree_id).get_name() != gport_name) { - VTR_LOG_ERROR("Global port '%s' of clock tree name '%s' must match the name of assoicated global port '%s' in tile annotation! Must be a valid name defined in the clock network description!\n", - clk_ntwk.tree_global_port(clk_tree_id).to_verilog_string().c_str(), clk_tree_name.c_str(), gport_name.c_str()); + VTR_LOG_ERROR( + "Global port '%s' of clock tree name '%s' must match the name of " + "assoicated global port '%s' in tile annotation! Must be a valid name " + "defined in the clock network description!\n", + clk_ntwk.tree_global_port(clk_tree_id).to_verilog_string().c_str(), + clk_tree_name.c_str(), gport_name.c_str()); return CMD_EXEC_FATAL_ERROR; } } diff --git a/openfpga/src/base/openfpga_read_arch_template.h b/openfpga/src/base/openfpga_read_arch_template.h index e0dd9dd34..346deae5f 100644 --- a/openfpga/src/base/openfpga_read_arch_template.h +++ b/openfpga/src/base/openfpga_read_arch_template.h @@ -246,10 +246,11 @@ int read_openfpga_clock_arch_template(T& openfpga_context, const Command& cmd, VTR_LOG_ERROR("Link clock network to routing architecture failed!"); return CMD_EXEC_FATAL_ERROR; } - if (CMD_EXEC_SUCCESS != - check_clock_network_tile_annotation(openfpga_context.clock_arch(), - openfpga_context.arch().tile_annotations)) { - VTR_LOG_ERROR("Check clock network consistency with tile annotation failed!"); + if (CMD_EXEC_SUCCESS != check_clock_network_tile_annotation( + openfpga_context.clock_arch(), + openfpga_context.arch().tile_annotations)) { + VTR_LOG_ERROR( + "Check clock network consistency with tile annotation failed!"); return CMD_EXEC_FATAL_ERROR; } /* Ensure clean data */ From 1bfcf7574c2e130dd492deca354597b210cceef3 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 1 Jul 2024 20:33:28 -0700 Subject: [PATCH 76/86] [test] validate region and single syntax --- .../regression_test_scripts/basic_reg_test.sh | 1 + .../config/clk_arch_1clk_1rst_2layer.xml | 36 +++++++++++++ .../config/pin_constraints_reset.xml | 8 +++ .../config/pin_constraints_resetb.xml | 8 +++ .../config/repack_pin_constraints.xml | 4 ++ .../config/task.conf | 54 +++++++++++++++++++ 6 files changed, 111 insertions(+) create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/clk_arch_1clk_1rst_2layer.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/pin_constraints_reset.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/pin_constraints_resetb.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/repack_pin_constraints.xml create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/task.conf diff --git a/openfpga_flow/regression_test_scripts/basic_reg_test.sh b/openfpga_flow/regression_test_scripts/basic_reg_test.sh index 476e8c010..f8742d781 100755 --- a/openfpga_flow/regression_test_scripts/basic_reg_test.sh +++ b/openfpga_flow/regression_test_scripts/basic_reg_test.sh @@ -235,6 +235,7 @@ run-task basic_tests/clock_network/homo_2clock_2layer $@ run-task basic_tests/clock_network/homo_2clock_2layer_disable_unused $@ run-task basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree $@ run-task basic_tests/clock_network/homo_1clock_1_reset_2layer $@ +run-task basic_tests/clock_network/homo_1clock_1_reset_2layer_syntax $@ run-task basic_tests/clock_network/homo_1clock_1_reset_2layer_disable_unused_spines $@ run-task basic_tests/clock_network/homo_1clock_1_reset_2layer_internal_driver $@ diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/clk_arch_1clk_1rst_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/clk_arch_1clk_1rst_2layer.xml new file mode 100644 index 000000000..ccdc3bc46 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/clk_arch_1clk_1rst_2layer.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/pin_constraints_reset.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/pin_constraints_reset.xml new file mode 100644 index 000000000..3788a1411 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/pin_constraints_reset.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/pin_constraints_resetb.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/pin_constraints_resetb.xml new file mode 100644 index 000000000..1311926f5 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/pin_constraints_resetb.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/repack_pin_constraints.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/repack_pin_constraints.xml new file mode 100644 index 000000000..06a125111 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/repack_pin_constraints.xml @@ -0,0 +1,4 @@ + + + + diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/task.conf b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/task.conf new file mode 100644 index 000000000..04489c15e --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/task.conf @@ -0,0 +1,54 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# Configuration file for running experiments +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs +# Each job execute fpga_flow script on combination of architecture & benchmark +# timeout_each_job is timeout for each job +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + +[GENERAL] +run_engine=openfpga_shell +power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml +power_analysis = false +spice_output=false +verilog_output=true +timeout_each_job = 3*60 +fpga_flow=yosys_vpr + +[OpenFPGA_SHELL] +openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/example_clkntwk_no_ace_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_Ntwk1clk1rst2lvl_cc_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml +openfpga_repack_constraints_file=${PATH:TASK_DIR}/config/repack_pin_constraints.xml +openfpga_vpr_device_layout=2x2 +openfpga_vpr_route_chan_width=40 +openfpga_clock_arch_file=${PATH:TASK_DIR}/config/clk_arch_1clk_1rst_2layer.xml +openfpga_verilog_testbench_port_mapping=--explicit_port_mapping +openfpga_route_clock_options= + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_reset/counter.v +bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_resetb/counter.v + +[SYNTHESIS_PARAM] +# Yosys script parameters +bench_yosys_cell_sim_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/openfpga_dff_sim.v +bench_yosys_dff_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/openfpga_dff_map.v +bench_read_verilog_options_common = -nolatches +bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dff_flow.ys +bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys;${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_rewrite_flow.ys + +bench0_top = counter +bench0_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/pin_constraints_reset.xml +bench0_openfpga_verilog_testbench_port_mapping= + +bench1_top = counter +bench1_openfpga_pin_constraints_file = ${PATH:TASK_DIR}/config/pin_constraints_resetb.xml +bench1_openfpga_verilog_testbench_port_mapping= + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= +vpr_fpga_verilog_formal_verification_top_netlist= From e00312d29e627fa62fbf4d0f8c1e54a3d4dbe356 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 1 Jul 2024 20:34:37 -0700 Subject: [PATCH 77/86] [test] typo --- .../config/clk_arch_1clk_1rst_2layer.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/clk_arch_1clk_1rst_2layer.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/clk_arch_1clk_1rst_2layer.xml index ccdc3bc46..41a1aed69 100644 --- a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/clk_arch_1clk_1rst_2layer.xml +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer_syntax/config/clk_arch_1clk_1rst_2layer.xml @@ -11,7 +11,7 @@ - + @@ -28,7 +28,7 @@ - + From 60e6e27e54872a1172853234cd1cb27c23ec458a Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 1 Jul 2024 20:45:55 -0700 Subject: [PATCH 78/86] [core] fixed a bug on tap point identificatin --- libs/libclkarchopenfpga/src/base/clock_network.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index 2889876ab..78a0a9c60 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -429,11 +429,11 @@ bool ClockNetwork::valid_tap_coord_in_bb( return true; } if (tap_type(tap_id) == ClockNetwork::e_tap_type::SINGLE && - tap_bbs_[tap_id].strictly_contains(tap_coord)) { + tap_bbs_[tap_id].coincident(tap_coord)) { return true; } if (tap_type(tap_id) == ClockNetwork::e_tap_type::REGION && - tap_bbs_[tap_id].strictly_contains(tap_coord)) { + tap_bbs_[tap_id].coincident(tap_coord)) { /* Check if steps are considered, coords still matches */ bool x_in_bb = false; for (size_t ix = tap_bbs_[tap_id].xmin(); ix < tap_bbs_[tap_id].xmax(); From 73b30841a78b8be0b996dd39e161ec61658f7517 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 1 Jul 2024 20:56:27 -0700 Subject: [PATCH 79/86] [lib] typo --- libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp index 1e03bc0ba..e36ed9ed8 100644 --- a/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp +++ b/libs/libclkarchopenfpga/src/io/write_xml_clock_network.cpp @@ -61,7 +61,7 @@ static int write_xml_clock_tree_taps(std::fstream& fp, } case ClockNetwork::e_tap_type::REGION: { openfpga::write_tab_to_file(fp, 4); - fp << "<" << XML_CLOCK_TREE_TAP_SINGLE_NODE_NAME << ""; + fp << "<" << XML_CLOCK_TREE_TAP_REGION_NODE_NAME << ""; write_xml_attribute( fp, XML_CLOCK_TREE_TAP_ATTRIBUTE_FROM_PIN, clk_ntwk.tap_from_port(tap_id).to_verilog_string().c_str()); From 578d7c8ec03fecf1c47db548b8825e3b1e811866 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 1 Jul 2024 20:58:41 -0700 Subject: [PATCH 80/86] [core] fixed a bug on region tap point identification --- libs/libclkarchopenfpga/src/base/clock_network.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index 78a0a9c60..bd02259b7 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -436,7 +436,7 @@ bool ClockNetwork::valid_tap_coord_in_bb( tap_bbs_[tap_id].coincident(tap_coord)) { /* Check if steps are considered, coords still matches */ bool x_in_bb = false; - for (size_t ix = tap_bbs_[tap_id].xmin(); ix < tap_bbs_[tap_id].xmax(); + for (size_t ix = tap_bbs_[tap_id].xmin(); ix <= tap_bbs_[tap_id].xmax(); ix = ix + tap_bb_steps_[tap_id].x()) { if (tap_coord.x() == ix) { x_in_bb = true; @@ -448,7 +448,7 @@ bool ClockNetwork::valid_tap_coord_in_bb( return false; } bool y_in_bb = false; - for (size_t iy = tap_bbs_[tap_id].ymin(); iy < tap_bbs_[tap_id].ymax(); + for (size_t iy = tap_bbs_[tap_id].ymin(); iy <= tap_bbs_[tap_id].ymax(); iy = iy + tap_bb_steps_[tap_id].y()) { if (tap_coord.y() == iy) { y_in_bb = true; From ec7ca1add1431ff79a7cfb4aec7f49e9f7a5a100 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 1 Jul 2024 21:41:33 -0700 Subject: [PATCH 81/86] [doc] add example to example clock network --- .../manual/file_formats/clock_network.rst | 32 +++++++++++++----- .../figures/prog_clk_network_example_2x2.png | Bin 0 -> 64210 bytes 2 files changed, 24 insertions(+), 8 deletions(-) create mode 100644 docs/source/manual/file_formats/figures/prog_clk_network_example_2x2.png diff --git a/docs/source/manual/file_formats/clock_network.rst b/docs/source/manual/file_formats/clock_network.rst index 5979c2f24..0b99fea10 100644 --- a/docs/source/manual/file_formats/clock_network.rst +++ b/docs/source/manual/file_formats/clock_network.rst @@ -37,6 +37,14 @@ Using the clock network description language, users can define multiple clock ne +.. _fig_prog_clock_network_example_2x2: + +.. figure:: figures/prog_clock_network_example_2x2.png + :width: 100% + :alt: An example of programmable clock network considering a 2x2 FPGA fabric + + An example of programmable clock network considering a 2x2 FPGA fabric + General Settings ^^^^^^^^^^^^^^^^ @@ -44,7 +52,7 @@ The following syntax are applicable to the XML definition under the root node `` .. option:: default_segment="" - Define the default routing segment to be used when building the routing tracks for the clock network. Must be a valid routing segment defined in the VPR architecture file. For example, + Define the default routing segment to be used when building the routing tracks for the clock network. The routing segments are used to build the spines of clock networks as shown in :numref:`fig_prog_clock_network_example_2x2`. Must be a valid routing segment defined in the VPR architecture file. For example, .. code-block:: xml @@ -62,11 +70,13 @@ where the segment is defined in the VPR architecture file: .. option:: default_tap_switch="" - Define the default routing switch to be used when interconnects the routing tracks to the input pins of programmable blocks in the clock network. Must be a valid routing switch defined in the VPR architecture file. See the example in the ``default_driver_switch``. + Define the default routing switch to be used when interconnects the routing tracks to the input pins of programmable blocks in the clock network. The tap switches are used to build the taps of clock networks as shown in :numref:`fig_prog_clock_network_example_2x2`. Must be a valid routing switch defined in the VPR architecture file. See the example in the ``default_driver_switch``. .. option:: default_driver_switch="" - Define the default routing switch to be used when interconnects the routing tracks in the clock network. Must be a valid routing switch defined in the VPR architecture file. For example, + .. note:: For internal drivers, suggest to use the same driver switch for the output pins of a programmable block as defined in VPR architecture. + + Define the default routing switch to be used when interconnects the routing tracks in the clock network. The driver switches are used to build the switch points of clock networks as shown in :numref:`fig_prog_clock_network_example_2x2`. Must be a valid routing switch defined in the VPR architecture file. For example, .. code-block:: xml @@ -103,13 +113,18 @@ where the clock network is used to drive the global clock pin ``clk0`` in OpenFP - + -.. option:: global_port="" +.. option:: global_port="" - Define the source port of the clock network. For example, ``clk[0:7]``. Note that the global port name should match the ``from_pin`` when defining the tap points (See details in :ref:`file_formats_clock_network_clock_tap_point`). + .. note:: When programmable clock network is specified for a global port in OpenFPGA architecure description file, the width of clock tree will be the final size of the global port. + + Define the source port of the clock network. For example, ``clk[0:7]``. Note that the global port name should match + + - the ``from_pin`` when defining the tap points (See details in :ref:`file_formats_clock_network_clock_tap_point`). + - the ``name`` of global port definition in OpenFPGA architecture description file .. _file_formats_clock_network_clock_spine: @@ -145,7 +160,7 @@ For example, -where a horizental clock spine ``spine0`` is defined which spans from (1, 1) to (2, 1) +where a horizental clock spine ``spine0`` is defined which spans from (1, 1) to (2, 1), as highlighted in orange in the :numref:`fig_prog_clock_network_example_2x2` .. note:: We only support clock spines in horizental and vertical directions. Diagonal clock spine is not supported! @@ -177,7 +192,7 @@ For example, -where clock spine ``spine0`` will drive another clock spine ``spine1`` at (1, 1). +where clock spine ``spine0`` will drive another clock spine ``spine1`` at (1, 1), as highlighted in blue in the :numref:`fig_prog_clock_network_example_2x2` For each switch point, outputs of neighbouring programmable blocks are allowed to drive the spine at next level, through syntax ``internal_driver``. @@ -285,3 +300,4 @@ where all the clock spines of the clock network ``clk_tree_0`` tap the clock pin + diff --git a/docs/source/manual/file_formats/figures/prog_clk_network_example_2x2.png b/docs/source/manual/file_formats/figures/prog_clk_network_example_2x2.png new file mode 100644 index 0000000000000000000000000000000000000000..eae255144ba225c55ceb0307bb04ee6a37a39c18 GIT binary patch literal 64210 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

8$f!Ra5gl3Bcvs_5r*Tc6lIkq*Tg-?u*{Y2-VTD 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%0A(^45!X!xs1E-N^E!6+JXWh zM7r}eo`G@~X7m#ZcRt+9mA*eD9Jk(0^|PnlXu0z|V+H80j2ISKf|s-b0&fTQY9`P% zc(&s9wMxtr;~Q4r>F8ia5o>gr*Km57z&?ZC=}l2sWYO}o@`DiSU0l@ z4j1vPclUb64e<)!^O#vZhtR8p6qNSLX<({FfOvIHd=P~k?ywHOk>3Z9h`BXCp}0Sh zug`M!?KB&d`9Hz6k2=0RqxYCHk8fT4<~KdNX7$mLRQhy?OafSsq07T*3t2g0Bf>=` zJw@|gHmTIaF6u+H4wklqc{XQVc)_k6mfKWYTQ$9N^z5xhG9goNj4FK$phV-1G@8f& z)>x4qe#fh4virhom%y+*4Ts-ssk=nrS_toHk4|9-I@v$YbhX{JJQ}&Q)Ny6r*ArXS z=h`zixV?TI!mL+sHJbOClot$tl%F4Zp^{8}q{& zBZb=U!xGBw#}0MpE!JjM%l;v?#XP^$yY%>x8NqtXWI<@@h!LVDvv|Oh`azbpoA8$2 zCLFGau9InfUSv{s1J+`z5j?XzomVYq!`SFnAo(7WV{ttYp`3Btu!HNyD5A|%0!nET zhTBY`>9yx-b6f z+PUSbhtUb->wSg0G{JfZ$Q}vO!V6gR|A;)v~nHoS0q~z$1c%Z*A z`d&ucJj)DR=*y zp$P}%-^0S+D7$26CqFA8DhQd)$A5F^pjG0s_d&PZzD9Fp!;?r`t{t5sv8^XHienQ& zrnU%;A-7tJS@2#dQhoJIMN>%-Mm#-WXbtA`d9^RnV+GoS?CNes?PUeGvrzpp#`?y7!OG7L2`Eb+e-lBKHCe z(OT3OQg|a&_ctUb#D178rEm;DqkIlz*R_?Z$mzmHTQ@>>fUnFqCIwXwG~%e1@6t{?-qP<(fsj?h`a#WZN*FXn=dc6ivuQ|f)&W**3wI|iWNB1F5*s(nq zYZ1*}NVVOTOtorH5ni{B|=9)eP8=(KJ*KAaH_fw(Lw($-_rK)hG}% zyVxyLc&8#98QMY1LNwRjhp{-awt`lXQWp<^vInX^Ar3~Z_KXJx15oC-unmEwv1x+) zIKE3eR|02)54BzLiA$7eUCKHMfn9yv*3)2tB@xAGUwwA=eoxO2OZa<=);tQRafSiQ zH_{iTSTIN`p)FV)>FGp6k!O48I3@ZH*23ulTO}tH>56_{*gIcwG3>r%duw4ArOUlY z+~((D&WH0m7hVNr_+y!U!G7*cA`N_)6EsOD&?HBN8P0fqHq=uF)k1ZLj^(7o&EbH< zVn=?nFAwWFu=GD&>zxOeT-r;nd6qo*h&4rJE9>4PT!a7)0DmIUlD$mI?cr^9kULl6 z#=2c!#W{_}i$xqAxc!3f@R$6ZL|F4;huVCE7k+f>VxgTesv?4LJ_F~hvpO55B0glI z_Z4!m(lf0MP7AGSj=)%d?%Usd13nacy`Gf$ZGe-APlX(8ar3IGQacrug;bZ%uZupe z`;Z^BR0jIqV~X#zTkw!>+I2^k6WWuBFd%&WQWmrDl?B=xhkG}+BwzSRmjvf82e>@| z*|o!_89$O8^)(RD3+1eR)Wh&Q`%hKQA1*3{`dm*pS-Cf`*3JBzfO$CQF1&q?bbaPz5bZBItL(wc<#X%88kk9PFvslh*`adYvT0_*W=G`*A_k#!!~53% zaqN@U8|MtZWl6VGL8TsvyuZLOFJQ|MiL8K}uG9`1Q*o@bOk~SKt2E|Qog1UT@0|S) zY|fp7#WbC!3o@wRcKaVVhSiq=zLm=<5V2E9rOE&Ef%R(}5n17ZCG|7E9p(Q3>;#x| zQj44UF*_vInc)9LSX5G1hJ%(q{r@I@?tB3D_g%ODB8ozD@VA)%E3x!vf&Q;t#-Dnt zJvWp73qSf_W`5n#{GVlZZutGL%|Q4=aQE^5qF(&3H~l}bOsZsMiVxQYlfH2*edE@@UE8_ddD)%2tPR>Oh4U~p<9dgs}pYp;ELn2yBWKO(K(_--4w=dSd~-g)ZZPjDI?`J=b^>)LVz zlx($vh1Oc-8tdP1&WCu9eIR4$&&%4b!)^mL02m~8T3m-sB^8vRlgGswVeRMLlcFNG zpB3#XZJ~i1ga?%!k(b5XA^juaFuGB`*#lh>&-oB~^{V^Js7Po${qlXTYXn&j-S3&=w^QZ(!XHDXaSJBVb(*e2U z=jVP6$(GenQYt;2@9TDx`o%qke&aM!`K#i7(OWgDg8Z63@TpjKj{=A~5YenXf4Rwg zT0HZx4QM4AzuTtlyEMEY&qs$C8lzv!6MtWw+fOYCYggsP&!%(o`)i5Nf@Q-oDeohVW+#El`c!TIMQJ3t zl;-k2F@E;CL(e&UilAmBs%M(n!!oZ1aR z%1F^u@=p@ZxPCOmUkdB%IJ9+QY~;Em^}Sn=f}FX46)^B$4DCE9`*%=C80vggVv;U1 zpa0*1IUM3nk7eYFC2mmy=E$iz3Ml%I8VF>*AMkqSVE>kRPteJq#P&oC6{k@XcpK_o zIVdJAk=dI;;aC8A>Y&cOt{wqsOnZV_MpIN5QhDh78%_nZu-CqTf`S27^uG-M4(s{P z!v8gi|F@k^U>%2@XfhXYI8k6qJudC#w4{zCH$SuK1S^ zus((FK&@AWb2wpq?@L_Xbu+s?--K|t!TOE@JLwwXL!-Rn`_%|mnMAb!Nk@f@NUyEo zqWq))+q}1lC~=#@YV8d@>B*PBy+fcx5ffpIE`iF9|A|)K<*>|DtGZbVr?rB+hrg6h z`$bDSVC`DLgY>iGG0M#<4IihjoldaBOb3|0>H=<8UG`;|zukjJ9rAm#`mVe{7fwANdvvazoY zQ3+9ut&0l+6p@49eJFoNEEXJCZEL?czBUf0w6khx*%v}AFGZ$gYEx3`^OWDr&84l! zQ?);WJJ3dyqJR0~mmXEgqWZbvq8CX%-Yz-1%T3w|70m(Mfw!wvH}rPnGB19Jk5pr0 z?rO=cw7@x9_NUnrE8Vtn9eqPhPE&7F(%F#Pk?9){+fzLC%4WwnkuTzSwfVgsPdJKN zN@icT=vwS^oj0gc-mu>N=sq2Dvx72XvY5v4mi(!UiZF+ES#`wov6M5pxDwy%)S~Ae zw7+?|k|`xbX2%~8`a+xcJQcdGWTJD?u61x$uf^lfr|{BN6b)g{ zP~Ut{4Rv%5^!xa(MOQt($!BM>=@wr5EUX((zF!fBi%7kY5g})WXc+qVMdoG-{=-E7 z)ssO6wTg&%{JZPV%LV(l-i*p2*n14j=51%vDX@;#*B z`I^7|LQxLqv-^d03sDd0 z3lInHCYw_hEK>q(jqRdP2kfw(z{lo+vA$gb@qEo3!kPqpm&h0AAdc9lG?tV^Gsj&z z@lho?BLXFu$+gADLVGs}t{Mt))*hZQPOZOlqlKjOW+RWIWDLD4mHHU`{3%^c5J3J5 z9SuIot18bDxgUH>;!TF+$>RF}r#7I@pYcFuQIM-)Dg9VhZ)E#S!TsthHvm1Y=w_ot z(H*{04v`z4>Ds@8M=PjGC!DsQG`cFH&zQPSrZB6OPPsdMc`#UW8BvTv(-o<}9Hh1I z(>Dc-Y?_k&F5OEa+}^E$#2NZS(X%}vp6_iNoxNY*yMZr#MBUIAQD2A&B^-J({jMbK zNm9|s>b%24+Xr7X%bz@1bo+zST=hs=DVs^O`!BG zOY;fRH}pJ-Lr8r!UfqX4YUF59))*^(m42c$zHD%rh-`X?sxmeaaH{Sh zx{M=`T`7*EDejT8>))pm-o!E%PxZ{Ikwwqa2K-R|e*fiUPf%Z-HroD5{gJ`HE1C0( zSBwOnuD_ZFC8pyVxc~VrzGvzUP3i37M{3**nZ4qNSo7^!*u{fLwqe(*HA;)s!qmfZjFI)Ythmha>6y@p6q z+I+%74bDN1j(FNZAUbe`P4p4?Jlt+Kk~iwO?FU6ZCWJ++R;&JjFzE#3lFV?pXV8ka zR%}`2m`xZ`Cd6QP>UL*mP2#ogr&l+4)n;?uB=oaB@iC}b6n|Sb z{X6BSD;GNQU-;&loN!0U)W!;9$P`PIV5-dJ=ysLa`1%f&d7NFDZYa3BjCsx<@y6zd z;DqX5W3DNGjm<3H(7ZRQ;M9JlH6=8=LGh*(wsw5~$1FIrYIv#3M8p|@)=$jU4p2+nYhOR;?#}1 zZ$v1pze=4+R18gzIP)xTV)#r}m%~8meo9*PEO^zCza}+7u_%i+bwf6A!fw>abTrH= zOypeK2~wLMx{vji>+H8GpUlE}G!sUBpj_$cVyE**6W5i#7Nf>##u~!i3A;mOXWS$w z`I$q+yz@`#2H6>e;`%~S(z6lup&KhT+k^cobeC^e9hE;G9`aDzQ&cx=a-^k1w{c@d zNPgi=LnP}$?jL^}R}-b}_!CPs_C^d7gO}d;tb&aV%9vD%w#I{GLtJ`zNm&4oNwOw( z<{&&p_XePSwUlT#7HOumZEOY~0*|cU`V)QM9B{k3CcrNKLvU)<2_mH@Nh3|7#M9qY zk~1?nh4`26kyO6a-8hx^LhzO!_@t2FkO;{$iOA8c-UsyQ?6%iv4F7iN(+onXhip;+{u%5iZ!z@X6<50Z0zGO|>q5~sONt7m?Wibo(l7n2< zy_bZT%`47;XvLe}`TF;?wE2~#d(!4rIeW1&8%EJ6e=4y;mSLW99!-(!o=wv9)%FhK zw{0CMPShbLn#Z&S#Mjhunp$Pe(60)ACQ+6xTtr+CiAC|ZJ?IqQJG8?COGi_fMEg%h z-vx<=6oD~HIC2^8tov@vCUCxx(0hkRW|V!mXKR-)PSbe66kJRXesjM&)yr9H3(LeRKt{cP&XB400zX z)Mrvk<-TQK?U-v&sY!F=Fw$MjXm)xNbtn=&zp$Ps$@(XZezunY_wX;bD%ezH)3?0K zBabm3OBrse)_6!vH-BF>_qr!pYV24F{wRW)S}tC>lgJ>=BqOBZDq7 z58E@xgODM5OlMx>hFW2dOaNd7u19vOZpwZ{k(A``|rm_3d>c2q{z0Lud zOJwy!jE!FTq{PR9H+4Urx*ktK#fJH;(w^tqgpx@px_?WY^b~1VWt2ql`^&Y=!`4)vIT<-Dc;BKnAPuAFTjsT# zx3AiCv71b3_3C6x2*@ffUsSa@++TXr{rhmylca#+<9M$~86K30Nf*p!{Doq0w0yvx z8I1L}3%p`_m^Kc#R#z%Tm{WTu(&buH4Y9Z$LER;f80Rt%gXcQuTHfKAxbPSSXD+;c zHrHjXAi*Z%3jzjCWBng;267+HtG&EY{-?F##mIZL^2jd)r{1aX5+DlW?{j1bTJjkg ztDFyhM7qo<%}Qd(A>6CNJU0Be$al@YJ>UZL;pMx<3SKbYsBQC2u>~Gd-_Vb`FV`Oj zcra~WjP?9`wlj<8XEwzQoOQWZKhn!zcQGsgm6c@QDq8ntkzLZ%^_sX!P67)lRgS3o zmTqlYMxC*!C1O#~Y)iw$_Q4*mhaCT4;A7)&QZkvb8yidhhWx4*!-C$no9nI*q@kq0 z;=YFYNxIR84AxwcstH^tlt#WQi`<_AFf`pJc` z<{k8`b&3BHY{a@REaS?_-YIaNj1pAl)Q{9hE#<|=@W^x!0{pRD&pr*~t_qn9{`4=nZzn$6tf9`$1z-6Q5F_Xl*Tk=jM;4C2mDQ&mA5osn2 zjvUh2Y6V_FlcgdZy((XNnykm9Z_RHN9d6m#*aLsOWWccJkEeQwG&j1~iN?;dQC(~; zvZINw5~R8O;b2xZxI>O7bw6UCEBZh@0~+6>Nz6ruPntqc4DFwMRgmlL zkoEZJiw$C#ZbNMHK*potoa4__v`L8<$MQWSb( zVc+ugUML@z$WAppO8;!Q^8|}Giv<%o&jcUYsVkCpH0PUs= zLA&_Rvi~)M|C+&n-oVd&b1d4R!fUL`4D!kU^b7653c{)jlcGP}{$6K#Ux7@%UsRju zAD-LP{SapTiGSjL;I|>KZ22jAK4eXTRe*DMBuHVP5`8h$=KniM#^YBv+Iqcq-M8`? zm&WyO|Fo;})XM?6N2^(ZOIJQKnUd%ME@MA?s&C6{qHQO`zXp*HM5eATiMZd03b#6{ zoZn-OY2U~y>+Tq0bV)J49e&|KyHHu8?)7OIH{V~yj(eqsd~%c$8d3PkR1p@D^;GJy zu{z(4*?)~sofNcB6jGYk<@`%3_r`NSPp|Y`u1u`LBHLmwK+iYaRoSldLeLh*9{R z3)8AV{H3FUN^i^>NwK>FCO!G2H~i``!EfhBVf2-rheXynr2~mOK@9)TaaiklDAGUr zgNHCB_`|Q!FxPvlKKa0uf0`P1zr@5yXngLQ%R9rntTnAMhtb=ft*Bhw-ZD7KuyEcb zS$qo5bhJgaejfEc_G?5&9b~|`*wx{V7=1j?_-c0|K>L~C^1+{>=wZ7gefZ#7j4hM( zHg?}HLp49{!hAa8ayE|w%|(UY^A;YwWmB?>j`1LE6IV!1Oa7CyGF9}^hrLNs>^Wce z=Iw(t%dFC`@aVYADV1G|H5w}qYj^kce~XvcOJQG0jpDstr`G{0JF-jE3l zHsNwb8n?GHUW6!IFb_(nK$^OaM77;eW0}<>`Rf(GCDgmRt0zx92$pZ0Nc+25%-!KV z$6B(iMN7tFwHA*z>Kyq~cuhY zFfP`V3eV^o@>@!$YCU#ZtHhcVBXGPOtc1&f`FAwV{QhIt$B3Gv~#2 zSulCvcL_zlVney!oso;2+55aie)*^pWknHFQ)BCy-;RT}OcCADO(jL|zdQ50bFmlO z#>hB3qx@K7_v73t-@#UDc4Os43ZLvblBLBZqQ9$1RaaKDx&{N-E3$W=jLcrX0uX2)LpI!du* zl9?5-3h^=o0T-Az#Lv(^A-%GqxAyJ?2 zBhDrppCxjA+x$4sm?Cw~0Z;XJFV3omf?-=Ig?iGuf#3{xkQ?(!-MM&kkEy$`ZI68* zhk6F8JqacBs8`cl;}e(vPkY}P)MVGSiz13hlPXC!8gY=G+Py|E>Jyekz zkd745P!o#ulF$SN1ZfgN2k9k--s>0N?|ppqIp@!rGxN=vGjIN6X3xI&Uh7(GUu*9* zyLg=|c@S0>NN9sZnI|z?i7;n3d>$Wt37i=HfRy83%J=PfZNIFE_Lcm4JgQW${>AIU zPuFVy(jhAAvx$(D{vFFDA6cIVL*r=6pXWlC{st;0VdFbtPdbQn`T}7k(DqZWx2&*U zu$ioJ7i7Zk7oe008-tg*vZ>*2gjE26)O-m1=a=ephj2p!zYFm%!(R(rK1+3-dGZg| z*zpomNY{A73ENd%2#qqEU!?!7;XBbhD?5lkM;fJxNHq6A>=!TR#DzU3)i!-ru35{c z3ysj}E4)mh)Se_i!MTq2A+NSBv0=)sOD8;F?3x%DM)gF5JA2|!qkr6~Zd4JS>woop zbzIA>q>l98al`f_2=HpUV(bk24{3LQ`q(A2)aiVB_B=wv&tFHgYU<4>{4doW_KdsB z`+CsE+0-!x{X1LeXnPr={6x*y{Zq?zMz4Gl#2Z-J2f5RRmOL<{t z*Sa^CB2zP7)iBZiBAjKyK}Y5OcA%Rcg6vN{a{NTZt8bueWSAE#WF>xv(Vw$}itBHp zmuvlKG$sB23{7qAH`iAzS02_red>bPqR7Qp5Cjs4=j`z0lO3g<`YiU3P)4YKFG_B! z1$+!Ozq^rg@Tz}Xc=p_1dfx{ywGQKqTk`&tsqf(D!J0ZodE)h}F(37s{N784SV{WR z{^ATB0QbO)&n6w#Vm)B*XT-n9kA|%ciJ8x{6*gjdx2co}U}^Jp@Ne*{)INp(!!Zbf zN$y?i=F;o=lWBHi0g_)}A*{(2^4GNG*Z(AjhFE2)mS#s$6RE}IHTq!Cm;K;}0NaKy zhRJ2!f4ZC)kX@sX#;qKWyDx$5P$U3E^X1yg7XNU})bxdakYZq#a8~w5a&w?M#jWx< zPqy7()O;)66&P>r9Z=ie`1WrvN@ZTR%1?2YA)GVXTl?C+W?uMt=5IfeXOeEorey~H z&gYmwXQMmQlO%tc)*>s~@;c7aZs7MZm&)9C)!Uut*SKtfP0f@*Ig-F)e!n{aqIo_H zf&XiMh-@yH1zjv=|2;18Kc6DdSzF;t?X-Z3N>+l&{=M{9CkalU+#u`@^@?+(dSZP3 zH!tT|b9r?{{%`z^DTIOQP8WZ(Df=XNeaY-ET*OIp>!%6BAe*}7+E31U`#rD5k1+kL zZ-Y(E5i0$afB0Ir^>eU@x3psJP6GG|w9)pHHg}sf*SraPXX`HpgQjw69z+xUp20|$ zJN#rodWZ6lRK@PU&h3CmEy@3^y5CXT*_2>N`M0S5Nu~TJ@AIFG+JDl2|4$`WkI%-? zXfCi57g?)oQUXRNmp`m7A9}`EdB5S-El5`zFtEM8_dbB;`~?S;9DA?d)OFL?61>T` zB%Cl&GfrC%^h!F#eI9k?|F?2!k%>^3*ConTGk@#)e^mBPKt^DKgvcv%v(s={*pJw> zpYTUS^cwLXBWd+K5z!m|Pk$B={SW*CpP-K`+G3T6iPrHthpYW|L`03_C>JI~G*Mv1 zJHUCO$7tl{gzMmQ3zrnS?Bg7kX6Jn(%4*lT(_@2mlMjqLa$IaL8Npsb4YfXet`2TyTk2YTw>P+?*0!P__v z>SLMu+Lo@1Ykfc_ozWw=Z_JUn&6oq@6dtxMnEj(9Q1R@D`=g4c@CV^stpjulJqaRl zRgx}Nerb+-Jc?)z1C7>B%F84t3@0dFJaw0cUt4mMUw9bFoI79kFuzDL6-$hdFd# z+sT0Hj~T&hhTLpFoJ9J}kC^(`b0-HvHIB9@Iknp`O3;lzS@jD-Ao**hjoC3>;zm6TU@xt=o4d#*iSIqZUYr#!^)KGKV zZ*^&}E}5z0$hC5>j_r)N^jGd_<#}wHxJH$@$lcu<$tu-m+C#vMAWgQ?viyt?2{r3W zsk?;N&RIzJ6(`dl=?op@+B~3}#$uVZlW3nKbvfU1TA;VMc{VcI z7o&t;_OEkmaa;<0TJaD89t9TUSa;1HpVTxCr)js1aEz_lI{q-jX&zX#>Nm;c8&QD( zKE;6Q6g`@m(>QjW6;TKN*@db*L!#nQ$ezJ9?qU5Mnvv!#uIFjf%r7TSPMXf}Pgtrj z4%002JU&yBK|eCI2181#i*4`jab}8+pQ>np^>CG_&RSO|*7{oh&^rN?0SJ!-441?v zl5Jblhc5vUO01sbnlhStQ?WZ~Q#mzD&DYVR(T7<;LZ>C+aYH7Qha;;?flOZiw+K zw|`x;a~Y95K`4LJJ^2J?HG@=Y?gqSRLIBS&jCa4_au+n+vH6W_6{cAk>jk$K$JXaO z;k^|D{$|vLvTP0&qXl9ELLQp(kiGb4XtB5Ep4;s1grEHq7_tH4)R?ee4I zTacWfiN&nh{gs~EN5~YrfYYP3k}8lu`Bp3Ir;iTRxCB~kglWfIsZ0UD-;A_SitSnU zsGVfPl_seRs*U!^kDv+Ml(F8aj}w0a_7(JgA)F%pX1w zT_h&#iM`A?L)D!gM<1F)>-bAUYKceVc00(>2Hhmrfzedr>pnRGyYA)_YxO-X9f%OY zHP%7dth~zid)^WA_5=?%V1bOejNeBupALr2`-(H1tgljRR}L;yX8UmBr;hZ)~99J zH8Vc8884PtVVEq4mUvfa8nO*2TeVS4bRA93?vCJil9eN4Ciz?g)c?4OLAo-{>O#WK zPEDGYt*QN-SLDj_gh99|LJ<1Wb4W=@)weK=Dp;Z*DNz@nec#ITwFQT%&3K8#sLUn% zGD|B}yWCRVDWC+JAHLFD=IUgUOqOb-xNO!K(ZPAhcQ6OZ1+40@q_c2*BdsFCLGGf0 z?eT=ym}4Zg;GXO&y!-=v(~rls9yxm$%BQAPJil>zYei3>j4eONKazP`)pmm~t_Z$; zb<&insKcGtNL9t+%Qov%>^)6<^yNlG0(rS?#pKlpnob$N7 z?oVgu(RjQs#jO4*R}S|q#?Ew_(I;gP+>0^DS8c~7hguZSc6EM?UlkteTdZuyT6;*fEu zLH;WlR4zjKto1Qr>uZsA&6|@@IaRAR_o|61^`a)!m5GPRZtmda5*J%jU>7HxkCK1( zWTufeDYw;W{c=XVutQpbNdJQal9;zlPU{;GJ$}tgWA7xA!|sw1Bi?Rs-${9J?x?ISht)Sil8rMU@UyPc zQI;9^e2ZvwzxwQW)xwq%Eof>}0lyF*g0?#H2)Le`HN$0E>oYJEQO&Lux@^IM`CMMz z-LTsF?7ff!m$Ve7h+HxwNp)a)(wv2!F`|pdmgyU1hgL&c!u4BfD0@%JP1sJY$`TPl zq7s0!DGUBo<6>9(5L{!l3tp%&-hxmNqRr(_Xno)Fc$w6uh)rv@(;h=fW8C%X!0yYU zZpB>VLU`^I{H4k)D<(F1jzmlHncur^YN0$oGSxpY6W&A1 zGTirBQ&}nS$p_YlCwY)c%&<*iuYBzlE3a{P;VKS$1~sa21D8&_}n z$h;`7L^~+JQqM#0uG`JExk?HvQ10^c^uabCXsahlrAo13gIYxxZlJ>hTGR_pez(4z zEUL`4fPE{f2nvWhsJg$}%i}6}Q(s-2=i`pt?av^ctlpS2GF>wcaoQb{4O&4E;ZZ`L zU7bYv=8IV^h5+Sn`B51{CQ|!$6)`^F?ZEm>#S>Zew>Yb6-nDF>t46}+g?obYM0SZGnSppKX3Ll_#Y zy~yKDD>VN+382$WmTyt2Dl;?-5XDOjb-k4d4(J;kis0P~i<0htfjTvcsrFCCGGWSJ z!5qL(Vhm7Qcv5($)8&%2AikBzL7569z}c9w>rl*6f>LgbTBy`We5~0=SSOXTTGuo~ z=pZ{_W^g&AQ}G=@v*C#M#*s6dz?#gNy%b&sokDF6CzwXUSGfxH#$Vjzw0f}bN`jC3 ziX9+i%=4R&t>r`wqo`ITi#UI^5Dd9ne1^1t6Weo@O+7ssacL+ee;Ci9(T|d#m@6DD`*M#oFRhk4_tTqC?(j4#eO`uBEiX%V(EAZHcV%U=v?_@)N*3 zt0i~9FVth_cVqLexo0Nw&+bCXieimy4SvAik)xv3jE6^@1K3K+ZuQEz#kj@KSbw=8 ze_UB1-~?SY(PUeSpF<-A*_^vjQUh|5-EuJfS>&n1hBkUcI+_yaW^dOw(Gk=amL660 z*exQ{MjuADWo*tAg7dYAtm$zF5aKI{fOUaAywNZw)gmZFw}N61PEAlqB+@gHF|CS< z-K&gZkil{2s<ABQ3rN8%`040qg2h6E16e4y96eohZ_>L`I`ApKq&np^#M_u`kn9t_@W5cUnoJ zPXu)2grIDCv-x8Zg2utGe+XFEPN<=fFFdkOQjV(M6PSo?WkwJMAm0FdSr zTy!hq5%8PgA#bp?YtGAF&aWZLAcFzk`~%Y@KU&PQow4Abs%EbP-#2+6qe6Dd|3yCMWHlb>*Vf=zcZ1vxUhHau`Rs^lf<~%hgbi)nN8&6KEx?ReT%)=Z7 zMeZZh$C3anqAptIi3ZQF$Va?r0;o0l^gmV(8SgaS%goS$*9?B{FDU1#c6wudd-+nH zo$1Gl5d2G=6;ya10|n-RrRy=D&LIhF2h$9@jl#hikJrj3uPy`NJGGe;CD_x&c*GG4 z{)F-K-CQ3`)VJ;7aLgm~B!h7Nw~(qUMXnC?Sl@j0;p;UYY$x8f_eTiycNH!H04c{s zBN;;|J&ij{E!ZD2WWV5IkgCmiov`p1#qQ1KOWvO(bc~N3i$M=? zZuxDQGoN=R2{iK|k*W%eeQ#5K&fai9-zKzpP*A(J89S7l2XXY{u?XfZDrT_>nE{;~ zgdE7;R)o~OAAZaV#*PU2@J08ZN85Crc(z=Tcw-10;K3k z&g(qDsu?4XG>1;%Q`71f)eO~i*bhPdPaUR5Nva$D@8~B*tb6^pvuyg-h^ZFq0l!$t z|I1l6^o+8Ed+4?`T>PoIS5({s{UhA=@I-CZ+BUN9goSa0zVgvpH$ad0cQHl=d)f-K zcBh)UHnMQxSFv8EOirdk0tQVN^FE-5X2^oM!^jy#J2f=j>)$}83hxvu)scR%HhAFm9FLm(47+0dazPFbfZ|a^r5$%Z#1h!(Zc(@POnF%;|uPCyJN6L~)I@9AwSc z^&D%I>X1xd7lZhWhB6PnH_S+N2^cfnJPXR-p0bT_4;(2^^FF(~5d}MeJ~kD!EPEMQ z1=W0^a;q~OJF6Wc@Umn!3ISl(W9(wq_cY!MIM9x=qcCpTwju142SZBJdXU&anCrQ0 z3p6bU4*sb9#bRpRO#?I&i+eYm@1p5&+JrkJcm*r6J_nTZuA-;X>pmV%o|g ze2=O=Aa`z{Pz##EIso#>ps#IvQ#bxkA?a5@rV-7hn`>dv;J51oUADCJ{~p0DlWkw0PuFgl1C)Piimm6B9|t`Xp?-$cG)tJiBV098MMaz>^P<$P1z2QA8x+ zS1#iy%N^O`OU_3^^xH9w`K0wgs*)&4th4IgZYav_Y&&V@od7Awh5AwiWU7RA!w`!{ zdti9sJfoHBaz8s@4FyVw8D+7iBzZ?eZEi+WQbz-o{blOZj$_e_dlbpz?_%V6H}8pq z)jWirCC27sCgwD8muHw<@|BxZE@9pJZ|rsf1wBElO;2Q;g*OV44fZlW%u*!!6Yn2b>)jvWT-3ew8jl2B zOWkonS-M(YF{KOd_rAC#_PO7viuYTUhnbXECrfrk4GBg;%$zfBj=<$_9UAnnvadUQ{3bhAV-JvoNGV(<}MB_+58$V^050GExQSbC#9vgE|gZGx| zt67|kwimxV93xPN>olmMR#=Ul-336FlT3kP{H}0B6N4fV1$23#fuw&u7rhj$Q- zy9$MMqpsb}sjb}A>k4fqG%frfN^}2j--;tI^7vndX>E)mlM4o5!gusJfSEP!FWU*% zhEwIdiU|N?ZkaoZmX8O1Ul~+&)+(!8^84s8qkm24cF+5smoVWn1MsP}QnpInd^qI8 zPOVOE9CU?TGtN$wU1v3a^7dKwq5QazDm|6!$JBztrzaC-n=0Q_L}@xq zbwmY%A~urh?vNHX1Fk{@bfoWla`Pij~Q8U2nc=5U_28cr+I%b%Bz$#!t0} z8Kd&7d*A!QwK|nA6j4PA#xPnGo$HdlDFO0nN&5r;0@G$eg zZTu9fNWHNymQB)zFzHm*4w&iXs-ddCc$8e2HPEHJagC zfnn z{_?NSmdH5NPuLPS41~sWQtEY-h Date: Tue, 2 Jul 2024 09:33:16 -0700 Subject: [PATCH 82/86] [test] fix a bug in arch --- .../openfpga_arch/k4_frac_N4_fracff_40nm_cc_openfpga.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_cc_openfpga.xml b/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_cc_openfpga.xml index 7a7154031..cc4d00f54 100644 --- a/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_cc_openfpga.xml +++ b/openfpga_flow/openfpga_arch/k4_frac_N4_fracff_40nm_cc_openfpga.xml @@ -197,6 +197,7 @@ + From 29452a7442bf2a48749e271884fead3eb38c83d8 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 2 Jul 2024 11:52:19 -0700 Subject: [PATCH 83/86] [test] fixed a bug on out-of-date arch --- .../config/clk_arch_1clk_2layer.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/openfpga_flow/tasks/basic_tests/tile_organization/homo_fabric_tile_clkntwk/config/clk_arch_1clk_2layer.xml b/openfpga_flow/tasks/basic_tests/tile_organization/homo_fabric_tile_clkntwk/config/clk_arch_1clk_2layer.xml index 0570406fd..6f289dbf4 100644 --- a/openfpga_flow/tasks/basic_tests/tile_organization/homo_fabric_tile_clkntwk/config/clk_arch_1clk_2layer.xml +++ b/openfpga_flow/tasks/basic_tests/tile_organization/homo_fabric_tile_clkntwk/config/clk_arch_1clk_2layer.xml @@ -1,5 +1,5 @@ - - + + @@ -11,7 +11,7 @@ - + From 1e7cca8cebfb4991885863c0463c2f5ffd2f4fc9 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 2 Jul 2024 11:52:30 -0700 Subject: [PATCH 84/86] [arch] code format --- openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml b/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml index ad21e6f59..013466e5c 100644 --- a/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml +++ b/openfpga_flow/vpr_arch/k4_frac_N4_tileable_fracff_40nm.xml @@ -108,8 +108,8 @@ - - + + clb.reset clb.clk clb.O[4:7] clb.I[6:11] clb.O[0:3] clb.I[0:5] From 7e461b09f88e479499dd84b41bcf135ebb3ee5c2 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 2 Jul 2024 13:22:41 -0700 Subject: [PATCH 85/86] [core] add missing file --- .../config/repack_pin_constraints.xml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/repack_pin_constraints.xml diff --git a/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/repack_pin_constraints.xml b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/repack_pin_constraints.xml new file mode 100644 index 000000000..06a125111 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/clock_network/homo_1clock_1reset_2layer/config/repack_pin_constraints.xml @@ -0,0 +1,4 @@ + + + + From 078fad1e74d2dd7cc4e05350c2b4a78cd71b7c9a Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 2 Jul 2024 14:57:24 -0700 Subject: [PATCH 86/86] [test] typo --- openfpga_flow/regression_test_scripts/basic_reg_test.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openfpga_flow/regression_test_scripts/basic_reg_test.sh b/openfpga_flow/regression_test_scripts/basic_reg_test.sh index f8742d781..72f1c01d6 100755 --- a/openfpga_flow/regression_test_scripts/basic_reg_test.sh +++ b/openfpga_flow/regression_test_scripts/basic_reg_test.sh @@ -234,10 +234,10 @@ run-task basic_tests/clock_network/homo_1clock_2layer_full_tb $@ run-task basic_tests/clock_network/homo_2clock_2layer $@ run-task basic_tests/clock_network/homo_2clock_2layer_disable_unused $@ run-task basic_tests/clock_network/homo_2clock_2layer_disable_unused_tree $@ -run-task basic_tests/clock_network/homo_1clock_1_reset_2layer $@ -run-task basic_tests/clock_network/homo_1clock_1_reset_2layer_syntax $@ -run-task basic_tests/clock_network/homo_1clock_1_reset_2layer_disable_unused_spines $@ -run-task basic_tests/clock_network/homo_1clock_1_reset_2layer_internal_driver $@ +run-task basic_tests/clock_network/homo_1clock_1reset_2layer $@ +run-task basic_tests/clock_network/homo_1clock_1reset_2layer_syntax $@ +run-task basic_tests/clock_network/homo_1clock_1reset_2layer_disable_unused_spines $@ +run-task basic_tests/clock_network/homo_1clock_1reset_2layer_internal_driver $@ echo -e "Testing configuration chain of a K4N4 FPGA using .blif generated by yosys+verific"; run-task basic_tests/verific_test $@