diff --git a/Makefile b/Makefile index 06d2df4c158..109288f0344 100644 --- a/Makefile +++ b/Makefile @@ -48,14 +48,14 @@ ifeq ($(VERBOSE),1) override CMAKE_PARAMS := -DVTR_ENABLE_VERBOSE=on ${CMAKE_PARAMS} endif -# -s : Suppresss makefile output (e.g. entering/leaving directories) +# -s : Suppresses makefile output (e.g. entering/leaving directories) # --output-sync target : For parallel compilation ensure output for each target is synchronized (make version >= 4.0) MAKEFLAGS := -s SOURCE_DIR := $(PWD) BUILD_DIR ?= build -#Check for the cmake exectuable +#Check for the cmake executable CMAKE := $(shell command -v cmake 2> /dev/null) #Show test log on failures with 'make test' diff --git a/doc/src/vpr/command_line_usage.rst b/doc/src/vpr/command_line_usage.rst index 6070663eddc..f21ee85f1eb 100644 --- a/doc/src/vpr/command_line_usage.rst +++ b/doc/src/vpr/command_line_usage.rst @@ -379,6 +379,14 @@ Use the options below to override this default naming behaviour. .. seealso:: :ref:`Routing Resource XML File `. +.. option:: --read_rr_edge_override + + Reads a file that overrides the intrinsic delay of specific edges in RR graph. + + This option should be used with both :option:`--read_rr_graph` and :option:`--write_rr_graph`. When used this way, + VPR reads the RR graph, updates the delays of selected edges using :option:`--read_rr_edge_override`, + and writes the updated RR graph. The modified RR graph can then be used in later VPR runs. + .. option:: --read_vpr_constraints Reads the :ref:`VPR constraints ` that the flow must respect from the specified XML file. diff --git a/doc/src/vpr/file_formats.rst b/doc/src/vpr/file_formats.rst index dc76e2ff5ea..32fbb0dfc93 100644 --- a/doc/src/vpr/file_formats.rst +++ b/doc/src/vpr/file_formats.rst @@ -1100,6 +1100,28 @@ To aid in handling large graphs, rr_graph files can also be :ref:`saved in >{}(val) + 0x9e3779b9 + (hash_val << 6) + (hash_val >> 2); + }; + + hash_combine(s.R); + hash_combine(s.Cin); + hash_combine(s.Cout); + hash_combine(s.Cinternal); + hash_combine(s.Tdel); + hash_combine(s.mux_trans_size); + hash_combine(s.buf_size); + hash_combine(static_cast(s.power_buffer_type)); + hash_combine(s.power_buffer_size); + hash_combine(s.intra_tile); + hash_combine(static_cast(s.type())); + + return hash_val; +} + void t_rr_switch_inf::set_type(SwitchType type_val) { type_ = type_val; } diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index 36d66b76e0e..b3550e83d01 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -1588,16 +1588,31 @@ enum class SegResType { NUM_RES_TYPES }; -constexpr std::array(SegResType::NUM_RES_TYPES)> RES_TYPE_STRING = {{"GCLK", "GENERAL"}}; //String versions of segment resource types +/// String versions of segment resource types +constexpr std::array(SegResType::NUM_RES_TYPES)> RES_TYPE_STRING{"GCLK", "GENERAL"}; +/// Defines the type of switch block used in FPGA routing. enum e_switch_block_type { + /// If the type is SUBSET, I use a Xilinx-like switch block where track i in one channel always + /// connects to track i in other channels. SUBSET, + + /// If type is WILTON, I use a switch block where track i + /// does not always connect to track i in other channels. + /// See Steve Wilton, PhD Thesis, University of Toronto, 1996. WILTON, + + /// The UNIVERSAL switch block is from Y. W. Chang et al, TODAES, Jan. 1996, pp. 80 - 101. UNIVERSAL, + + /// The FULL switch block type allows for complete connectivity between tracks. FULL, + + /// A CUSTOM switch block has also been added which allows a user to describe custom permutation functions and connection patterns. + /// See comment at top of SRC/route/build_switchblocks.c CUSTOM }; -typedef enum e_switch_block_type t_switch_block_type; + enum e_Fc_type { ABSOLUTE, FRACTIONAL @@ -1906,16 +1921,28 @@ struct t_rr_switch_inf { bool intra_tile = false; public: - //Returns the type of switch + /// Returns the type of switch SwitchType type() const; - //Returns true if this switch type isolates its input and output into - //separate DC-connected subcircuits + /// Returns true if this switch type isolates its input and output into + /// separate DC-connected subcircuits bool buffered() const; - //Returns true if this switch type is configurable + /// Returns true if this switch type is configurable bool configurable() const; + bool operator==(const t_rr_switch_inf& other) const; + + /** + * @brief Functor for computing a hash value for t_rr_switch_inf. + * + * This custom hasher enables the use of t_rr_switch_inf objects as keys + * in unordered containers such as std::unordered_map or std::unordered_set. + */ + struct Hasher { + std::size_t operator()(const t_rr_switch_inf& s) const; + }; + public: void set_type(SwitchType type_val); diff --git a/libs/librrgraph/src/base/rr_graph_builder.h b/libs/librrgraph/src/base/rr_graph_builder.h index cc367395bc6..4844a785d70 100644 --- a/libs/librrgraph/src/base/rr_graph_builder.h +++ b/libs/librrgraph/src/base/rr_graph_builder.h @@ -239,7 +239,7 @@ class RRGraphBuilder { /** @brief Reserve the lists of edges to be memory efficient. * This function is mainly used to reserve memory space inside RRGraph, - * when adding a large number of edges in order to avoid memory fragements */ + * when adding a large number of edges in order to avoid memory fragments */ inline void reserve_edges(size_t num_edges) { node_storage_.reserve_edges(num_edges); } @@ -264,6 +264,12 @@ class RRGraphBuilder { node_storage_.alloc_and_load_edges(rr_edges_to_create); } + /** @brief Overrides the associated switch for a given edge by + * updating the edge to use the passed in switch. */ + inline void override_edge_switch(RREdgeId edge_id, RRSwitchId switch_id) { + node_storage_.override_edge_switch(edge_id, switch_id); + } + /** @brief set_node_cost_index gets the index of cost data in the list of cost_indexed_data data structure * It contains the routing cost for different nodes in the RRGraph * when used in evaluate different routing paths @@ -304,7 +310,7 @@ class RRGraphBuilder { /** @brief Reserve the lists of nodes, edges, switches etc. to be memory efficient. * This function is mainly used to reserve memory space inside RRGraph, * when adding a large number of nodes/edge/switches/segments, - * in order to avoid memory fragements */ + * in order to avoid memory fragments */ inline void reserve_nodes(size_t size) { node_storage_.reserve(size); } diff --git a/libs/librrgraph/src/base/rr_graph_storage.cpp b/libs/librrgraph/src/base/rr_graph_storage.cpp index 8d8dcd5ac20..cb7ad810dd8 100644 --- a/libs/librrgraph/src/base/rr_graph_storage.cpp +++ b/libs/librrgraph/src/base/rr_graph_storage.cpp @@ -536,10 +536,9 @@ void t_rr_graph_storage::partition_edges(const vtr::vector& rr_switches) const { VTR_ASSERT(!node_first_edge_.empty() && remapped_edges_); diff --git a/libs/librrgraph/src/base/rr_graph_storage.h b/libs/librrgraph/src/base/rr_graph_storage.h index 82c8f0b2326..ac6bece7526 100644 --- a/libs/librrgraph/src/base/rr_graph_storage.h +++ b/libs/librrgraph/src/base/rr_graph_storage.h @@ -393,13 +393,27 @@ class t_rr_graph_storage { * This method should generally not be used, and instead first_edge and * last_edge should be used. */ - RREdgeId edge_id(const RRNodeId& id, t_edge_size iedge) const { + RREdgeId edge_id(RRNodeId id, t_edge_size iedge) const { RREdgeId first_edge = this->first_edge(id); RREdgeId ret(size_t(first_edge) + iedge); VTR_ASSERT_SAFE(ret < last_edge(id)); return ret; } + /** + * @brief Retrieve the RREdgeId that connects the given source and sink nodes. + * If the given source/sink nodes are not connected, RREdgeId::INVALID() is returned. + */ + RREdgeId edge_id(RRNodeId src, RRNodeId sink) const { + for (RREdgeId outgoing_edge_id : edge_range(src)) { + if (edge_sink_node(outgoing_edge_id) == sink) { + return outgoing_edge_id; + } + } + + return RREdgeId::INVALID(); + } + /** @brief Get the source node for the specified edge. */ RRNodeId edge_src_node(const RREdgeId& edge) const { VTR_ASSERT_DEBUG(edge.is_valid()); @@ -448,7 +462,7 @@ class t_rr_graph_storage { * * The following methods implement an interface that appears to be * equivalent to the interface exposed by std::vector. - * This was done for backwards compability. See t_rr_node for more details. + * This was done for backwards compatibility. See t_rr_node for more details. * * Proxy methods: * @@ -483,8 +497,8 @@ class t_rr_graph_storage { ***************************/ /** @brief - * Makes room in storage for RRNodeId in amoritized O(1) fashion. - * This results in an allocation pattern similiar to what would happen + * Makes room in storage for RRNodeId in amortized O(1) fashion. + * This results in an allocation pattern similar to what would happen * if push_back(x) / emplace_back() were used if underlying storage * was not pre-allocated. */ @@ -616,8 +630,8 @@ class t_rr_graph_storage { void set_node_direction(RRNodeId, Direction new_direction); /** @brief - * Add a side to the node abbributes - * This is the function to use when you just add a new side WITHOUT reseting side attributes + * Add a side to the node attributes + * This is the function to use when you just add a new side WITHOUT resetting side attributes */ void add_node_side(RRNodeId, e_side new_side); @@ -707,9 +721,8 @@ class t_rr_graph_storage { * * init_fan_in does not need to be invoked before this method. */ - size_t count_rr_switches( - const std::vector& arch_switch_inf, - t_arch_switch_fanin& arch_switch_fanins); + size_t count_rr_switches(const std::vector& arch_switch_inf, + t_arch_switch_fanin& arch_switch_fanins); /** @brief Maps arch_switch_inf indicies to rr_switch_inf indicies. * @@ -731,6 +744,10 @@ class t_rr_graph_storage { */ void partition_edges(const vtr::vector& rr_switches); + /** @brief Overrides the associated switch for a given edge by + * updating the edge to use the passed in switch. */ + void override_edge_switch(RREdgeId edge_id, RRSwitchId switch_id); + /** @brief Validate that edge data is partitioned correctly.*/ bool validate_node(RRNodeId node_id, const vtr::vector& rr_switches) const; bool validate(const vtr::vector& rr_switches) const; diff --git a/libs/librrgraph/src/base/rr_graph_view.h b/libs/librrgraph/src/base/rr_graph_view.h index d0fffc04307..c3a2ff6273f 100644 --- a/libs/librrgraph/src/base/rr_graph_view.h +++ b/libs/librrgraph/src/base/rr_graph_view.h @@ -413,6 +413,11 @@ class RRGraphView { return node_storage_.edge_switch(id, iedge); } + /// @brief Returns the associated switch for a given edge. + inline short edge_switch(RREdgeId id) const { + return node_storage_.edge_switch(id); + } + /** @brief Return the source node for the specified edge. */ inline RRNodeId edge_src_node(const RREdgeId edge_id) const { diff --git a/libs/librrgraph/src/io/rr_graph_reader.cpp b/libs/librrgraph/src/io/rr_graph_reader.cpp index b0351479f6f..0bcd843ae34 100644 --- a/libs/librrgraph/src/io/rr_graph_reader.cpp +++ b/libs/librrgraph/src/io/rr_graph_reader.cpp @@ -19,6 +19,8 @@ #include "rr_graph_uxsdcxx.h" #include +#include +#include #include "vtr_time.h" #include "pugixml.hpp" @@ -29,6 +31,20 @@ # include "mmap_file.h" #endif +/** + * @brief Parses a line from the RR edge delay override file. + * + * @details Expected formats: + * edge_id Tdel + * (source_node_id, sink_node_id) Tdel + * + * @param line The line to parse. + * @param rr_graph The RR graph for edge lookup using source-sink nodes. + * @return A pair containing an RR edge and the overridden Tdel (intrinsic delay). + */ +static std::pair process_rr_edge_override(const std::string& line, + const RRGraphView& rr_graph); + /************************ Subroutine definitions ****************************/ /* loads the given RR_graph file into the appropriate data structures * as specified by read_rr_graph_name. Set up correct routing data @@ -38,6 +54,7 @@ * parameters are a workaround to passing the data structures of DeviceContext. * Needs a solution to reduce the number of parameters passed in.*/ + void load_rr_file(RRGraphBuilder* rr_graph_builder, RRGraphView* rr_graph, const std::vector& physical_tile_types, @@ -53,7 +70,7 @@ void load_rr_file(RRGraphBuilder* rr_graph_builder, int* wire_to_rr_ipin_switch, int* wire_to_rr_ipin_switch_between_dice, const char* read_rr_graph_name, - std::string* read_rr_graph_filename, + std::string* loaded_rr_graph_filename, bool read_edge_metadata, bool do_check_rr_graph, bool echo_enabled, @@ -74,7 +91,7 @@ void load_rr_file(RRGraphBuilder* rr_graph_builder, wire_to_rr_ipin_switch_between_dice, do_check_rr_graph, read_rr_graph_name, - read_rr_graph_filename, + loaded_rr_graph_filename, read_edge_metadata, echo_enabled, echo_file_name, @@ -115,3 +132,79 @@ void load_rr_file(RRGraphBuilder* rr_graph_builder, read_rr_graph_name); } } + +static std::pair process_rr_edge_override(const std::string& line, + const RRGraphView& rr_graph) { + std::istringstream iss(line); + char ch; + RREdgeId edge_id; + + if (std::isdigit(line[0])) { + // Line starts with an integer + int first; + iss >> first; + edge_id = (RREdgeId)first; + } else if (line[0] == '(') { + // Line starts with (first, second) + int first, second; + iss >> ch >> first >> ch >> second >> ch; + + RRNodeId src_node_id = RRNodeId(first); + RRNodeId sink_node_id = RRNodeId(second); + + edge_id = rr_graph.rr_nodes().edge_id(src_node_id, sink_node_id); + + VTR_LOGV_ERROR(!edge_id.is_valid(), + "Couldn't find an edge connecting node %d to node %d\n", + src_node_id, + sink_node_id); + + } else { + VTR_LOG_ERROR("Invalid line format: %s\n", line.c_str()); + } + + float overridden_Tdel; + if (!(iss >> overridden_Tdel)) { + VTR_LOG_ERROR("Couldn't parse the overridden delay in this line: %s\n", line.c_str()); + } + + return {edge_id, overridden_Tdel}; +} + +void load_rr_edge_delay_overrides(std::string_view filename, + RRGraphBuilder& rr_graph_builder, + const RRGraphView& rr_graph) { + std::ifstream file(filename.data()); + VTR_LOGV_ERROR(!file, "Failed to open the RR edge override file: %s\n", filename.data()); + + std::unordered_map unique_switch_info; + for (const auto& [rr_sw_idx, sw] : rr_graph.rr_switch().pairs()) { + unique_switch_info.insert({sw, rr_sw_idx}); + } + + std::string line; + + while (std::getline(file, line)) { + if (line[0] == '#') { + continue; // Ignore lines starting with '#' + } + + if (!line.empty()) { + const auto [edge_id, overridden_Tdel] = process_rr_edge_override(line, rr_graph); + RRSwitchId curr_switch_id = (RRSwitchId)rr_graph.edge_switch(edge_id); + t_rr_switch_inf switch_override_info = rr_graph.rr_switch_inf(curr_switch_id); + + switch_override_info.Tdel = overridden_Tdel; + + RRSwitchId new_switch_id; + auto it = unique_switch_info.find(switch_override_info); + if (it == unique_switch_info.end()) { + new_switch_id = rr_graph_builder.add_rr_switch(switch_override_info); + unique_switch_info.insert({switch_override_info, new_switch_id}); + } else { + new_switch_id = it->second; + } + rr_graph_builder.override_edge_switch(edge_id, new_switch_id); + } + } +} \ No newline at end of file diff --git a/libs/librrgraph/src/io/rr_graph_reader.h b/libs/librrgraph/src/io/rr_graph_reader.h index 219bc902171..044345ee721 100644 --- a/libs/librrgraph/src/io/rr_graph_reader.h +++ b/libs/librrgraph/src/io/rr_graph_reader.h @@ -28,11 +28,31 @@ void load_rr_file(RRGraphBuilder* rr_graph_builder, int* wire_to_rr_ipin_switch, int* wire_to_rr_ipin_switch_between_dice, const char* read_rr_graph_name, - std::string* read_rr_graph_filename, + std::string* loaded_rr_graph_filename, bool read_edge_metadata, bool do_check_rr_graph, bool echo_enabled, const char* echo_file_name, bool is_flat); +/** + * @brief Reads a text file where the intrinsic delay of edges are overridden. + * + * @details This function tries to find a switch with the overridden delay. If such a + * switch exists, the edge will point to it as its corresponding switch. + * Otherwise, a new switch is created so that the edge can point to a valid switch. + * The architecture file allows the user to specify nominal switch delays, but delays + * may vary for the same switch type across the device. To represent switch delays + * more accurately, the user can specify multiple switch types in the architecture file + * and restrict each one to a region or a single location. Alternatively, the user can + * use this file to override edge delays. + * + * @param filename The text file to be ingested by this function. + * @param rr_graph_builder Used to add switches and override switch IDs for edges. + * @param rr_graph Provides read only access to RR graph. + */ +void load_rr_edge_delay_overrides(std::string_view filename, + RRGraphBuilder& rr_graph_builder, + const RRGraphView& rr_graph); + #endif /* RR_GRAPH_READER_H */ diff --git a/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h b/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h index 9a0126441fb..c97039f1821 100644 --- a/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h +++ b/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h @@ -276,7 +276,7 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { int* wire_to_rr_ipin_switch_between_dice, bool do_check_rr_graph, const char* read_rr_graph_name, - std::string* read_rr_graph_filename, + std::string* loaded_rr_graph_filename, bool read_edge_metadata, bool echo_enabled, const char* echo_file_name, @@ -303,7 +303,7 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { , rr_graph_(rr_graph) , rr_switch_inf_(rr_switch_inf) , rr_indexed_data_(rr_indexed_data) - , read_rr_graph_filename_(read_rr_graph_filename) + , loaded_rr_graph_filename_(loaded_rr_graph_filename) , rr_rc_data_(rr_rc_data) , graph_type_(graph_type) , base_cost_type_(base_cost_type) @@ -1825,9 +1825,9 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { (*rr_indexed_data_)[RRIndexedDataId(i)].seg_index = seg_index_[RRIndexedDataId(i)]; } - VTR_ASSERT(read_rr_graph_filename_ != nullptr); + VTR_ASSERT(loaded_rr_graph_filename_ != nullptr); VTR_ASSERT(read_rr_graph_name_ != nullptr); - read_rr_graph_filename_->assign(read_rr_graph_name_); + loaded_rr_graph_filename_->assign(read_rr_graph_name_); if (do_check_rr_graph_) { check_rr_graph(*rr_graph_, @@ -2162,7 +2162,7 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { vtr::vector* rr_switch_inf_; vtr::vector* rr_indexed_data_; t_rr_node_indices* rr_node_indices_; - std::string* read_rr_graph_filename_; + std::string* loaded_rr_graph_filename_; std::vector* rr_rc_data_; // Constant data for loads and writes. diff --git a/libs/librrgraph/src/io/rr_graph_writer.cpp b/libs/librrgraph/src/io/rr_graph_writer.cpp index 0e48dd866aa..291d9ffafa4 100644 --- a/libs/librrgraph/src/io/rr_graph_writer.cpp +++ b/libs/librrgraph/src/io/rr_graph_writer.cpp @@ -21,7 +21,7 @@ /************************ Subroutine definitions ****************************/ -/* This function is used to write the rr_graph into xml format into a a file with name: file_name */ +/* This function is used to write the rr_graph into xml format into a file with name: file_name */ /**FIXME: To make rr_graph_reader independent of vpr_context, the below * parameters are a workaround to passing the data structures of DeviceContext. diff --git a/utils/route_diag/CMakeLists.txt b/utils/route_diag/CMakeLists.txt index 809785c939a..b6b41592df9 100644 --- a/utils/route_diag/CMakeLists.txt +++ b/utils/route_diag/CMakeLists.txt @@ -8,7 +8,7 @@ target_link_libraries(route_diag libvpr ) -#Supress IPO link warnings if IPO is enabled +#Suppress IPO link warnings if IPO is enabled get_target_property(TEST_ROUTE_DIAG_USES_IPO route_diag INTERPROCEDURAL_OPTIMIZATION) if (TEST_ROUTE_DIAG_USES_IPO) set_property(TARGET route_diag APPEND PROPERTY LINK_FLAGS ${IPO_LINK_WARN_SUPRESS_FLAGS}) diff --git a/utils/route_diag/src/main.cpp b/utils/route_diag/src/main.cpp index 6812b5bc881..5074d79cc09 100644 --- a/utils/route_diag/src/main.cpp +++ b/utils/route_diag/src/main.cpp @@ -247,7 +247,7 @@ t_route_util_options read_route_util_options(int argc, const char** argv) { route_diag_grp.add_argument(args.profile_source, "--profile_source") .help( "Profile routes from source to IPINs at all locations." - "This is similiar to the placer delay matrix construction.") + "This is similar to the placer delay matrix construction.") .show_in(argparse::ShowIn::HELP_ONLY); parser.parse_args(argc, argv); diff --git a/utils/vqm2blif/test/scripts/test_vqm2blif.sh b/utils/vqm2blif/test/scripts/test_vqm2blif.sh index 98966a9bc45..60c217a99e5 100755 --- a/utils/vqm2blif/test/scripts/test_vqm2blif.sh +++ b/utils/vqm2blif/test/scripts/test_vqm2blif.sh @@ -259,7 +259,7 @@ do done -# we create seperate subshells to process each iteration of the loops above. +# we create separate subshells to process each iteration of the loops above. # So below we check the result of the last shell. if [ $? -eq 1 ]; then diff --git a/vpr/src/base/SetupVPR.cpp b/vpr/src/base/SetupVPR.cpp index 78b8f797ff5..e645b35e538 100644 --- a/vpr/src/base/SetupVPR.cpp +++ b/vpr/src/base/SetupVPR.cpp @@ -236,6 +236,7 @@ void SetupVPR(const t_options* options, SetupAPOpts(*options, *apOpts); routingArch->write_rr_graph_filename = options->write_rr_graph_file; routingArch->read_rr_graph_filename = options->read_rr_graph_file; + routingArch->read_rr_edge_override_filename = options->read_rr_edge_override_file; for (auto has_global_routing : arch->layer_global_routing) { device_ctx.inter_cluster_prog_routing_resources.emplace_back(has_global_routing); diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index 26f9b5bb132..4451dd720cd 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -1769,19 +1769,26 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio .show_in(argparse::ShowIn::HELP_ONLY); file_grp.add_argument(args.read_rr_graph_file, "--read_rr_graph") - .help( - "The routing resource graph file to load." - " The loaded routing resource graph overrides any routing architecture specified in the architecture file.") + .help("The routing resource graph file to load. " + "The loaded routing resource graph overrides any routing architecture specified in the architecture file.") .metavar("RR_GRAPH_FILE") .show_in(argparse::ShowIn::HELP_ONLY); + file_grp.add_argument(args.read_rr_edge_override_file, "--read_rr_edge_override") + .help("The routing resource edge attributes override file to load. " + "This file overrides edge attributes in the routing resource graph. " + "The user can use the architecture file to specify nominal switch delays, " + "while this file can be used to override the nominal delays to make it more accurate " + "for specific edges.") + .show_in(argparse::ShowIn::HELP_ONLY); + file_grp.add_argument(args.write_rr_graph_file, "--write_rr_graph") - .help("Writes the routing resource graph to the specified file") + .help("Writes the routing resource graph to the specified file.") .metavar("RR_GRAPH_FILE") .show_in(argparse::ShowIn::HELP_ONLY); file_grp.add_argument(args.write_initial_place_file, "--write_initial_place_file") - .help("Writes out the the placement chosen by the initial placement algorithm to the specified file") + .help("Writes out the the placement chosen by the initial placement algorithm to the specified file.") .metavar("INITIAL_PLACE_FILE") .show_in(argparse::ShowIn::HELP_ONLY); @@ -3355,7 +3362,7 @@ void set_conditional_defaults(t_options& args) { bool verify_args(const t_options& args) { /* - * Check for conflicting paramaters or dependencies where one parameter set requires another parameter to be included + * Check for conflicting parameters or dependencies where one parameter set requires another parameter to be included */ if (args.read_rr_graph_file.provenance() == Provenance::SPECIFIED && args.RouteChanWidth.provenance() != Provenance::SPECIFIED) { diff --git a/vpr/src/base/read_options.h b/vpr/src/base/read_options.h index dd1be4b2575..a71ba63428a 100644 --- a/vpr/src/base/read_options.h +++ b/vpr/src/base/read_options.h @@ -29,6 +29,7 @@ struct t_options { argparse::ArgValue constraints_file; argparse::ArgValue write_rr_graph_file; argparse::ArgValue read_rr_graph_file; + argparse::ArgValue read_rr_edge_override_file; argparse::ArgValue write_initial_place_file; argparse::ArgValue read_initial_place_file; argparse::ArgValue read_vpr_constraints_file; diff --git a/vpr/src/base/vpr_context.h b/vpr/src/base/vpr_context.h index f27bfa0d4ff..3a5ca67df21 100644 --- a/vpr/src/base/vpr_context.h +++ b/vpr/src/base/vpr_context.h @@ -269,12 +269,15 @@ struct DeviceContext : public Context { ********************************************************************/ t_clock_arch* clock_arch; - /** - * @brief Name of rrgraph file read (if any). - * - * Used to determine when reading rrgraph if file is already loaded. - */ - std::string read_rr_graph_filename; + /// @brief Name of rrgraph file read (if any). + /// Used to determine if the specified rr-graph file is already loaded, + /// so we can avoid redundant reading of the rr-graph + std::string loaded_rr_graph_filename; + + /// @brief Name of rrgraph edge override file read (if any). + /// Used to determine if the specified rr-graph edge override file is already loaded, + /// so we can avoid redundant reading of the rr-graph + std::string loaded_rr_edge_override_filename; /******************************************************************* * Place Related diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index 3bad2e48d3a..ddbcb59b08e 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -734,7 +734,7 @@ struct t_packer_opts { bool use_attraction_groups; int pack_num_moves; std::string pack_move_type; - bool load_flat_placement; + bool load_flat_placement = false; }; /** @@ -1289,7 +1289,7 @@ struct t_analysis_opts { e_timing_update_type timing_update_type; }; -// used to store NoC specific options, when supplied as an input by the user +/// Stores NoC specific options, when supplied as an input by the user struct t_noc_opts { bool noc; /// switchblocks; short global_route_switch; + + /// Index of a zero delay switch (used to connect things that should have no delay). short delayless_switch; + + /// Keeps track of the type of architecture switch that connects wires to ipins int wire_to_arch_ipin_switch; + + /// Keeps track of the type of architecture switch that connects + /// wires from another die to ipins in different die int wire_to_arch_ipin_switch_between_dice = -1; + + /// keeps track of the type of RR graph switch + /// that connects wires to ipins in the RR graph int wire_to_rr_ipin_switch; + + /// keeps track of the type of RR graph switch that connects wires + /// from another die to ipins in different die in the RR graph int wire_to_rr_ipin_switch_between_dice = -1; + + /// Resistance (in Ohms) of a minimum width nmos transistor. + /// Used only in the FPGA area model. float R_minW_nmos; + + /// Resistance (in Ohms) of a minimum width pmos transistor. float R_minW_pmos; + /// File to read the RR graph from (overrides architecture) std::string read_rr_graph_filename; + /// File to write the RR graph to after generation std::string write_rr_graph_filename; + /// File to read the RR graph edge attribute overrides. + std::string read_rr_edge_override_filename; }; constexpr bool is_pin(e_rr_type type) { return (type == IPIN || type == OPIN); } diff --git a/vpr/src/route/rr_graph.cpp b/vpr/src/route/rr_graph.cpp index a5a72fbe878..072b62c1c98 100644 --- a/vpr/src/route/rr_graph.cpp +++ b/vpr/src/route/rr_graph.cpp @@ -1,7 +1,5 @@ #include -#include #include -#include #include #include #include @@ -23,7 +21,6 @@ #include "rr_graph_utils.h" #include "rr_graph.h" #include "rr_graph_area.h" -#include "rr_graph_utils.h" #include "rr_graph2.h" #include "rr_graph_sbox.h" #include "rr_graph_timing_params.h" @@ -35,9 +32,7 @@ #include "rr_graph_clock.h" #include "edge_groups.h" #include "rr_graph_builder.h" - #include "rr_types.h" -#include "echo_files.h" //#define VERBOSE //used for getting the exact count of each edge type and printing it to std out. @@ -773,7 +768,7 @@ void create_rr_graph(e_graph_type graph_type, } } else { if (load_rr_graph) { - if (device_ctx.read_rr_graph_filename != det_routing_arch->read_rr_graph_filename) { + if (device_ctx.loaded_rr_graph_filename != det_routing_arch->read_rr_graph_filename) { free_rr_graph(); load_rr_file(&mutable_device_ctx.rr_graph_builder, @@ -791,7 +786,7 @@ void create_rr_graph(e_graph_type graph_type, &det_routing_arch->wire_to_rr_ipin_switch, &det_routing_arch->wire_to_arch_ipin_switch_between_dice, det_routing_arch->read_rr_graph_filename.c_str(), - &det_routing_arch->read_rr_graph_filename, + &mutable_device_ctx.loaded_rr_graph_filename, router_opts.read_rr_edge_metadata, router_opts.do_check_rr_graph, echo_enabled, @@ -828,6 +823,18 @@ void create_rr_graph(e_graph_type graph_type, Warnings, router_opts.route_verbosity); } + + // Check if there is an edge override file to read and that it is not already loaded. + if (!det_routing_arch->read_rr_edge_override_filename.empty() + && det_routing_arch->read_rr_edge_override_filename != device_ctx.loaded_rr_edge_override_filename) { + + load_rr_edge_delay_overrides(det_routing_arch->read_rr_edge_override_filename, + mutable_device_ctx.rr_graph_builder, + device_ctx.rr_graph); + + // Remember the loaded filename to avoid reloading it before the RR graph is cleared. + mutable_device_ctx.loaded_rr_edge_override_filename = det_routing_arch->read_rr_edge_override_filename; + } } if (is_flat) { @@ -2740,7 +2747,8 @@ void free_rr_graph() { * allocated, as ALL the chunk allocated data is already free! */ auto& device_ctx = g_vpr_ctx.mutable_device(); - device_ctx.read_rr_graph_filename.clear(); + device_ctx.loaded_rr_graph_filename.clear(); + device_ctx.loaded_rr_edge_override_filename.clear(); device_ctx.rr_graph_builder.clear(); diff --git a/vpr/test/test_connection_router.cpp b/vpr/test/test_connection_router.cpp index c824d9b876e..138e003b04e 100644 --- a/vpr/test/test_connection_router.cpp +++ b/vpr/test/test_connection_router.cpp @@ -143,8 +143,7 @@ TEST_CASE("connection_router", "[vpr]") { kArchFile, "wire.eblif", "--route_chan_width", "100"}; - vpr_init(sizeof(argv) / sizeof(argv[0]), argv, - &options, &vpr_setup, &arch); + vpr_init(sizeof(argv) / sizeof(argv[0]), argv, &options, &vpr_setup, &arch); vpr_create_device_grid(vpr_setup, arch); vpr_setup_clock_networks(vpr_setup, arch); diff --git a/vpr/test/test_read_rr_edge_override.txt b/vpr/test/test_read_rr_edge_override.txt new file mode 100644 index 00000000000..05cccc8cbb9 --- /dev/null +++ b/vpr/test/test_read_rr_edge_override.txt @@ -0,0 +1,9 @@ +# edge Tdel +12 5.9e-11 +1586 4.2e-11 +1111 7.1e-11 +1324 9.4e-11 +(645, 127) 7.3e-11 +(591, 347) 7.9e-11 +(544, 45) 8.3e-11 +(37 , 511) 9.5e-11 \ No newline at end of file diff --git a/vpr/test/test_vpr.cpp b/vpr/test/test_vpr.cpp index 5d162c579bc..c05d33e54f9 100644 --- a/vpr/test/test_vpr.cpp +++ b/vpr/test/test_vpr.cpp @@ -232,4 +232,163 @@ TEST_CASE("read_rr_graph_metadata", "[vpr]") { vpr_free_all(arch, vpr_setup); } +TEST_CASE("read_rr_edge_override", "[vpr]") { + + const std::string RR_GRAPH_NAME = "test_read_rr_edge_override"; + const std::string RR_EDGE_OVERRIDE_FILENAME = "test_read_rr_edge_override.txt"; + const std::array file_extensions{".xml", ".bin"}; + + // We test both xml and binary file formats + for (const std::string& file_extension : file_extensions) { + std::string rr_graph_filename = RR_GRAPH_NAME + file_extension; + std::string overridden_rr_graph_filename = RR_GRAPH_NAME + "_overridden" + file_extension; + + RRNodeId src_inode = RRNodeId::INVALID(); + RRNodeId sink_inode = RRNodeId::INVALID(); + short switch_id = -1; + + { // Generate an RR graph and write it out + t_vpr_setup vpr_setup; + t_arch arch; + t_options options; + const char* argv[] = { + "test_vpr", + kArchFile, + "wire.eblif", + "--route_chan_width", + "100"}; + vpr_init(sizeof(argv) / sizeof(argv[0]), argv, &options, &vpr_setup, &arch); + vpr_create_device(vpr_setup, arch); + + const auto& device_ctx = g_vpr_ctx.device(); + auto& mutable_device_ctx = g_vpr_ctx.mutable_device(); + const auto& rr_graph = device_ctx.rr_graph; + bool echo_enabled = getEchoEnabled() && isEchoFileEnabled(E_ECHO_RR_GRAPH_INDEXED_DATA); + const char* echo_file_name = getEchoFileName(E_ECHO_RR_GRAPH_INDEXED_DATA); + + for (const RRNodeId inode : device_ctx.rr_graph.nodes()) { + if ((rr_graph.node_type(inode) == CHANX || rr_graph.node_type(inode) == CHANY) && rr_graph.num_edges(inode) > 0) { + src_inode = inode; + break; + } + } + + REQUIRE(src_inode.is_valid()); + sink_inode = rr_graph.edge_sink_node(RRNodeId(src_inode), 0); + switch_id = rr_graph.edge_switch(RRNodeId(src_inode), 0); + + write_rr_graph(&mutable_device_ctx.rr_graph_builder, + &mutable_device_ctx.rr_graph, + device_ctx.physical_tile_types, + &mutable_device_ctx.rr_indexed_data, + &mutable_device_ctx.rr_rc_data, + device_ctx.grid, + device_ctx.arch_switch_inf, + device_ctx.arch, + &mutable_device_ctx.chan_width, + rr_graph_filename.c_str(), + echo_enabled, + echo_file_name, + false); + + vpr_free_all(arch, vpr_setup); + } + + REQUIRE(src_inode.is_valid()); + REQUIRE(sink_inode.is_valid()); + REQUIRE(switch_id != -1); + + { // Override edge attributes + t_vpr_setup vpr_setup; + t_arch arch; + t_options options; + const char* argv[] = { + "test_vpr", + kArchFile, + "wire.eblif", + "--route_chan_width", + "100", + "--read_rr_graph", + rr_graph_filename.c_str(), + "--read_rr_edge_override", + RR_EDGE_OVERRIDE_FILENAME.c_str()}; + + vpr_init(sizeof(argv) / sizeof(argv[0]), argv, &options, &vpr_setup, &arch); + vpr_create_device(vpr_setup, arch); + + const auto& device_ctx = g_vpr_ctx.device(); + auto& mutable_device_ctx = g_vpr_ctx.mutable_device(); + bool echo_enabled = getEchoEnabled() && isEchoFileEnabled(E_ECHO_RR_GRAPH_INDEXED_DATA); + const char* echo_file_name = getEchoFileName(E_ECHO_RR_GRAPH_INDEXED_DATA); + + write_rr_graph(&mutable_device_ctx.rr_graph_builder, + &mutable_device_ctx.rr_graph, + device_ctx.physical_tile_types, + &mutable_device_ctx.rr_indexed_data, + &mutable_device_ctx.rr_rc_data, + device_ctx.grid, + device_ctx.arch_switch_inf, + device_ctx.arch, + &mutable_device_ctx.chan_width, + overridden_rr_graph_filename.c_str(), + echo_enabled, + echo_file_name, + false); + + vpr_free_all(arch, vpr_setup); + } + + { // Verify overridden values + t_vpr_setup vpr_setup; + t_arch arch; + t_options options; + const char* argv[] = { + "test_vpr", + kArchFile, + "wire.eblif", + "--route_chan_width", + "100", + "--read_rr_graph", + overridden_rr_graph_filename.c_str()}; + + vpr_init(sizeof(argv) / sizeof(argv[0]), argv, &options, &vpr_setup, &arch); + vpr_create_device(vpr_setup, arch); + + const auto& device_ctx = g_vpr_ctx.device(); + const auto& rr_graph = device_ctx.rr_graph; + + switch_id = rr_graph.edge_switch((RREdgeId)12); + REQUIRE(rr_graph.rr_switch_inf((RRSwitchId)switch_id).Tdel == 5.9e-11f); + + switch_id = rr_graph.edge_switch((RREdgeId)1586); + REQUIRE(rr_graph.rr_switch_inf((RRSwitchId)switch_id).Tdel == 4.2e-11f); + + switch_id = rr_graph.edge_switch((RREdgeId)1111); + REQUIRE(rr_graph.rr_switch_inf((RRSwitchId)switch_id).Tdel == 7.1e-11f); + + switch_id = rr_graph.edge_switch((RREdgeId)1324); + REQUIRE(rr_graph.rr_switch_inf((RRSwitchId)switch_id).Tdel == 9.4e-11f); + + RREdgeId edge_id; + edge_id = rr_graph.rr_nodes().edge_id((RRNodeId)645, (RRNodeId)127); + switch_id = rr_graph.edge_switch(edge_id); + REQUIRE(rr_graph.rr_switch_inf((RRSwitchId)switch_id).Tdel == 7.3e-11f); + + edge_id = rr_graph.rr_nodes().edge_id((RRNodeId)591, (RRNodeId)347); + switch_id = rr_graph.edge_switch(edge_id); + REQUIRE(rr_graph.rr_switch_inf((RRSwitchId)switch_id).Tdel == 7.9e-11f); + + edge_id = rr_graph.rr_nodes().edge_id((RRNodeId)544, (RRNodeId)45); + switch_id = rr_graph.edge_switch(edge_id); + REQUIRE(rr_graph.rr_switch_inf((RRSwitchId)switch_id).Tdel == 8.3e-11f); + + edge_id = rr_graph.rr_nodes().edge_id((RRNodeId)37, (RRNodeId)511); + switch_id = rr_graph.edge_switch(edge_id); + REQUIRE(rr_graph.rr_switch_inf((RRSwitchId)switch_id).Tdel == 9.5e-11f); + + vpr_free_all(arch, vpr_setup); + } + } +} + } // namespace