diff --git a/libs/libclkarchopenfpga/CMakeLists.txt b/libs/libclkarchopenfpga/CMakeLists.txt index 07283a792..b465429cd 100644 --- a/libs/libclkarchopenfpga/CMakeLists.txt +++ b/libs/libclkarchopenfpga/CMakeLists.txt @@ -20,6 +20,7 @@ set_target_properties(libclkarchopenfpga PROPERTIES PREFIX "") #Avoid extra 'lib #Specify link-time dependancies target_link_libraries(libclkarchopenfpga libopenfpgautil + libopenfpgashell libarchopenfpga librrgraph libvtrutil diff --git a/libs/libclkarchopenfpga/src/base/clock_network.cpp b/libs/libclkarchopenfpga/src/base/clock_network.cpp index a4ed7801c..9de997e6c 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.cpp +++ b/libs/libclkarchopenfpga/src/base/clock_network.cpp @@ -14,7 +14,11 @@ namespace openfpga { // Begin namespace openfpga /************************************************************************ * Constructors ***********************************************************************/ -ClockNetwork::ClockNetwork() { is_dirty_ = true; } +ClockNetwork::ClockNetwork() { + default_segment_id_ = RRSegmentId::INVALID(); + default_switch_id_ = RRSwitchId::INVALID(); + is_dirty_ = true; +} /************************************************************************ * Public Accessors : aggregates @@ -115,6 +119,10 @@ std::string ClockNetwork::default_segment_name() const { return default_segment_name_; } +RRSegmentId ClockNetwork::default_segment() const { + return default_segment_id_; +} + std::string ClockNetwork::default_switch_name() const { return default_switch_name_; } @@ -227,6 +235,10 @@ void ClockNetwork::reserve_trees(const size_t& num_trees) { tree_top_spines_.reserve(num_trees); } +void ClockNetwork::set_default_segment(const RRSegmentId& seg_id) { + default_segment_id_ = seg_id; +} + void ClockNetwork::set_default_segment_name(const std::string& name) { default_segment_name_ = name; } @@ -339,13 +351,46 @@ void ClockNetwork::add_spine_switch_point(const ClockSpineId& spine_id, } bool ClockNetwork::link() { - is_dirty_ = true; for (ClockTreeId tree_id : trees()) { if (!link_tree(tree_id)) { return false; } } - is_dirty_ = false; + return true; +} + +bool ClockNetwork::validate_tree() const { + for (ClockTreeId tree_id : trees()) { + for (ClockSpineId spine_id : spines(tree_id)) { + for (ClockSwitchPointId switch_point_id : spine_switch_points(spine_id)) { + if (!valid_spine_switch_point_id(spine_id, switch_point_id)) { + VTR_LOG_ERROR( + "Spine '%s' contains invalid switching point (%lu, %lu)\n", + spine_name(spine_id).c_str(), + spine_switch_point(spine_id, switch_point_id).x(), + spine_switch_point(spine_id, switch_point_id).y()); + return false; + } + } + if (!valid_spine_start_end_points(spine_id)) { + VTR_LOG_ERROR( + "Spine '%s' contains invalid starting point (%lu, %lu) or ending " + "point (%lu, %lu)\n", + spine_name(spine_id).c_str(), spine_start_point(spine_id).x(), + spine_start_point(spine_id).y(), spine_end_point(spine_id).x(), + spine_end_point(spine_id).y()); + return false; + } + } + } + return true; +} + +bool ClockNetwork::validate() const { + is_dirty_ = true; + if (default_segment_id_ && default_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 8be76ad1e..6f00dd3ca 100644 --- a/libs/libclkarchopenfpga/src/base/clock_network.h +++ b/libs/libclkarchopenfpga/src/base/clock_network.h @@ -62,6 +62,9 @@ class ClockNetwork { size_t num_tracks(const ClockTreeId& tree_id, const ClockLevelId& level, const t_rr_type& track_type, const Direction& direction) const; + /* Return the id of default routing segment, use this to find detailed segment + * information from RRGraph */ + RRSegmentId default_segment() const; std::string default_segment_name() const; std::string default_switch_name() const; std::string tree_name(const ClockTreeId& tree_id) const; @@ -106,6 +109,7 @@ class ClockNetwork { void reserve_spines(const size_t& num_spines); /* Reserve a number of trees to be memory efficent */ void reserve_trees(const size_t& num_trees); + void set_default_segment(const RRSegmentId& seg_id); void set_default_segment_name(const std::string& name); void set_default_switch_name(const std::string& name); /* Create a new tree, by default the tree can accomodate only 1 clock signal; @@ -145,6 +149,14 @@ class ClockNetwork { * X-direction spine or a Y-direction spine. Diagonal spine is not supported! */ bool valid_spine_start_end_points(const ClockSpineId& spine_id) const; + /* Validate the internal data. Required to ensure clean data before usage. If + * validation is successful, is_valid() will return true */ + bool validate() const; + + private: /* Public invalidators/validators */ + /* Ensure tree data is clean. All the spines are valid, and switch points are + * valid */ + bool validate_tree() const; private: /* Private mutators */ /* Build internal links between spines under a given tree */ @@ -189,7 +201,7 @@ class ClockNetwork { std::map spine_name2id_map_; /* Flags */ - bool is_dirty_; + mutable bool is_dirty_; }; } // End of namespace openfpga diff --git a/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp b/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp new file mode 100644 index 000000000..b58daf418 --- /dev/null +++ b/libs/libclkarchopenfpga/src/utils/clock_network_utils.cpp @@ -0,0 +1,29 @@ +#include "clock_network_utils.h" + +#include "command_exit_codes.h" +#include "vtr_assert.h" +#include "vtr_time.h" + +namespace openfpga { // Begin namespace openfpga + +/******************************************************************** + * Link all the segments that are defined in a routing resource graph to a given + *clock network + *******************************************************************/ +int link_clock_network_rr_segments(ClockNetwork& clk_ntwk, + const RRGraphView& rr_graph) { + /* default segment id */ + std::string default_segment_name = clk_ntwk.default_segment_name(); + for (size_t rr_seg_id = 0; rr_seg_id < rr_graph.num_rr_segments(); + ++rr_seg_id) { + if (rr_graph.rr_segments(RRSegmentId(rr_seg_id)).name == + default_segment_name) { + clk_ntwk.set_default_segment(RRSegmentId(rr_seg_id)); + return CMD_EXEC_SUCCESS; + } + } + + return CMD_EXEC_FATAL_ERROR; +} + +} // End of namespace openfpga diff --git a/libs/libclkarchopenfpga/src/utils/clock_network_utils.h b/libs/libclkarchopenfpga/src/utils/clock_network_utils.h new file mode 100644 index 000000000..faa348989 --- /dev/null +++ b/libs/libclkarchopenfpga/src/utils/clock_network_utils.h @@ -0,0 +1,21 @@ +#ifndef CLOCK_NETWORK_UTILS_H +#define CLOCK_NETWORK_UTILS_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include "clock_network.h" +#include "rr_graph_view.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ + +namespace openfpga { // Begin namespace openfpga + +int link_clock_network_rr_segments(ClockNetwork& clk_ntwk, + const RRGraphView& rr_graph); + +} // End of namespace openfpga + +#endif diff --git a/openfpga/src/annotation/append_clock_rr_graph.cpp b/openfpga/src/annotation/append_clock_rr_graph.cpp index ae56a41ed..ee2fdf5f6 100644 --- a/openfpga/src/annotation/append_clock_rr_graph.cpp +++ b/openfpga/src/annotation/append_clock_rr_graph.cpp @@ -83,10 +83,10 @@ static size_t estimate_clock_rr_graph_num_nodes(const DeviceGrid& grids, * with direction, ptc and coordinates etc. *******************************************************************/ static void add_rr_graph_block_clock_nodes(RRGraphBuilder& rr_graph_builder, - const RRGraphView& rr_graph_view, - const ClockNetwork& clk_ntwk, - const vtr::Point chan_coord, - const t_rr_type& chan_type) { + const RRGraphView& rr_graph_view, + const ClockNetwork& clk_ntwk, + const vtr::Point chan_coord, + const t_rr_type& chan_type) { size_t orig_chan_width = rr_graph_view.node_lookup() .find_channel_nodes(chan_coord.x(), chan_coord.y(), chan_type) @@ -116,7 +116,6 @@ static void add_rr_graph_block_clock_nodes(RRGraphBuilder& rr_graph_builder, } } - /******************************************************************** * Add clock nodes one by one to the routing resource graph. * Assign node-level attributes properly @@ -139,7 +138,7 @@ static void add_rr_graph_clock_nodes(RRGraphBuilder& rr_graph_builder, continue; } add_rr_graph_block_clock_nodes(rr_graph_builder, rr_graph_view, clk_ntwk, - chanx_coord, CHANX); + chanx_coord, CHANX); } } @@ -154,7 +153,7 @@ static void add_rr_graph_clock_nodes(RRGraphBuilder& rr_graph_builder, continue; } add_rr_graph_block_clock_nodes(rr_graph_builder, rr_graph_view, clk_ntwk, - chany_coord, CHANY); + chany_coord, CHANY); } } } @@ -163,10 +162,10 @@ static void add_rr_graph_clock_nodes(RRGraphBuilder& rr_graph_builder, * Add edges for the clock nodes in a given connection block *******************************************************************/ void add_rr_graph_block_clock_edges(RRGraphBuilder& rr_graph_builder, - const RRGraphView& rr_graph_view, - const ClockNetwork& clk_ntwk, - const vtr::Point chan_coord, - const t_rr_type& chan_type) { + const RRGraphView& rr_graph_view, + const ClockNetwork& clk_ntwk, + const vtr::Point chan_coord, + const t_rr_type& chan_type) { for (auto itree : clk_ntwk.trees()) { for (auto ilvl : clk_ntwk.levels(itree)) { for (auto node_dir : {Direction::INC, Direction::DEC}) { @@ -182,16 +181,17 @@ void add_rr_graph_block_clock_edges(RRGraphBuilder& rr_graph_builder, } } - /******************************************************************** * Add edges to interconnect clock nodes * Walk through the routing tracks in each connection block (driver nodes) * and add edge to their fan-out clock nodes - * Note that + * Note that * - clock nodes at the same level of a clock tree can only go straight - * - clock nodes can only drive clock nodes belong to the same clock index (a clock tree may contain multiple clocks) - * - clock nodes can only drive clock nodes (by making a turn, straight connection is not allowed) which are 1 level lower in the same clock tree with the same clock index - * For example + * - clock nodes can only drive clock nodes belong to the same clock index (a + *clock tree may contain multiple clocks) + * - clock nodes can only drive clock nodes (by making a turn, straight + *connection is not allowed) which are 1 level lower in the same clock tree with + *the same clock index For example * * clk0_lvl1_chany[1][2] * ^ @@ -235,7 +235,6 @@ void add_rr_graph_clock_edges(RRGraphBuilder& rr_graph_builder, chany_coord, CHANY); } } - } /******************************************************************** @@ -262,7 +261,8 @@ int append_clock_rr_graph(DeviceContext& vpr_device_ctx, /* 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"); + "Currently only support 1 clock tree in programmable clock " + "architecture\nPlease update your clock architecture definition\n"); 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 9003642ba..c60b91452 100644 --- a/openfpga/src/base/openfpga_read_arch_template.h +++ b/openfpga/src/base/openfpga_read_arch_template.h @@ -7,6 +7,7 @@ #include "check_circuit_library.h" #include "check_tile_annotation.h" #include "circuit_library_utils.h" +#include "clock_network_utils.h" #include "command.h" #include "command_context.h" #include "command_exit_codes.h" @@ -236,6 +237,14 @@ int read_openfpga_clock_arch_template(T& openfpga_context, const Command& cmd, read_xml_clock_network(arch_file_name.c_str()); /* Build internal links */ openfpga_context.mutable_clock_arch().link(); + link_clock_network_rr_segments(openfpga_context.mutable_clock_arch(), + g_vpr_ctx.device().rr_graph); + /* Ensure clean data */ + openfpga_context.clock_arch().validate(); + if (!openfpga_context.clock_arch().is_valid()) { + VTR_LOG_ERROR("Pre-checking clock architecture failed!"); + return CMD_EXEC_FATAL_ERROR; + } /* TODO: should identify the error code from internal function execution */ return CMD_EXEC_SUCCESS;