diff --git a/libs/libarchfpga/src/arch_check.cpp b/libs/libarchfpga/src/arch_check.cpp index 0b8f88e1f10..022e2d57ded 100644 --- a/libs/libarchfpga/src/arch_check.cpp +++ b/libs/libarchfpga/src/arch_check.cpp @@ -86,7 +86,7 @@ void warn_model_missing_timing(const t_model* model, const char* file, uint32_t for (t_model_ports* port = model->outputs; port != nullptr; port = port->next) { if (port->clock.empty() //Not sequential - && !comb_connected_outputs.count(port->name) //Not combinationally drivven + && !comb_connected_outputs.count(port->name) //Not combinationally driven && !port->is_clock //Not an output clock ) { VTR_LOGF_WARN(file, line, diff --git a/libs/libarchfpga/src/arch_types.h b/libs/libarchfpga/src/arch_types.h index 9f88a64669e..69ac28ae479 100644 --- a/libs/libarchfpga/src/arch_types.h +++ b/libs/libarchfpga/src/arch_types.h @@ -18,7 +18,10 @@ /* Value for UNDEFINED data */ constexpr int UNDEFINED = -1; -/* Maximum value for mininum channel width to avoid overflows of short data type. */ +/** The total number of predefined blif models */ +constexpr int NUM_MODELS_IN_LIBRARY = 4; + +/* Maximum value for minimum channel width to avoid overflows of short data type. */ constexpr int MAX_CHANNEL_WIDTH = 8000; /* Built-in library models */ diff --git a/libs/libarchfpga/src/arch_util.cpp b/libs/libarchfpga/src/arch_util.cpp index a6b804bf0d3..4a111a38c4e 100644 --- a/libs/libarchfpga/src/arch_util.cpp +++ b/libs/libarchfpga/src/arch_util.cpp @@ -520,7 +520,7 @@ t_port* findPortByName(const char* name, t_pb_type* pb_type, int* high_index, in return port; } -t_physical_tile_type get_empty_physical_type(const char* name) { +t_physical_tile_type get_empty_physical_type(const char* name /*= EMPTY_BLOCK_NAME*/) { t_physical_tile_type type; type.name = vtr::strdup(name); type.num_pins = 0; @@ -538,7 +538,7 @@ t_physical_tile_type get_empty_physical_type(const char* name) { return type; } -t_logical_block_type get_empty_logical_type(const char* name) { +t_logical_block_type get_empty_logical_type(const char* name /*=EMPTY_BLOCK_NAME*/) { t_logical_block_type type; type.name = vtr::strdup(name); type.pb_type = nullptr; diff --git a/libs/libarchfpga/src/main.cpp b/libs/libarchfpga/src/main.cpp index 6a9e3f354d1..81b49860c5c 100644 --- a/libs/libarchfpga/src/main.cpp +++ b/libs/libarchfpga/src/main.cpp @@ -5,12 +5,11 @@ * Author: Jason Luu */ -#include -#include +#include +#include #include #include "vtr_error.h" -#include "vtr_memory.h" #include "arch_util.h" #include "read_xml_arch_file.h" diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index c00d65bfb41..b98ea5b368e 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -28,6 +28,7 @@ #define PHYSICAL_TYPES_H #include +#include #include #include #include @@ -129,7 +130,7 @@ struct t_metadata_dict : vtr::flat_map< // Get metadata values matching key. // - // Returns nullptr if key is not found or if multiple values are prsent + // Returns nullptr if key is not found or if multiple values are present // per key. inline const t_metadata_value* one(vtr::interned_string key) const { auto values = get(key); @@ -146,7 +147,7 @@ struct t_metadata_dict : vtr::flat_map< void add(vtr::interned_string key, vtr::interned_string value) { // Get the iterator to the key, which may already have elements if // add was called with this key in the past. - (*this)[key].emplace_back(t_metadata_value(value)); + (*this)[key].emplace_back(value); } }; @@ -181,11 +182,11 @@ constexpr std::array SIDES = {{TOP, RIGHT, BOTTOM, LEFT}}; constexpr std::array SIDE_STRING = {{"TOP", "RIGHT", "BOTTOM", "LEFT"}}; //String versions of side orientations /* pin location distributions */ -enum e_pin_location_distr { - E_SPREAD_PIN_DISTR, - E_PERIMETER_PIN_DISTR, - E_SPREAD_INPUTS_PERIMETER_OUTPUTS_PIN_DISTR, - E_CUSTOM_PIN_DISTR +enum class e_pin_location_distr { + SPREAD, + PERIMETER, + SPREAD_INPUTS_PERIMETER_OUTPUTS, + CUSTOM }; /* pb_type class */ @@ -263,10 +264,10 @@ enum e_sb_location { */ struct t_grid_loc_spec { t_grid_loc_spec(std::string start, std::string end, std::string repeat, std::string incr) - : start_expr(start) - , end_expr(end) - , repeat_expr(repeat) - , incr_expr(incr) {} + : start_expr(std::move(start)) + , end_expr(std::move(end)) + , repeat_expr(std::move(repeat)) + , incr_expr(std::move(incr)) {} std::string start_expr; //Starting position (inclusive) std::string end_expr; //Ending position (inclusive) @@ -280,7 +281,7 @@ struct t_grid_loc_spec { /* Definition of how to place physical logic block in the grid. * This defines a region of the grid to be set to a specific type - * (provided it's priority is high enough to override other blocks). + * (provided its priority is high enough to override other blocks). * * The diagram below illustrates the layout specification. * @@ -345,7 +346,7 @@ struct t_grid_loc_spec { */ struct t_grid_loc_def { t_grid_loc_def(std::string block_type_val, int priority_val) - : block_type(block_type_val) + : block_type(std::move(block_type_val)) , priority(priority_val) , x("0", "W-1", "max(w+1,W)", "w") //Fill in x direction, no repeat, incr by block width , y("0", "H-1", "max(h+1,H)", "h") //Fill in y direction, no repeat, incr by block height @@ -358,7 +359,7 @@ struct t_grid_loc_def { // the largest priority wins. t_grid_loc_spec x; //Horizontal location specification - t_grid_loc_spec y; //Veritcal location specification + t_grid_loc_spec y; //Vertical location specification // When 1 metadata tag is split among multiple t_grid_loc_def, one // t_grid_loc_def is arbitrarily chosen to own the metadata, and the other @@ -648,7 +649,7 @@ struct t_physical_tile_type { std::vector class_inf; /* [0..num_class-1] */ - // Primitive class is refered to a classes that are in the primitive blocks. These classes are + // Primitive class is referred to a classes that are in the primitive blocks. These classes are // used during flat-routing to route the nets. // The starting number of primitive classes int primitive_class_starting_idx = -1; @@ -755,7 +756,7 @@ struct t_capacity_range { struct t_sub_tile { char* name = nullptr; - // Mapping between the sub tile's pins and the physical pins corresponding + // Mapping between the subtile's pins and the physical pins corresponding // to the physical tile type. std::vector sub_tile_to_tile_pin_indices; @@ -1601,7 +1602,7 @@ struct t_hash_segment_inf { enum class SwitchType { MUX = 0, //A configurable (buffered) mux (single-driver) TRISTATE, //A configurable tristate-able buffer (multi-driver) - PASS_GATE, //A configurable pass transitor switch (multi-driver) + PASS_GATE, //A configurable pass transistor switch (multi-driver) SHORT, //A non-configurable electrically shorted connection (multi-driver) BUFFER, //A non-configurable non-tristate-able buffer (uni-driver) INVALID, //Unspecified, usually an error @@ -1946,6 +1947,16 @@ struct t_noc_inf { /** A list of all routers in the NoC*/ std::vector router_list; + /** Stores NoC routers that have a different latency than the NoC-wide router latency. + * (router_user_id, overridden router latency)*/ + std::map router_latency_overrides; + /** Stores NoC links that have a different latency than the NoC-wide link latency. + * ((source router id, destination router id), overridden link latency)*/ + std::map, double> link_latency_overrides; + /** Stores NoC links that have a different bandwidth than the NoC-wide link bandwidth. + * ((source router id, destination router id), overridden link bandwidth)*/ + std::map, double> link_bandwidth_overrides; + /** Represents the name of a router tile on the FPGA device. This should match the name used in the arch file when * describing a NoC router tile within the FPGA device*/ std::string noc_router_tile_name; @@ -1953,6 +1964,8 @@ struct t_noc_inf { /* Detailed routing architecture */ struct t_arch { + /** Stores unique strings used as key and values in tags, + * i.e. implements a flyweight pattern to save memory.*/ mutable vtr::string_internment strings; std::vector interned_strings; @@ -1992,7 +2005,7 @@ struct t_arch { // nets from the circuit netlist are belonging to the constant network, // and assigned to it accordingly. // - // NOTE: At the moment, the constant cells and nets are primarly used + // NOTE: At the moment, the constant cells and nets are primarily used // for the interchange netlist format, to determine which are the constants // net names and which virtual cell is responsible to generate them. // The information is present in the device database. diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index fa605911698..f4581a48bf7 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -3,7 +3,7 @@ * will generate two pugi::xml_nodes. One called "a" and its * child "b". Each pugi::xml_node can contain various XML data such as attribute * information and text content. The XML parser provides several functions to - * help the developer build, and traverse tree (this is also somtime referred to + * help the developer build, and traverse tree (this is also sometimes referred to * as the Document Object Model or DOM). * * For convenience, it often makes sense to use some wraper functions (provided in @@ -36,7 +36,7 @@ * */ -#include +#include #include #include #include @@ -65,6 +65,8 @@ #include "physical_types_util.h" +#include "read_xml_arch_file_noc_tag.h" + using namespace std::string_literals; using pugiutil::ReqOpt; @@ -80,7 +82,7 @@ struct t_pin_counts { int output = 0; int clock = 0; - int total() { + int total() const { return input + output + clock; } }; @@ -92,12 +94,12 @@ struct t_pin_locs { bool distribution_set = false; public: - enum e_pin_location_distr distribution = E_SPREAD_PIN_DISTR; + e_pin_location_distr distribution = e_pin_location_distr::SPREAD; /* [0..num_sub_tiles-1][0..width-1][0..height-1][0..num_of_layer-1][0..3][0..num_tokens-1] */ vtr::NdMatrix, 5> assignments; - bool is_distribution_set() { + bool is_distribution_set() const { return distribution_set; } @@ -128,21 +130,25 @@ static void ProcessTiles(pugi::xml_node Node, const t_default_fc_spec& arch_def_fc, t_arch& arch, const pugiutil::loc_data& loc_data, - const int num_of_avail_layer); + int num_of_avail_layer); + // TODO: Remove block_type_contains_blif_model / pb_type_contains_blif_model // as part of // https://github.com/verilog-to-routing/vtr-verilog-to-routing/issues/1193 static void MarkIoTypes(std::vector& PhysicalTileTypes); + static void ProcessTileProps(pugi::xml_node Node, t_physical_tile_type* PhysicalTileType, const pugiutil::loc_data& loc_data); + static t_pin_counts ProcessSubTilePorts(pugi::xml_node Parent, t_sub_tile* SubTile, - std::unordered_map& tile_port_names, const pugiutil::loc_data& loc_data); + static void ProcessTilePort(pugi::xml_node Node, t_physical_tile_port* port, const pugiutil::loc_data& loc_data); + static void ProcessTileEquivalentSites(pugi::xml_node Parent, t_sub_tile* SubTile, t_physical_tile_type* PhysicalTileType, @@ -165,21 +171,38 @@ static void ProcessPinLocations(pugi::xml_node Locations, t_pin_locs* pin_locs, const pugiutil::loc_data& loc_data, const int num_of_avail_layer); + static void ProcessSubTiles(pugi::xml_node Node, t_physical_tile_type* PhysicalTileType, std::vector& LogicalBlockTypes, std::vector& segments, const t_default_fc_spec& arch_def_fc, const pugiutil::loc_data& loc_data, - const int num_of_avail_layer); -static void ProcessPb_Type(vtr::string_internment* strings, - pugi::xml_node Parent, + int num_of_avail_layer); + +/** + * @brief Parses a tag and all and tags under it. + * + * @param Parent An XML node pointing to tag to be processed + * @param pb_type To be filled by this function with parsed information + * about the given pb_type + * @param mode The parent mode of the pb_type to be processed. If the given + * pb_type is the root, nullptr should be passed. + * @param timing_enabled Determines whether timing-aware optimizations are enabled. + * @param arch Contains high-level architecture information like models and + * string interment storage. + * @param loc_data Points to the location in the architecture file where the parser is reading. + * @param pb_idx Used to assign unique values to index_in_logical_block field in +* t_pb_type for all pb_types under a logical block type. + */ +static void ProcessPb_Type(pugi::xml_node Parent, t_pb_type* pb_type, t_mode* mode, - const bool timing_enabled, + bool timing_enabled, const t_arch& arch, const pugiutil::loc_data& loc_data, int& pb_idx); + static void ProcessPb_TypePort(pugi::xml_node Parent, t_port* port, e_power_estimation_method power_method, @@ -189,15 +212,56 @@ static void ProcessPinToPinAnnotations(pugi::xml_node parent, t_pin_to_pin_annotation* annotation, t_pb_type* parent_pb_type, const pugiutil::loc_data& loc_data); -static void ProcessInterconnect(vtr::string_internment* strings, pugi::xml_node Parent, t_mode* mode, const pugiutil::loc_data& loc_data); -static void ProcessMode(vtr::string_internment* strings, - pugi::xml_node Parent, + +/** + * @brief Parses tags under a or tag. + * + * @param strings String internment storage used to store strings used + * as keys and values in tags under the given tag. + * @param Parent An XML node pointing to tag to be processed + * @param mode To be filled with interconnect-related information. + * @param loc_data Points to the location in the architecture file where + * the parser is reading. + */ +static void ProcessInterconnect(vtr::string_internment& strings, + pugi::xml_node Parent, + t_mode* mode, + const pugiutil::loc_data& loc_data); + +/** + * @brief Processes a tag under tag in the architecture file. + * If a tag does not have any tags, a default mode is implied. + * + * @param Parent An XML node referring to either tag or tag. + * It the XML node refers to tag, the mode is implied. + * @param mode Mode information to be filled by this function. + * @param timing_enabled Determines whether timing-aware optimizations are enabled. + * @param arch Contains high-level architecture information like models and + * string interment storage. + * @param loc_data Points to the location in the architecture file where the parser is reading. + * @param parent_pb_idx Used to assign unique values to index_in_logical_block field in + * t_pb_type for all pb_types under a logical block type. + */ +static void ProcessMode(pugi::xml_node Parent, t_mode* mode, - const bool timing_enabled, + bool timing_enabled, const t_arch& arch, const pugiutil::loc_data& loc_data, int& parent_pb_idx); -static t_metadata_dict ProcessMetadata(vtr::string_internment* strings, pugi::xml_node Parent, const pugiutil::loc_data& loc_data); +/** + * @brief Processes tags. + * + * @param strings String internment storage used to store strings used +* as keys and values in tags. + * @param Parent An XML node pointing to the parent tag whose children + * are to be parsed. + * @param loc_data Points to the location in the architecture file where the parser is reading. + * @return A t_metadata_dict that stored parsed (key, value) pairs. + */ +static t_metadata_dict ProcessMetadata(vtr::string_internment& strings, + pugi::xml_node Parent, + const pugiutil::loc_data& loc_data); + static void Process_Fc_Values(pugi::xml_node Node, t_default_fc_spec& spec, const pugiutil::loc_data& loc_data); static void Process_Fc(pugi::xml_node Node, t_physical_tile_type* PhysicalTileType, @@ -207,10 +271,23 @@ static void Process_Fc(pugi::xml_node Node, const t_default_fc_spec& arch_def_fc, const pugiutil::loc_data& loc_data); static t_fc_override Process_Fc_override(pugi::xml_node node, const pugiutil::loc_data& loc_data); + +/** + * @brief Processes optional tag under a tag// + * + * @param switchblock_locations An XML node pointing to tag + * if it exists. + * @param type To be filled with information extracted from the given + * tag. This function fills switchblock_locations and + * switchblock_switch_overrides fields. + * @param arch Used to find switchblock by name + * @param loc_data Points to the location in the xml file where the parser is reading. + */ static void ProcessSwitchblockLocations(pugi::xml_node switchblock_locations, t_physical_tile_type* type, const t_arch& arch, const pugiutil::loc_data& loc_data); + static e_fc_value_type string_to_fc_value_type(const std::string& str, pugi::xml_node node, const pugiutil::loc_data& loc_data); static void ProcessChanWidthDistr(pugi::xml_node Node, t_arch* arch, @@ -219,11 +296,27 @@ static void ProcessChanWidthDistrDir(pugi::xml_node Node, t_chan* chan, const pu static void ProcessModels(pugi::xml_node Node, t_arch* arch, const pugiutil::loc_data& loc_data); static void ProcessModelPorts(pugi::xml_node port_group, t_model* model, std::set& port_names, const pugiutil::loc_data& loc_data); static void ProcessLayout(pugi::xml_node Node, t_arch* arch, const pugiutil::loc_data& loc_data, int& num_of_avail_layer); -static t_grid_def ProcessGridLayout(vtr::string_internment* strings, pugi::xml_node layout_type_tag, const pugiutil::loc_data& loc_data, t_arch* arch, int& num_of_avail_layer); -static void ProcessBlockTypeLocs(t_grid_def& grid_def, int die_number, vtr::string_internment* strings, pugi::xml_node layout_block_type_tag, const pugiutil::loc_data& loc_data); +static t_grid_def ProcessGridLayout(vtr::string_internment& strings, pugi::xml_node layout_type_tag, const pugiutil::loc_data& loc_data, t_arch* arch, int& num_of_avail_layer); +static void ProcessBlockTypeLocs(t_grid_def& grid_def, int die_number, vtr::string_internment& strings, pugi::xml_node layout_block_type_tag, const pugiutil::loc_data& loc_data); static int get_number_of_layers(pugi::xml_node layout_type_tag, const pugiutil::loc_data& loc_data); static void ProcessDevice(pugi::xml_node Node, t_arch* arch, t_default_fc_spec& arch_def_fc, const pugiutil::loc_data& loc_data); -static void ProcessComplexBlocks(vtr::string_internment* strings, pugi::xml_node Node, std::vector& LogicalBlockTypes, t_arch& arch, const bool timing_enabled, const pugiutil::loc_data& loc_data); + +/** + * @brief Parses tag in the architecture file. + * + * @param Node The xml node referring to tag + * @param LogicalBlockTypes This function fills this vector with all available + * logical block types. + * @param arch Used to access models and string internment storage. + * @param timing_enabled Determines whether timing-aware optimizations are enabled. + * @param loc_data Points to the location in the xml file where the parser is reading. + */ +static void ProcessComplexBlocks(pugi::xml_node Node, + std::vector& LogicalBlockTypes, + const t_arch& arch, + bool timing_enabled, + const pugiutil::loc_data& loc_data); + static void ProcessSwitches(pugi::xml_node Node, t_arch_switch_inf** Switches, int* NumSwitches, @@ -264,13 +357,6 @@ static void ProcessPower(pugi::xml_node parent, static void ProcessClocks(pugi::xml_node Parent, t_clock_arch* clocks, const pugiutil::loc_data& loc_data); -static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc_data& loc_data); - -static void processTopology(pugi::xml_node topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref); - -static void processMeshTopology(pugi::xml_node mesh_topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref); - -static void processRouter(pugi::xml_node router_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, std::map>& routers_info_in_arch); static void ProcessPb_TypePowerEstMethod(pugi::xml_node Parent, t_pb_type* pb_type, const pugiutil::loc_data& loc_data); static void ProcessPb_TypePort_Power(pugi::xml_node Parent, t_port* port, e_power_estimation_method power_method, const pugiutil::loc_data& loc_data); @@ -280,21 +366,14 @@ std::string inst_port_to_port_name(std::string inst_port); static bool attribute_to_bool(const pugi::xml_node node, const pugi::xml_attribute attr, const pugiutil::loc_data& loc_data); -int find_switch_by_name(const t_arch& arch, std::string switch_name); -e_side string_to_side(std::string side_str); +static int find_switch_by_name(const t_arch& arch, const std::string& switch_name); + +e_side string_to_side(const std::string& side_str); template static T* get_type_by_name(const char* type_name, std::vector& types); -static void generate_noc_mesh(pugi::xml_node mesh_topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, double mesh_region_start_x, double mesh_region_end_x, double mesh_region_start_y, double mesh_region_end_y, int mesh_size); - -static bool parse_noc_router_connection_list(pugi::xml_node router_tag, const pugiutil::loc_data& loc_data, int router_id, std::vector& connection_list, std::string connection_list_attribute_value, std::map>& routers_in_arch_info); - -static void update_router_info_in_arch(int router_id, bool router_updated_as_a_connection, std::map>& routers_in_arch_info); - -static void verify_noc_topology(std::map>& routers_in_arch_info); - /* * * @@ -312,7 +391,7 @@ void XmlReadArch(const char* ArchFile, pugi::xml_node Next; ReqOpt POWER_REQD, SWITCHBLOCKLIST_REQD; - if (vtr::check_file_name_extension(ArchFile, ".xml") == false) { + if (!vtr::check_file_name_extension(ArchFile, ".xml")) { VTR_LOG_WARN( "Architecture file '%s' may be in incorrect format. " "Expecting .xml format for architecture files.\n", @@ -380,7 +459,7 @@ void XmlReadArch(const char* ArchFile, /* Process logical block types */ Next = get_single_child(architecture, "complexblocklist", loc_data); - ProcessComplexBlocks(&arch->strings, Next, LogicalBlockTypes, *arch, timing_enabled, loc_data); + ProcessComplexBlocks(Next, LogicalBlockTypes, *arch, timing_enabled, loc_data); /* Process logical block types */ Next = get_single_child(architecture, "tiles", loc_data); @@ -461,9 +540,8 @@ void XmlReadArch(const char* ArchFile, // process NoC (optional) Next = get_single_child(architecture, "noc", loc_data, pugiutil::OPTIONAL); - if (Next) { - ProcessNoc(Next, arch, loc_data); + process_noc_tag(Next, arch, loc_data); } SyncModelsPbTypes(arch, LogicalBlockTypes); @@ -495,7 +573,7 @@ static void LoadPinLoc(pugi::xml_node Locations, type->pin_layer_offset.resize(type->num_pins, 0); std::vector physical_pin_counts(type->num_pins, 0); - if (pin_locs->distribution == E_SPREAD_PIN_DISTR) { + if (pin_locs->distribution == e_pin_location_distr::SPREAD) { /* evenly distribute pins starting at bottom left corner */ int num_sides = 4 * (type->width * type->height); @@ -520,7 +598,7 @@ static void LoadPinLoc(pugi::xml_node Locations, } VTR_ASSERT(side_index == num_sides); VTR_ASSERT(count == type->num_pins); - } else if (pin_locs->distribution == E_PERIMETER_PIN_DISTR) { + } else if (pin_locs->distribution == e_pin_location_distr::PERIMETER) { //Add one pin at-a-time to perimeter sides in round-robin order int ipin = 0; while (ipin < type->num_pins) { @@ -546,7 +624,7 @@ static void LoadPinLoc(pugi::xml_node Locations, } VTR_ASSERT(ipin == type->num_pins); - } else if (pin_locs->distribution == E_SPREAD_INPUTS_PERIMETER_OUTPUTS_PIN_DISTR) { + } else if (pin_locs->distribution == e_pin_location_distr::SPREAD_INPUTS_PERIMETER_OUTPUTS) { //Collect the sets of block input/output pins std::vector input_pins; std::vector output_pins; @@ -613,7 +691,7 @@ static void LoadPinLoc(pugi::xml_node Locations, VTR_ASSERT(ipin == output_pins.size()); } else { - VTR_ASSERT(pin_locs->distribution == E_CUSTOM_PIN_DISTR); + VTR_ASSERT(pin_locs->distribution == e_pin_location_distr::CUSTOM); for (auto& sub_tile : type->sub_tiles) { int sub_tile_index = sub_tile.index; int sub_tile_capacity = sub_tile.capacity.total(); @@ -622,7 +700,7 @@ static void LoadPinLoc(pugi::xml_node Locations, for (int width = 0; width < type->width; ++width) { for (int height = 0; height < type->height; ++height) { for (e_side side : {TOP, RIGHT, BOTTOM, LEFT}) { - for (auto token : pin_locs->assignments[sub_tile_index][width][height][layer][side]) { + for (const auto& token : pin_locs->assignments[sub_tile_index][width][height][layer][side]) { auto pin_range = ProcessPinString(Locations, &sub_tile, token.c_str(), @@ -1117,60 +1195,48 @@ static void ProcessPb_TypePowerEstMethod(pugi::xml_node Parent, t_pb_type* pb_ty } /* Takes in a pb_type, allocates and loads data for it and recurses downwards */ -static void ProcessPb_Type(vtr::string_internment* strings, - pugi::xml_node Parent, +static void ProcessPb_Type(pugi::xml_node Parent, t_pb_type* pb_type, t_mode* mode, const bool timing_enabled, const t_arch& arch, const pugiutil::loc_data& loc_data, int& pb_idx) { - int num_ports, i, j, k, num_annotations; const char* Prop; pugi::xml_node Cur; - bool is_root_pb_type = !(mode != nullptr && mode->parent_pb_type != nullptr); + bool is_root_pb_type = (mode == nullptr || mode->parent_pb_type == nullptr); bool is_leaf_pb_type = bool(get_attribute(Parent, "blif_model", loc_data, ReqOpt::OPTIONAL)); std::vector children_to_expect = {"input", "output", "clock", "mode", "power", "metadata"}; if (!is_leaf_pb_type) { //Non-leafs may have a model/pb_type children - children_to_expect.push_back("model"); - children_to_expect.push_back("pb_type"); - children_to_expect.push_back("interconnect"); + children_to_expect.emplace_back("model"); + children_to_expect.emplace_back("pb_type"); + children_to_expect.emplace_back("interconnect"); if (is_root_pb_type) { VTR_ASSERT(!is_leaf_pb_type); //Top level pb_type's may also have the following tag types - children_to_expect.push_back("fc"); - children_to_expect.push_back("pinlocations"); - children_to_expect.push_back("switchblock_locations"); + children_to_expect.emplace_back("fc"); + children_to_expect.emplace_back("pinlocations"); + children_to_expect.emplace_back("switchblock_locations"); } } else { VTR_ASSERT(is_leaf_pb_type); VTR_ASSERT(!is_root_pb_type); //Leaf pb_type's may also have the following tag types - children_to_expect.push_back("T_setup"); - children_to_expect.push_back("T_hold"); - children_to_expect.push_back("T_clock_to_Q"); - children_to_expect.push_back("delay_constant"); - children_to_expect.push_back("delay_matrix"); + children_to_expect.emplace_back("T_setup"); + children_to_expect.emplace_back("T_hold"); + children_to_expect.emplace_back("T_clock_to_Q"); + children_to_expect.emplace_back("delay_constant"); + children_to_expect.emplace_back("delay_matrix"); } //Sanity check contained tags expect_only_children(Parent, children_to_expect, loc_data); - char* class_name; - /* STL maps for checking various duplicate names */ - std::map pb_port_names; - std::map mode_names; - std::pair::iterator, bool> ret_pb_ports; - std::pair::iterator, bool> ret_mode_names; - int num_in_ports, num_out_ports, num_clock_ports; - int num_delay_constant, num_delay_matrix, num_C_constant, num_C_matrix, - num_T_setup, num_T_cq, num_T_hold; - pb_type->parent_mode = mode; pb_type->index_in_logical_block = pb_idx; if (mode != nullptr && mode->parent_pb_type != nullptr) { @@ -1187,7 +1253,7 @@ static void ProcessPb_Type(vtr::string_internment* strings, pb_type->class_type = UNKNOWN_CLASS; Prop = get_attribute(Parent, "class", loc_data, ReqOpt::OPTIONAL).as_string(nullptr); - class_name = vtr::strdup(Prop); + char* class_name = vtr::strdup(Prop); if (class_name) { if (0 == strcmp(class_name, PB_TYPE_CLASS_STRING[LUT_CLASS])) { @@ -1211,17 +1277,16 @@ static void ProcessPb_Type(vtr::string_internment* strings, } VTR_ASSERT(pb_type->num_pb > 0); - num_ports = num_in_ports = num_out_ports = num_clock_ports = 0; - num_in_ports = count_children(Parent, "input", loc_data, ReqOpt::OPTIONAL); - num_out_ports = count_children(Parent, "output", loc_data, ReqOpt::OPTIONAL); - num_clock_ports = count_children(Parent, "clock", loc_data, ReqOpt::OPTIONAL); - num_ports = num_in_ports + num_out_ports + num_clock_ports; + + const int num_in_ports = count_children(Parent, "input", loc_data, ReqOpt::OPTIONAL); + const int num_out_ports = count_children(Parent, "output", loc_data, ReqOpt::OPTIONAL); + const int num_clock_ports = count_children(Parent, "clock", loc_data, ReqOpt::OPTIONAL); + const int num_ports = num_in_ports + num_out_ports + num_clock_ports; pb_type->ports = (t_port*)vtr::calloc(num_ports, sizeof(t_port)); pb_type->num_ports = num_ports; /* Enforce VPR's definition of LUT/FF by checking number of ports */ - if (pb_type->class_type == LUT_CLASS - || pb_type->class_type == LATCH_CLASS) { + if (pb_type->class_type == LUT_CLASS || pb_type->class_type == LATCH_CLASS) { if (num_in_ports != 1 || num_out_ports != 1) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(Parent), "%s primitives must contain exactly one input port and one output port." @@ -1232,64 +1297,57 @@ static void ProcessPb_Type(vtr::string_internment* strings, } /* Initialize Power Structure */ - pb_type->pb_type_power = (t_pb_type_power*)vtr::calloc(1, - sizeof(t_pb_type_power)); + pb_type->pb_type_power = (t_pb_type_power*)vtr::calloc(1, sizeof(t_pb_type_power)); ProcessPb_TypePowerEstMethod(Parent, pb_type, loc_data); /* process ports */ - j = 0; int absolute_port_first_pin_index = 0; + int port_idx = 0; + + // STL sets for checking duplicate port names + std::set pb_port_names; + + for (const char* child_name : {"input", "output", "clock"}) { + Cur = get_first_child(Parent, child_name, loc_data, ReqOpt::OPTIONAL); + int port_index_by_type = 0; - for (i = 0; i < 3; i++) { - if (i == 0) { - k = 0; - Cur = get_first_child(Parent, "input", loc_data, ReqOpt::OPTIONAL); - } else if (i == 1) { - k = 0; - Cur = get_first_child(Parent, "output", loc_data, ReqOpt::OPTIONAL); - } else { - k = 0; - Cur = get_first_child(Parent, "clock", loc_data, ReqOpt::OPTIONAL); - } while (Cur) { - pb_type->ports[j].parent_pb_type = pb_type; - pb_type->ports[j].index = j; - pb_type->ports[j].port_index_by_type = k; - ProcessPb_TypePort(Cur, &pb_type->ports[j], + pb_type->ports[port_idx].parent_pb_type = pb_type; + pb_type->ports[port_idx].index = port_idx; + pb_type->ports[port_idx].port_index_by_type = port_index_by_type; + ProcessPb_TypePort(Cur, &pb_type->ports[port_idx], pb_type->pb_type_power->estimation_method, is_root_pb_type, loc_data); - pb_type->ports[j].absolute_first_pin_index = absolute_port_first_pin_index; - absolute_port_first_pin_index += pb_type->ports[j].num_pins; + pb_type->ports[port_idx].absolute_first_pin_index = absolute_port_first_pin_index; + absolute_port_first_pin_index += pb_type->ports[port_idx].num_pins; //Check port name duplicates - ret_pb_ports = pb_port_names.insert(std::pair(pb_type->ports[j].name, 0)); - if (!ret_pb_ports.second) { + auto [_, success] = pb_port_names.insert(pb_type->ports[port_idx].name); + if (!success) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(Cur), "Duplicate port names in pb_type '%s': port '%s'\n", - pb_type->name, pb_type->ports[j].name); + pb_type->name, pb_type->ports[port_idx].name); } /* get next iteration */ - j++; - k++; + port_idx++; + port_index_by_type++; Cur = Cur.next_sibling(Cur.name()); } } - VTR_ASSERT(j == num_ports); + VTR_ASSERT(port_idx == num_ports); /* Count stats on the number of each type of pin */ pb_type->num_clock_pins = pb_type->num_input_pins = pb_type->num_output_pins = 0; - for (i = 0; i < pb_type->num_ports; i++) { - if (pb_type->ports[i].type == IN_PORT - && pb_type->ports[i].is_clock == false) { - pb_type->num_input_pins += pb_type->ports[i].num_pins; - } else if (pb_type->ports[i].type == OUT_PORT) { - pb_type->num_output_pins += pb_type->ports[i].num_pins; + for (int port_i = 0; port_i < pb_type->num_ports; port_i++) { + if (pb_type->ports[port_i].type == IN_PORT && !pb_type->ports[port_i].is_clock) { + pb_type->num_input_pins += pb_type->ports[port_i].num_pins; + } else if (pb_type->ports[port_i].type == OUT_PORT) { + pb_type->num_output_pins += pb_type->ports[port_i].num_pins; } else { - VTR_ASSERT(pb_type->ports[i].is_clock - && pb_type->ports[i].type == IN_PORT); - pb_type->num_clock_pins += pb_type->ports[i].num_pins; + VTR_ASSERT(pb_type->ports[port_i].is_clock && pb_type->ports[port_i].type == IN_PORT); + pb_type->num_clock_pins += pb_type->ports[port_i].num_pins; } } @@ -1308,51 +1366,30 @@ static void ProcessPb_Type(vtr::string_internment* strings, pb_type->annotations = nullptr; pb_type->num_annotations = 0; - i = 0; /* Determine if this is a leaf or container pb_type */ if (pb_type->blif_model != nullptr) { /* Process delay and capacitance annotations */ - num_annotations = 0; - num_delay_constant = count_children(Parent, "delay_constant", loc_data, ReqOpt::OPTIONAL); - num_delay_matrix = count_children(Parent, "delay_matrix", loc_data, ReqOpt::OPTIONAL); - num_C_constant = count_children(Parent, "C_constant", loc_data, ReqOpt::OPTIONAL); - num_C_matrix = count_children(Parent, "C_matrix", loc_data, ReqOpt::OPTIONAL); - num_T_setup = count_children(Parent, "T_setup", loc_data, ReqOpt::OPTIONAL); - num_T_cq = count_children(Parent, "T_clock_to_Q", loc_data, ReqOpt::OPTIONAL); - num_T_hold = count_children(Parent, "T_hold", loc_data, ReqOpt::OPTIONAL); - num_annotations = num_delay_constant + num_delay_matrix + num_C_constant - + num_C_matrix + num_T_setup + num_T_cq + num_T_hold; + int num_annotations = 0; + for (auto child_name : {"delay_constant", "delay_matrix", "C_constant", "C_matrix", "T_setup", "T_clock_to_Q", "T_hold"}) { + num_annotations += count_children(Parent, child_name, loc_data, ReqOpt::OPTIONAL); + } pb_type->annotations = (t_pin_to_pin_annotation*)vtr::calloc(num_annotations, sizeof(t_pin_to_pin_annotation)); pb_type->num_annotations = num_annotations; - j = 0; - for (i = 0; i < 7; i++) { - if (i == 0) { - Cur = get_first_child(Parent, "delay_constant", loc_data, ReqOpt::OPTIONAL); - } else if (i == 1) { - Cur = get_first_child(Parent, "delay_matrix", loc_data, ReqOpt::OPTIONAL); - } else if (i == 2) { - Cur = get_first_child(Parent, "C_constant", loc_data, ReqOpt::OPTIONAL); - } else if (i == 3) { - Cur = get_first_child(Parent, "C_matrix", loc_data, ReqOpt::OPTIONAL); - } else if (i == 4) { - Cur = get_first_child(Parent, "T_setup", loc_data, ReqOpt::OPTIONAL); - } else if (i == 5) { - Cur = get_first_child(Parent, "T_clock_to_Q", loc_data, ReqOpt::OPTIONAL); - } else if (i == 6) { - Cur = get_first_child(Parent, "T_hold", loc_data, ReqOpt::OPTIONAL); - } + int annotation_idx = 0; + for (auto child_name : {"delay_constant", "delay_matrix", "C_constant", "C_matrix", "T_setup", "T_clock_to_Q", "T_hold"}) { + Cur = get_first_child(Parent, child_name, loc_data, ReqOpt::OPTIONAL); + while (Cur) { - ProcessPinToPinAnnotations(Cur, &pb_type->annotations[j], - pb_type, loc_data); + ProcessPinToPinAnnotations(Cur, &pb_type->annotations[annotation_idx], pb_type, loc_data); /* get next iteration */ - j++; + annotation_idx++; Cur = Cur.next_sibling(Cur.name()); } } - VTR_ASSERT(j == num_annotations); + VTR_ASSERT(annotation_idx == num_annotations); if (timing_enabled) { check_leaf_pb_model_timing_consistency(pb_type, arch); @@ -1373,45 +1410,46 @@ static void ProcessPb_Type(vtr::string_internment* strings, VTR_ASSERT(pb_type->class_type == UNKNOWN_CLASS); pb_type->num_modes = count_children(Parent, "mode", loc_data, ReqOpt::OPTIONAL); pb_type->pb_type_power->leakage_default_mode = 0; + int mode_idx = 0; if (pb_type->num_modes == 0) { /* The pb_type operates in an implied one mode */ pb_type->num_modes = 1; pb_type->modes = new t_mode[pb_type->num_modes]; - pb_type->modes[i].parent_pb_type = pb_type; - pb_type->modes[i].index = i; - ProcessMode(strings, Parent, &pb_type->modes[i], timing_enabled, arch, loc_data, pb_idx); - i++; + pb_type->modes[mode_idx].parent_pb_type = pb_type; + pb_type->modes[mode_idx].index = mode_idx; + ProcessMode(Parent, &pb_type->modes[mode_idx], timing_enabled, arch, loc_data, pb_idx); + mode_idx++; } else { pb_type->modes = new t_mode[pb_type->num_modes]; + // STL set for checking duplicate mode names + std::set mode_names; + Cur = get_first_child(Parent, "mode", loc_data); while (Cur != nullptr) { if (0 == strcmp(Cur.name(), "mode")) { - pb_type->modes[i].parent_pb_type = pb_type; - pb_type->modes[i].index = i; - ProcessMode(strings, Cur, &pb_type->modes[i], timing_enabled, arch, loc_data, pb_idx); + pb_type->modes[mode_idx].parent_pb_type = pb_type; + pb_type->modes[mode_idx].index = mode_idx; + ProcessMode(Cur, &pb_type->modes[mode_idx], timing_enabled, arch, loc_data, pb_idx); - ret_mode_names = mode_names.insert(std::pair(pb_type->modes[i].name, 0)); - if (!ret_mode_names.second) { + auto [_, success] = mode_names.insert(pb_type->modes[mode_idx].name); + if (!success) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(Cur), "Duplicate mode name: '%s' in pb_type '%s'.\n", - pb_type->modes[i].name, pb_type->name); + pb_type->modes[mode_idx].name, pb_type->name); } /* get next iteration */ - i++; + mode_idx++; Cur = Cur.next_sibling(Cur.name()); } } } - VTR_ASSERT(i == pb_type->num_modes); + VTR_ASSERT(mode_idx == pb_type->num_modes); } - pb_port_names.clear(); - mode_names.clear(); - - pb_type->meta = ProcessMetadata(strings, Parent, loc_data); + pb_type->meta = ProcessMetadata(arch.strings, Parent, loc_data); ProcessPb_TypePower(Parent, pb_type, loc_data); } @@ -1646,136 +1684,110 @@ static void ProcessPb_TypePort(pugi::xml_node Parent, t_port* port, e_power_esti ProcessPb_TypePort_Power(Parent, port, power_method, loc_data); } -static void ProcessInterconnect(vtr::string_internment* strings, pugi::xml_node Parent, t_mode* mode, const pugiutil::loc_data& loc_data) { - int num_interconnect = 0; - int num_complete, num_direct, num_mux; - int i, j, k, L_index, num_annotations; - int num_delay_constant, num_delay_matrix, num_C_constant, num_C_matrix, - num_pack_pattern; +static void ProcessInterconnect(vtr::string_internment& strings, + pugi::xml_node Parent, + t_mode* mode, + const pugiutil::loc_data& loc_data) { const char* Prop; - pugi::xml_node Cur; - pugi::xml_node Cur2; - std::map interc_names; - std::pair::iterator, bool> ret_interc_names; + // used to find duplicate names + std::set interconnect_names; - num_complete = num_direct = num_mux = 0; - num_complete = count_children(Parent, "complete", loc_data, ReqOpt::OPTIONAL); - num_direct = count_children(Parent, "direct", loc_data, ReqOpt::OPTIONAL); - num_mux = count_children(Parent, "mux", loc_data, ReqOpt::OPTIONAL); - num_interconnect = num_complete + num_direct + num_mux; + int num_interconnect = 0; + // count the total number of interconnect tags + for (auto child_name : {"complete", "direct", "mux"}) { + num_interconnect += count_children(Parent, child_name, loc_data, ReqOpt::OPTIONAL); + } mode->num_interconnect = num_interconnect; mode->interconnect = new t_interconnect[num_interconnect]; - i = 0; - for (L_index = 0; L_index < 3; L_index++) { - if (L_index == 0) { - Cur = get_first_child(Parent, "complete", loc_data, ReqOpt::OPTIONAL); - } else if (L_index == 1) { - Cur = get_first_child(Parent, "direct", loc_data, ReqOpt::OPTIONAL); - } else { - Cur = get_first_child(Parent, "mux", loc_data, ReqOpt::OPTIONAL); - } + int interconnect_idx = 0; + for (auto child_name : {"complete", "direct", "mux"}) { + pugi::xml_node Cur = get_first_child(Parent, child_name, loc_data, ReqOpt::OPTIONAL); + while (Cur != nullptr) { if (0 == strcmp(Cur.name(), "complete")) { - mode->interconnect[i].type = COMPLETE_INTERC; + mode->interconnect[interconnect_idx].type = COMPLETE_INTERC; } else if (0 == strcmp(Cur.name(), "direct")) { - mode->interconnect[i].type = DIRECT_INTERC; + mode->interconnect[interconnect_idx].type = DIRECT_INTERC; } else { VTR_ASSERT(0 == strcmp(Cur.name(), "mux")); - mode->interconnect[i].type = MUX_INTERC; + mode->interconnect[interconnect_idx].type = MUX_INTERC; } - mode->interconnect[i].line_num = loc_data.line(Cur); + mode->interconnect[interconnect_idx].line_num = loc_data.line(Cur); - mode->interconnect[i].parent_mode_index = mode->index; - mode->interconnect[i].parent_mode = mode; + mode->interconnect[interconnect_idx].parent_mode_index = mode->index; + mode->interconnect[interconnect_idx].parent_mode = mode; Prop = get_attribute(Cur, "input", loc_data).value(); - mode->interconnect[i].input_string = vtr::strdup(Prop); + mode->interconnect[interconnect_idx].input_string = vtr::strdup(Prop); Prop = get_attribute(Cur, "output", loc_data).value(); - mode->interconnect[i].output_string = vtr::strdup(Prop); + mode->interconnect[interconnect_idx].output_string = vtr::strdup(Prop); Prop = get_attribute(Cur, "name", loc_data).value(); - mode->interconnect[i].name = vtr::strdup(Prop); - mode->interconnect[i].meta = ProcessMetadata(strings, Cur, loc_data); + mode->interconnect[interconnect_idx].name = vtr::strdup(Prop); + mode->interconnect[interconnect_idx].meta = ProcessMetadata(strings, Cur, loc_data); - ret_interc_names = interc_names.insert(std::pair(mode->interconnect[i].name, 0)); - if (!ret_interc_names.second) { + auto [_, success] = interconnect_names.insert(mode->interconnect[interconnect_idx].name); + if (!success) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(Cur), "Duplicate interconnect name: '%s' in mode: '%s'.\n", - mode->interconnect[i].name, mode->name); + mode->interconnect[interconnect_idx].name, mode->name); } /* Process delay and capacitance annotations */ - num_annotations = 0; - num_delay_constant = count_children(Cur, "delay_constant", loc_data, ReqOpt::OPTIONAL); - num_delay_matrix = count_children(Cur, "delay_matrix", loc_data, ReqOpt::OPTIONAL); - num_C_constant = count_children(Cur, "C_constant", loc_data, ReqOpt::OPTIONAL); - num_C_matrix = count_children(Cur, "C_matrix", loc_data, ReqOpt::OPTIONAL); - num_pack_pattern = count_children(Cur, "pack_pattern", loc_data, ReqOpt::OPTIONAL); - num_annotations = num_delay_constant + num_delay_matrix - + num_C_constant + num_C_matrix + num_pack_pattern; - - mode->interconnect[i].annotations = (t_pin_to_pin_annotation*)vtr::calloc(num_annotations, + int num_annotations = 0; + for (auto annot_child_name : {"delay_constant", "delay_matrix", "C_constant", "C_matrix", "pack_pattern"}) { + num_annotations += count_children(Cur, annot_child_name, loc_data, ReqOpt::OPTIONAL); + } + + mode->interconnect[interconnect_idx].annotations = (t_pin_to_pin_annotation*)vtr::calloc(num_annotations, sizeof(t_pin_to_pin_annotation)); - mode->interconnect[i].num_annotations = num_annotations; - - k = 0; - for (j = 0; j < 5; j++) { - if (j == 0) { - Cur2 = get_first_child(Cur, "delay_constant", loc_data, ReqOpt::OPTIONAL); - } else if (j == 1) { - Cur2 = get_first_child(Cur, "delay_matrix", loc_data, ReqOpt::OPTIONAL); - } else if (j == 2) { - Cur2 = get_first_child(Cur, "C_constant", loc_data, ReqOpt::OPTIONAL); - } else if (j == 3) { - Cur2 = get_first_child(Cur, "C_matrix", loc_data, ReqOpt::OPTIONAL); - } else if (j == 4) { - Cur2 = get_first_child(Cur, "pack_pattern", loc_data, ReqOpt::OPTIONAL); - } + mode->interconnect[interconnect_idx].num_annotations = num_annotations; + + + int annotation_idx = 0; + for (auto annot_child_name : {"delay_constant", "delay_matrix", "C_constant", "C_matrix", "pack_pattern"}) { + pugi::xml_node Cur2 = get_first_child(Cur, annot_child_name, loc_data, ReqOpt::OPTIONAL); + while (Cur2 != nullptr) { ProcessPinToPinAnnotations(Cur2, - &(mode->interconnect[i].annotations[k]), nullptr, loc_data); + &(mode->interconnect[interconnect_idx].annotations[annotation_idx]), nullptr, loc_data); /* get next iteration */ - k++; + annotation_idx++; Cur2 = Cur2.next_sibling(Cur2.name()); } } - VTR_ASSERT(k == num_annotations); + VTR_ASSERT(annotation_idx == num_annotations); /* Power */ - mode->interconnect[i].interconnect_power = (t_interconnect_power*)vtr::calloc(1, + mode->interconnect[interconnect_idx].interconnect_power = (t_interconnect_power*)vtr::calloc(1, sizeof(t_interconnect_power)); - mode->interconnect[i].interconnect_power->port_info_initialized = false; + mode->interconnect[interconnect_idx].interconnect_power->port_info_initialized = false; /* get next iteration */ Cur = Cur.next_sibling(Cur.name()); - i++; + interconnect_idx++; } } - interc_names.clear(); - VTR_ASSERT(i == num_interconnect); + VTR_ASSERT(interconnect_idx == num_interconnect); } -static void ProcessMode(vtr::string_internment* strings, - pugi::xml_node Parent, +static void ProcessMode(pugi::xml_node Parent, t_mode* mode, const bool timing_enabled, const t_arch& arch, const pugiutil::loc_data& loc_data, int& parent_pb_idx) { - int i; const char* Prop; pugi::xml_node Cur; - std::map pb_type_names; - std::pair::iterator, bool> ret_pb_types; - bool implied_mode = 0 == strcmp(Parent.name(), "pb_type"); + bool implied_mode = (0 == strcmp(Parent.name(), "pb_type")); if (implied_mode) { mode->name = vtr::strdup("default"); } else { @@ -1783,7 +1795,7 @@ static void ProcessMode(vtr::string_internment* strings, mode->name = vtr::strdup(Prop); } - /* Parse XML about if this mode is disable for packing or not + /* Parse XML about if this mode is disabled for packing or not * By default, all the mode will be visible to packer */ mode->disable_packing = false; @@ -1797,7 +1809,7 @@ static void ProcessMode(vtr::string_internment* strings, /* Override if user specify */ mode->disable_packing = get_attribute(Parent, "disable_packing", loc_data, ReqOpt::OPTIONAL).as_bool(mode->disable_packing); - if (true == mode->disable_packing) { + if (mode->disable_packing) { VTR_LOG("mode '%s[%s]' is defined by user to be disabled in packing\n", mode->parent_pb_type->name, mode->name); @@ -1807,23 +1819,25 @@ static void ProcessMode(vtr::string_internment* strings, if (mode->num_pb_type_children > 0) { mode->pb_type_children = new t_pb_type[mode->num_pb_type_children]; - i = 0; + // used to find duplicate pb_type names + std::set pb_type_names; + + int pb_type_child_idx = 0; Cur = get_first_child(Parent, "pb_type", loc_data); while (Cur != nullptr) { if (0 == strcmp(Cur.name(), "pb_type")) { parent_pb_idx++; - ProcessPb_Type(strings, Cur, &mode->pb_type_children[i], mode, timing_enabled, arch, loc_data, parent_pb_idx); + ProcessPb_Type(Cur, &mode->pb_type_children[pb_type_child_idx], mode, timing_enabled, arch, loc_data, parent_pb_idx); - ret_pb_types = pb_type_names.insert( - std::pair(mode->pb_type_children[i].name, 0)); - if (!ret_pb_types.second) { + auto [_, success] = pb_type_names.insert(mode->pb_type_children[pb_type_child_idx].name); + if (!success) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(Cur), "Duplicate pb_type name: '%s' in mode: '%s'.\n", - mode->pb_type_children[i].name, mode->name); + mode->pb_type_children[pb_type_child_idx].name, mode->name); } /* get next iteration */ - i++; + pb_type_child_idx++; Cur = Cur.next_sibling(Cur.name()); } } @@ -1837,17 +1851,16 @@ static void ProcessMode(vtr::string_internment* strings, if (!implied_mode) { // Implied mode metadata is attached to the pb_type, rather than // the t_mode object. - mode->meta = ProcessMetadata(strings, Parent, loc_data); + mode->meta = ProcessMetadata(arch.strings, Parent, loc_data); } - /* Clear STL map used for duplicate checks */ - pb_type_names.clear(); - Cur = get_single_child(Parent, "interconnect", loc_data); - ProcessInterconnect(strings, Cur, mode, loc_data); + ProcessInterconnect(arch.strings, Cur, mode, loc_data); } -static t_metadata_dict ProcessMetadata(vtr::string_internment* strings, pugi::xml_node Parent, const pugiutil::loc_data& loc_data) { +static t_metadata_dict ProcessMetadata(vtr::string_internment& strings, + pugi::xml_node Parent, + const pugiutil::loc_data& loc_data) { // // CLBLL_L_ // @@ -1859,8 +1872,8 @@ static t_metadata_dict ProcessMetadata(vtr::string_internment* strings, pugi::xm auto key = get_attribute(meta_tag, "name", loc_data).as_string(); auto value = meta_tag.child_value(); - data.add(strings->intern_string(vtr::string_view(key)), - strings->intern_string(vtr::string_view(value))); + data.add(strings.intern_string(vtr::string_view(key)), + strings.intern_string(vtr::string_view(value))); meta_tag = meta_tag.next_sibling(meta_tag.name()); } } @@ -2062,12 +2075,11 @@ static e_fc_value_type string_to_fc_value_type(const std::string& str, pugi::xml return fc_value_type; } -//Process any custom switchblock locations static void ProcessSwitchblockLocations(pugi::xml_node switchblock_locations, t_physical_tile_type* type, const t_arch& arch, const pugiutil::loc_data& loc_data) { - VTR_ASSERT(type); + VTR_ASSERT(type != nullptr); expect_only_attributes(switchblock_locations, {"pattern", "internal_switch"}, loc_data); @@ -2430,13 +2442,13 @@ static void ProcessLayout(pugi::xml_node layout_tag, t_arch* arch, const pugiuti VTR_ASSERT_MSG(auto_layout_cnt == 0 || auto_layout_cnt == 1, " may appear at most once"); for (auto layout_type_tag : layout_tag.children()) { - t_grid_def grid_def = ProcessGridLayout(&arch->strings, layout_type_tag, loc_data, arch, num_of_avail_layer); + t_grid_def grid_def = ProcessGridLayout(arch->strings, layout_type_tag, loc_data, arch, num_of_avail_layer); arch->grid_layouts.emplace_back(std::move(grid_def)); } } -static t_grid_def ProcessGridLayout(vtr::string_internment* strings, +static t_grid_def ProcessGridLayout(vtr::string_internment& strings, pugi::xml_node layout_type_tag, const pugiutil::loc_data& loc_data, t_arch* arch, @@ -2507,7 +2519,7 @@ static t_grid_def ProcessGridLayout(vtr::string_internment* strings, static void ProcessBlockTypeLocs(t_grid_def& grid_def, int die_number, - vtr::string_internment* strings, + vtr::string_internment& strings, pugi::xml_node layout_block_type_tag, const pugiutil::loc_data& loc_data) { //Process all the block location specifications @@ -2533,7 +2545,7 @@ static void ProcessBlockTypeLocs(t_grid_def& grid_def, right_edge.y.start_expr = "0"; right_edge.y.end_expr = "H - 1"; - t_grid_loc_def bottom_edge(type_name, priority); //Exclucing corners + t_grid_loc_def bottom_edge(type_name, priority); //Excluding corners bottom_edge.x.start_expr = "1"; bottom_edge.x.end_expr = "W - 2"; bottom_edge.y.start_expr = "0"; @@ -2894,12 +2906,12 @@ static void ProcessTiles(pugi::xml_node Node, t_arch& arch, const pugiutil::loc_data& loc_data, const int num_of_avail_layer) { - pugi::xml_node CurTileType; - pugi::xml_node Cur; - std::map tile_type_descriptors; - /* Alloc the type list. Need one additional t_type_desctiptors: - * 1: empty psuedo-type + // used to find duplicate tile names + std::set tile_type_descriptors; + + /* Alloc the type list. Need one additional t_type_descriptors: + * 1: empty pseudo-type */ t_physical_tile_type EMPTY_PHYSICAL_TILE_TYPE = get_empty_physical_type(); EMPTY_PHYSICAL_TILE_TYPE.index = 0; @@ -2908,7 +2920,7 @@ static void ProcessTiles(pugi::xml_node Node, /* Process the types */ int index = 1; /* Skip over 'empty' type */ - CurTileType = Node.first_child(); + pugi::xml_node CurTileType = Node.first_child(); while (CurTileType) { check_node(CurTileType, "tile", loc_data); @@ -2919,8 +2931,8 @@ static void ProcessTiles(pugi::xml_node Node, /* Parses the properties fields of the type */ ProcessTileProps(CurTileType, &PhysicalTileType, loc_data); - auto result = tile_type_descriptors.insert(std::pair(PhysicalTileType.name, 0)); - if (!result.second) { + auto [_, success] = tile_type_descriptors.insert(PhysicalTileType.name); + if (!success) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(CurTileType), "Duplicate tile descriptor name: '%s'.\n", PhysicalTileType.name); } @@ -2937,7 +2949,7 @@ static void ProcessTiles(pugi::xml_node Node, } //Load switchblock type and location overrides - Cur = get_single_child(CurTileType, "switchblock_locations", loc_data, ReqOpt::OPTIONAL); + pugi::xml_node Cur = get_single_child(CurTileType, "switchblock_locations", loc_data, ReqOpt::OPTIONAL); ProcessSwitchblockLocations(Cur, &PhysicalTileType, arch, loc_data); ProcessSubTiles(CurTileType, &PhysicalTileType, LogicalBlockTypes, arch.Segments, arch_def_fc, loc_data, num_of_avail_layer); @@ -2951,7 +2963,6 @@ static void ProcessTiles(pugi::xml_node Node, /* Free this node and get its next sibling node */ CurTileType = CurTileType.next_sibling(CurTileType.name()); } - tile_type_descriptors.clear(); } static void MarkIoTypes(std::vector& PhysicalTileTypes) { @@ -2999,27 +3010,22 @@ static void ProcessTileProps(pugi::xml_node Node, static t_pin_counts ProcessSubTilePorts(pugi::xml_node Parent, t_sub_tile* SubTile, - std::unordered_map& tile_port_names, const pugiutil::loc_data& loc_data) { pugi::xml_node Cur; - std::map sub_tile_port_names; - - int num_ports, num_in_ports, num_out_ports, num_clock_ports; - - num_ports = num_in_ports = num_out_ports = num_clock_ports = 0; - num_in_ports = count_children(Parent, "input", loc_data, ReqOpt::OPTIONAL); - num_out_ports = count_children(Parent, "output", loc_data, ReqOpt::OPTIONAL); - num_clock_ports = count_children(Parent, "clock", loc_data, ReqOpt::OPTIONAL); - num_ports = num_in_ports + num_out_ports + num_clock_ports; + int num_ports = 0; + for (auto port_type : {"input", "output", "clock"}) { + num_ports += count_children(Parent, port_type, loc_data, ReqOpt::OPTIONAL); + } - int port_index_by_type; int port_index = 0; int absolute_first_pin_index = 0; - std::vector port_types = {"input", "output", "clock"}; - for (auto port_type : port_types) { - port_index_by_type = 0; + // used to find duplicate port names + std::set sub_tile_port_names; + + for (auto port_type : {"input", "output", "clock"}) { + int port_index_by_type = 0; Cur = get_first_child(Parent, port_type, loc_data, ReqOpt::OPTIONAL); while (Cur) { t_physical_tile_port port; @@ -3030,24 +3036,13 @@ static t_pin_counts ProcessSubTilePorts(pugi::xml_node Parent, ProcessTilePort(Cur, &port, loc_data); //Check port name duplicates - auto sub_tile_port_result = sub_tile_port_names.insert(std::pair(port.name, 0)); - if (!sub_tile_port_result.second) { + auto [_, subtile_success] = sub_tile_port_names.insert(port.name); + if (!subtile_success) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(Cur), - "Duplicate port names in tile '%s': port '%s'\n", + "Duplicate port names in subtile '%s': port '%s'\n", SubTile->name, port.name); } - //Check port name duplicates - auto tile_port_result = tile_port_names.insert(std::pair(port.name, port)); - if (!tile_port_result.second) { - if (tile_port_result.first->second.num_pins != port.num_pins || tile_port_result.first->second.equivalent != port.equivalent) { - archfpga_throw(loc_data.filename_c_str(), loc_data.line(Cur), - "Another port found with the same name in other sub tiles " - "that did not match the current port settings. '%s': port '%s'\n", - SubTile->name, port.name); - } - } - //Push port SubTile->ports.push_back(port); @@ -3066,7 +3061,7 @@ static t_pin_counts ProcessSubTilePorts(pugi::xml_node Parent, /* Count stats on the number of each type of pin */ for (const auto& port : SubTile->ports) { - if (port.type == IN_PORT && port.is_clock == false) { + if (port.type == IN_PORT && !port.is_clock) { pin_counts.input += port.num_pins; } else if (port.type == OUT_PORT) { pin_counts.output += port.num_pins; @@ -3085,7 +3080,7 @@ static void ProcessTilePort(pugi::xml_node Node, std::vector expected_attributes = {"name", "num_pins", "equivalent"}; if (Node.name() == "input"s || Node.name() == "clock"s) { - expected_attributes.push_back("is_non_clock_global"); + expected_attributes.emplace_back("is_non_clock_global"); } expect_only_attributes(Node, expected_attributes, loc_data); @@ -3134,7 +3129,7 @@ static void ProcessTilePort(pugi::xml_node Node, port->type = IN_PORT; port->is_clock = true; - if (port->is_non_clock_global == true) { + if (port->is_non_clock_global) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(Node), "Port %s cannot be both a clock and a non-clock simultaneously\n", Node.name()); @@ -3290,19 +3285,19 @@ static void ProcessPinLocations(pugi::xml_node Locations, Prop = get_attribute(Locations, "pattern", loc_data).value(); if (strcmp(Prop, "spread") == 0) { - distribution = E_SPREAD_PIN_DISTR; + distribution = e_pin_location_distr::SPREAD; } else if (strcmp(Prop, "perimeter") == 0) { - distribution = E_PERIMETER_PIN_DISTR; + distribution = e_pin_location_distr::PERIMETER; } else if (strcmp(Prop, "spread_inputs_perimeter_outputs") == 0) { - distribution = E_SPREAD_INPUTS_PERIMETER_OUTPUTS_PIN_DISTR; + distribution = e_pin_location_distr::SPREAD_INPUTS_PERIMETER_OUTPUTS; } else if (strcmp(Prop, "custom") == 0) { - distribution = E_CUSTOM_PIN_DISTR; + distribution = e_pin_location_distr::CUSTOM; } else { archfpga_throw(loc_data.filename_c_str(), loc_data.line(Locations), "%s is an invalid pin location pattern.\n", Prop); } } else { - distribution = E_SPREAD_PIN_DISTR; + distribution = e_pin_location_distr::SPREAD; Prop = "spread"; } @@ -3318,10 +3313,10 @@ static void ProcessPinLocations(pugi::xml_node Locations, pin_locs->set_distribution(); } - int sub_tile_index = SubTile->index; + const int sub_tile_index = SubTile->index; /* Load the pin locations */ - if (distribution == E_CUSTOM_PIN_DISTR) { + if (distribution == e_pin_location_distr::CUSTOM) { expect_only_children(Locations, {"loc"}, loc_data); Cur = Locations.first_child(); //check for duplications ([0..3][0..type->width-1][0..type->height-1][0..num_of_avail_layer-1]) @@ -3384,7 +3379,7 @@ static void ProcessPinLocations(pugi::xml_node Locations, if (Count > 0) { for (int pin = 0; pin < Count; ++pin) { /* Store location assignment */ - pin_locs->assignments[sub_tile_index][x_offset][y_offset][std::abs(layer_offset)][side].push_back(std::string(Tokens[pin].c_str())); + pin_locs->assignments[sub_tile_index][x_offset][y_offset][std::abs(layer_offset)][side].emplace_back(Tokens[pin].c_str()); /* Advance through list of pins in this location */ } } @@ -3399,7 +3394,7 @@ static void ProcessPinLocations(pugi::xml_node Locations, for (int w = 0; w < PhysicalTileType->width; ++w) { for (int h = 0; h < PhysicalTileType->height; ++h) { for (e_side side : {TOP, RIGHT, BOTTOM, LEFT}) { - for (auto token : pin_locs->assignments[sub_tile_index][w][h][l][side]) { + for (const auto& token : pin_locs->assignments[sub_tile_index][w][h][l][side]) { InstPort inst_port(token.c_str()); //A pin specification should contain only the block name, and not any instance count information @@ -3444,7 +3439,7 @@ static void ProcessPinLocations(pugi::xml_node Locations, VTR_ASSERT(pin_high_idx >= 0); for (int ipin = pin_low_idx; ipin <= pin_high_idx; ++ipin) { - //Record that the pin has it's location specified + //Record that the pin has its location specified port_pins_with_specified_locations[inst_port.port_name()].insert(ipin); } } @@ -3479,15 +3474,12 @@ static void ProcessSubTiles(pugi::xml_node Node, const int num_of_avail_layer) { pugi::xml_node CurSubTile; pugi::xml_node Cur; - int index = 0; unsigned long int num_sub_tiles = count_children(Node, "sub_tile", loc_data); unsigned long int width = PhysicalTileType->width; unsigned long int height = PhysicalTileType->height; unsigned long int num_sides = 4; - std::map sub_tile_names; - t_pin_locs pin_locs; pin_locs.assignments.resize({num_sub_tiles, width, height, (unsigned long int)num_of_avail_layer, num_sides}); @@ -3498,12 +3490,18 @@ static void ProcessSubTiles(pugi::xml_node Node, PhysicalTileType->name); } + // used to find duplicate subtile names + std::set sub_tile_names; + + // used to assign indices to subtiles + int subtile_index = 0; + CurSubTile = get_first_child(Node, "sub_tile", loc_data); while (CurSubTile) { t_sub_tile SubTile; - SubTile.index = index; + SubTile.index = subtile_index; expect_only_attributes(CurSubTile, {"name", "capacity"}, loc_data); @@ -3511,8 +3509,8 @@ static void ProcessSubTiles(pugi::xml_node Node, auto name = vtr::strdup(get_attribute(CurSubTile, "name", loc_data).value()); //Check Sub Tile name duplicates - auto result = sub_tile_names.insert(std::pair(std::string(name), 0)); - if (!result.second) { + auto [_, success] = sub_tile_names.insert(name); + if (!success) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(Cur), "Duplicate Sub Tile names in tile '%s': Sub Tile'%s'\n", PhysicalTileType->name, name); @@ -3526,8 +3524,7 @@ static void ProcessSubTiles(pugi::xml_node Node, PhysicalTileType->capacity += capacity; /* Process sub tile port definitions */ - std::unordered_map tile_port_names; - auto pin_counts = ProcessSubTilePorts(CurSubTile, &SubTile, tile_port_names, loc_data); + const auto pin_counts = ProcessSubTilePorts(CurSubTile, &SubTile, loc_data); /* Map Sub Tile physical pins with the Physical Tile Type physical pins. * This takes into account the capacity of each sub tiles to add the correct offset. @@ -3556,13 +3553,13 @@ static void ProcessSubTiles(pugi::xml_node Node, Cur = get_single_child(CurSubTile, "fc", loc_data, ReqOpt::OPTIONAL); Process_Fc(Cur, PhysicalTileType, &SubTile, pin_counts, segments, arch_def_fc, loc_data); - //Load equivalent sites infromation + //Load equivalent sites information Cur = get_single_child(CurSubTile, "equivalent_sites", loc_data, ReqOpt::REQUIRED); ProcessTileEquivalentSites(Cur, &SubTile, PhysicalTileType, LogicalBlockTypes, loc_data); PhysicalTileType->sub_tiles.push_back(SubTile); - index++; + subtile_index++; CurSubTile = CurSubTile.next_sibling(CurSubTile.name()); } @@ -3577,13 +3574,19 @@ static void ProcessSubTiles(pugi::xml_node Node, /* Takes in node pointing to and loads all the * child type objects. */ -static void ProcessComplexBlocks(vtr::string_internment* strings, pugi::xml_node Node, std::vector& LogicalBlockTypes, t_arch& arch, const bool timing_enabled, const pugiutil::loc_data& loc_data) { +static void ProcessComplexBlocks(pugi::xml_node Node, + std::vector& LogicalBlockTypes, + const t_arch& arch, + const bool timing_enabled, + const pugiutil::loc_data& loc_data) { pugi::xml_node CurBlockType; pugi::xml_node Cur; - std::map pb_type_descriptors; - /* Alloc the type list. Need one additional t_type_desctiptors: - * 1: empty psuedo-type + // used to find duplicate pb_types names + std::set pb_type_descriptors; + + /* Alloc the type list. Need one additional t_type_descriptors: + * 1: empty pseudo-type */ t_logical_block_type EMPTY_LOGICAL_BLOCK_TYPE = get_empty_logical_type(); EMPTY_LOGICAL_BLOCK_TYPE.index = 0; @@ -3606,8 +3609,8 @@ static void ProcessComplexBlocks(vtr::string_internment* strings, pugi::xml_node auto Prop = get_attribute(CurBlockType, "name", loc_data).value(); LogicalBlockType.name = vtr::strdup(Prop); - auto result = pb_type_descriptors.insert(std::pair(LogicalBlockType.name, 0)); - if (!result.second) { + auto [_, success] = pb_type_descriptors.insert(LogicalBlockType.name); + if (!success) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(CurBlockType), "Duplicate pb_type descriptor name: '%s'.\n", LogicalBlockType.name); } @@ -3615,7 +3618,7 @@ static void ProcessComplexBlocks(vtr::string_internment* strings, pugi::xml_node /* Load pb_type info to assign to the Logical Block Type */ LogicalBlockType.pb_type = new t_pb_type; LogicalBlockType.pb_type->name = vtr::strdup(LogicalBlockType.name); - ProcessPb_Type(strings, CurBlockType, LogicalBlockType.pb_type, nullptr, timing_enabled, arch, loc_data, pb_type_idx); + ProcessPb_Type(CurBlockType, LogicalBlockType.pb_type, nullptr, timing_enabled, arch, loc_data, pb_type_idx); LogicalBlockType.index = index; @@ -3628,7 +3631,6 @@ static void ProcessComplexBlocks(vtr::string_internment* strings, pugi::xml_node /* Free this node and get its next sibling node */ CurBlockType = CurBlockType.next_sibling(CurBlockType.name()); } - pb_type_descriptors.clear(); } static void ProcessSegments(pugi::xml_node Parent, @@ -4665,228 +4667,6 @@ static void ProcessClocks(pugi::xml_node Parent, t_clock_arch* clocks, const pug Node = Node.next_sibling(Node.name()); } } -/* - * Get the NoC design - */ -static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc_data& loc_data) { - // a vector representing all the possible attributes within the noc tag - std::vector expected_noc_attributes = {"link_bandwidth", "link_latency", "router_latency", "noc_router_tile_name"}; - - std::vector expected_noc_children_tags = {"mesh", "topology"}; - - pugi::xml_node noc_topology; - pugi::xml_node noc_mesh_topology; - - // identifier that lets us know when we could not properly convert a string conversion value - std::string attribute_conversion_failure_string = ""; - - // if we are here, then the user has a NoC in their architecture, so need to add it - arch->noc = new t_noc_inf; - t_noc_inf* noc_ref = arch->noc; - - /* process the noc attributes first */ - - // quick error check to make sure that we dont have unexpected attributes - pugiutil::expect_only_attributes(noc_tag, expected_noc_attributes, loc_data); - - // now go through and parse the required attributes for noc tag - - // variables below temporarily store the attribute values as string - // this is so that scientific notation can be used for these attributes - std::string link_bandwidth_intermediate_val; - std::string router_latency_intermediate_val; - std::string link_latency_intermediate_val; - - link_bandwidth_intermediate_val = pugiutil::get_attribute(noc_tag, "link_bandwidth", loc_data, pugiutil::REQUIRED).as_string(); - noc_ref->link_bandwidth = std::atof(link_bandwidth_intermediate_val.c_str()); - - link_latency_intermediate_val = pugiutil::get_attribute(noc_tag, "link_latency", loc_data, pugiutil::REQUIRED).as_string(); - noc_ref->link_latency = std::atof(link_latency_intermediate_val.c_str()); - - router_latency_intermediate_val = pugiutil::get_attribute(noc_tag, "router_latency", loc_data, pugiutil::REQUIRED).as_string(); - noc_ref->router_latency = std::atof(router_latency_intermediate_val.c_str()); - - noc_ref->noc_router_tile_name = pugiutil::get_attribute(noc_tag, "noc_router_tile_name", loc_data, pugiutil::REQUIRED).as_string(); - - // the noc parameters can only be non-zero positive values - if ((noc_ref->link_bandwidth <= 0.) || (noc_ref->link_latency <= 0.) || (noc_ref->router_latency <= 0.)) { - archfpga_throw(loc_data.filename_c_str(), loc_data.line(noc_tag), - "The link bandwidth, link latency and router latency for the NoC must be a positive non-zero value."); - } - - // check that the router tile name was supplied properly - if (!(noc_ref->noc_router_tile_name.compare(attribute_conversion_failure_string))) { - archfpga_throw(loc_data.filename_c_str(), loc_data.line(noc_tag), - "The noc router tile name must be a string."); - } - - /* We processed the NoC node, so now process the topology*/ - - // make sure that only the topology tag is found under NoC - pugiutil::expect_only_children(noc_tag, expected_noc_children_tags, loc_data); - - noc_mesh_topology = pugiutil::get_single_child(noc_tag, "mesh", loc_data, pugiutil::OPTIONAL); - - // we cannot check for errors related to number of routers and as well as whether a router is out of bounds (this will be done later) - // the chip still needs to be sized - - if (noc_mesh_topology) { - processMeshTopology(noc_mesh_topology, loc_data, noc_ref); - } else { - noc_topology = pugiutil::get_single_child(noc_tag, "topology", loc_data, pugiutil::REQUIRED); - - processTopology(noc_topology, loc_data, noc_ref); - } - - return; -} - -/* - * A NoC mesh is created based on the user supplied size and region location. - */ -static void processMeshTopology(pugi::xml_node mesh_topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref) { - // noc mesh topology properties - double mesh_region_start_x = 0; - double mesh_region_end_x = 0; - double mesh_region_start_y = 0; - double mesh_region_end_y = 0; - int mesh_size = 0; - - // identifier that lets us know when we could not properly convert an attribute value to a integer - int attribute_conversion_failure = -1; - - // a list of attrbutes that should be found for the mesh tag - std::vector expected_router_attributes = {"startx", "endx", "starty", "endy", "size"}; - - // verify that only the acceptable attributes were supplied - pugiutil::expect_only_attributes(mesh_topology_tag, expected_router_attributes, loc_data); - - // go through the attributes and store their values - mesh_region_start_x = pugiutil::get_attribute(mesh_topology_tag, "startx", loc_data, pugiutil::REQUIRED).as_double(attribute_conversion_failure); - - mesh_region_end_x = pugiutil::get_attribute(mesh_topology_tag, "endx", loc_data, pugiutil::REQUIRED).as_double(attribute_conversion_failure); - - mesh_region_start_y = pugiutil::get_attribute(mesh_topology_tag, "starty", loc_data, pugiutil::REQUIRED).as_double(attribute_conversion_failure); - - mesh_region_end_y = pugiutil::get_attribute(mesh_topology_tag, "endy", loc_data, pugiutil::REQUIRED).as_double(attribute_conversion_failure); - - mesh_size = pugiutil::get_attribute(mesh_topology_tag, "size", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); - - // verify that the attrbiutes provided were legal - if ((mesh_region_start_x < 0) || (mesh_region_end_x < 0) || (mesh_region_start_y < 0) || (mesh_region_end_y < 0) || (mesh_size < 0)) { - archfpga_throw(loc_data.filename_c_str(), loc_data.line(mesh_topology_tag), - "The parameters for the mesh topology have to be positive values."); - } - - // now create the mesh topology for the noc - // create routers, make connections and detertmine positions - generate_noc_mesh(mesh_topology_tag, loc_data, noc_ref, mesh_region_start_x, mesh_region_end_x, mesh_region_start_y, mesh_region_end_y, mesh_size); - - return; -} - -/* - * Go through each router in the NoC and store the list of routers that connect to it. - */ -static void processTopology(pugi::xml_node topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref) { - // The topology tag should have no attributes, check that - pugiutil::expect_only_attributes(topology_tag, {}, loc_data); - - /** - * Stores router information that includes the number of connections a router has within a given topology and also the number of times a router was declared in the arch file using the tag. - * In the datastructure below, the router id is the key and the stored data is a pair, where the first element describes the number of router declarations and the second element describes the number of router connections. - * This is used only for error checking. - */ - std::map> routers_in_arch_info; - - /* Now go through the children tags of topology, which is basically - * each router found within the NoC - */ - for (pugi::xml_node router : topology_tag.children()) { - // we can only have router tags within the topology - if (router.name() != std::string("router")) { - bad_tag(router, loc_data, topology_tag, {"router"}); - } else { - // curent tag is a valid router, so process it - processRouter(router, loc_data, noc_ref, routers_in_arch_info); - } - } - - // check whether any routers were supplied - if (noc_ref->router_list.size() == 0) { - archfpga_throw(loc_data.filename_c_str(), loc_data.line(topology_tag), - "No routers were supplied for the NoC."); - } - - // check that the topology of the noc was correctly described in the arch file - verify_noc_topology(routers_in_arch_info); - - return; -} - -/* - * Store the properties of a single router and then store the list of routers that connect to it. - */ -static void processRouter(pugi::xml_node router_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, std::map>& routers_in_arch_info) { - // identifier that lets us know when we could not properly convert an attribute value to a integer - int attribute_conversion_failure = -1; - - // an accepted list of attributes for the router tag - std::vector expected_router_attributes = {"id", "positionx", "positiony", "connections"}; - - // variable to store current router info - t_router router_info; - - // router connection list attribute information - std::string router_connection_list_attribute_value; - - // lets us know if there was an error processing the router connection list - bool router_connection_list_result = true; - - // check that only the accepted router attributes are found in the tag - pugiutil::expect_only_attributes(router_tag, expected_router_attributes, loc_data); - - // store the router information from the attributes - router_info.id = pugiutil::get_attribute(router_tag, "id", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); - - router_info.device_x_position = pugiutil::get_attribute(router_tag, "positionx", loc_data, pugiutil::REQUIRED).as_double(attribute_conversion_failure); - - router_info.device_y_position = pugiutil::get_attribute(router_tag, "positiony", loc_data, pugiutil::REQUIRED).as_double(attribute_conversion_failure); - - // verify whether the attribute information was legal - if ((router_info.id < 0) || (router_info.device_x_position < 0) || (router_info.device_y_position < 0)) { - archfpga_throw(loc_data.filename_c_str(), loc_data.line(router_tag), - "The router id, and position (x & y) for the router must be a positive number."); - } - - // get the current router connection list - router_connection_list_attribute_value.assign(pugiutil::get_attribute(router_tag, "connections", loc_data, pugiutil::REQUIRED).as_string()); - - // if the connections attrbiute was not provided or it was empty, then we don't process it and throw a warning - - if (router_connection_list_attribute_value.compare("") != 0) { - // process the router connection list - router_connection_list_result = parse_noc_router_connection_list(router_tag, loc_data, router_info.id, router_info.connection_list, router_connection_list_attribute_value, routers_in_arch_info); - - // check if the user provided a legal router connection list - if (!router_connection_list_result) { - archfpga_throw(loc_data.filename_c_str(), loc_data.line(router_tag), - "The 'connections' attribute for the router must be a list of integers seperated by spaces, where each integer represents a router id that the current router is connected to."); - } - - } else { - VTR_LOGF_WARN(loc_data.filename_c_str(), loc_data.line(router_tag), - "The router with id:%d either has an empty 'connections' attrtibute or does not have any associated connections to other routers in the NoC.\n", router_info.id); - } - - // at this point the current router information was completely legal, so we store the newly created router within the noc - noc_ref->router_list.push_back(router_info); - - // update the number of declarations info for the current router (since we just finished processing one tag) - update_router_info_in_arch(router_info.id, false, routers_in_arch_info); - - return; -} std::string inst_port_to_port_name(std::string inst_port) { auto pos = inst_port.find('.'); @@ -4910,7 +4690,7 @@ static bool attribute_to_bool(const pugi::xml_node node, return false; } -int find_switch_by_name(const t_arch& arch, std::string switch_name) { +static int find_switch_by_name(const t_arch& arch, const std::string& switch_name) { for (int iswitch = 0; iswitch < arch.num_switches; ++iswitch) { const t_arch_switch_inf& arch_switch = arch.Switches[iswitch]; if (arch_switch.name == switch_name) { @@ -4921,7 +4701,7 @@ int find_switch_by_name(const t_arch& arch, std::string switch_name) { return OPEN; } -e_side string_to_side(std::string side_str) { +e_side string_to_side(const std::string& side_str) { e_side side = NUM_SIDES; if (side_str.empty()) { side = NUM_SIDES; @@ -4950,211 +4730,4 @@ static T* get_type_by_name(const char* type_name, std::vector& types) { archfpga_throw(__FILE__, __LINE__, "Could not find type: %s\n", type_name); -} - -/* - * Create routers and set their properties so that a mesh grid of routers is created. Then connect the routers together so that a mesh topology is created. - */ -static void generate_noc_mesh(pugi::xml_node mesh_topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, double mesh_region_start_x, double mesh_region_end_x, double mesh_region_start_y, double mesh_region_end_y, int mesh_size) { - // check that the mesh size of the router is not 0 - if (mesh_size == 0) { - archfpga_throw(loc_data.filename_c_str(), loc_data.line(mesh_topology_tag), - "The NoC mesh size cannot be 0."); - } - - // calculating the vertical horizontal distances between routers in the supplied region - // we decrease the mesh size by 1 when calculating the spacing so that the first and last routers of each row or column are positioned on the mesh boundary - /* - * For example: - * - If we had a mesh size of 3, then using 3 would result in a spacing that would result in one router positions being placed in either the start of the reigion or end of the region. This is because the distance calculation resulted in having 3 spaces between the ends of the region - * - * start end - *** *** *** *** - * - * - if we instead used 2 in the distance calculation, the the resulting positions would result in having 2 routers positioned on the start and end of the region. This is beacuse we now specified 2 spaces between the region and this allows us to place 2 routers on the regions edges and one router in the center. - * - * start end - *** *** *** - * - * THe reasoning for this is to reduce the number of calculated router positions. - */ - double vertical_router_separation = (mesh_region_end_y - mesh_region_start_y) / (mesh_size - 1); - double horizontal_router_separation = (mesh_region_end_x - mesh_region_start_x) / (mesh_size - 1); - - t_router temp_router; - - // improper region check - if ((vertical_router_separation <= 0) || (horizontal_router_separation <= 0)) { - archfpga_throw(loc_data.filename_c_str(), loc_data.line(mesh_topology_tag), - "The NoC region is invalid."); - } - - // create routers and their connections - // start with router id 0 (bottom left of the chip) to the maximum router id (top right of the chip) - for (int j = 0; j < mesh_size; j++) { - for (int i = 0; i < mesh_size; i++) { - // assign router id - temp_router.id = (mesh_size * j) + i; - - // calculate router position - /* The first and last router of each column or row will be located on the mesh region boundary, the remaining routers will be placed within the region and seperated from other routers using the distance calculated previously. - */ - temp_router.device_x_position = (i * horizontal_router_separation) + mesh_region_start_x; - temp_router.device_y_position = (j * vertical_router_separation) + mesh_region_start_y; - - // assign connections - // check if there is a router to the left - if ((i - 1) >= 0) { - // add the left router as a connection - temp_router.connection_list.push_back((mesh_size * j) + i - 1); - } - - // check if there is a router to the top - if ((j + 1) <= (mesh_size - 1)) { - // add the top router as a connection - temp_router.connection_list.push_back((mesh_size * (j + 1)) + i); - } - - // check if there is a router to the right - if ((i + 1) <= (mesh_size - 1)) { - // add the router located to the right - temp_router.connection_list.push_back((mesh_size * j) + i + 1); - } - - // check of there is a router below - if ((j - 1) >= (0)) { - // add the bottom router as a connection - temp_router.connection_list.push_back((mesh_size * (j - 1)) + i); - } - - // add the router to the list - noc_ref->router_list.push_back(temp_router); - - // clear the current router information for the next router - temp_router.connection_list.clear(); - } - } - - return; -} - -/* - * THe user provides the list of routers any given router is connected to by the router ids seperated by spaces. For example: - * - * connections= 1 2 3 4 5 - * - * Go through the connections here and store them. Also make sure the list is legal. - */ -static bool parse_noc_router_connection_list(pugi::xml_node router_tag, const pugiutil::loc_data& loc_data, int router_id, std::vector& connection_list, std::string connection_list_attribute_value, std::map>& routers_in_arch_info) { - // we wil be modifying the string so store it in a temporary variable - // additinally, we peocess substrings seperated by spaces, so we add a space at the end of the string to be able to process the last sub-string - std::string modified_attribute_value = connection_list_attribute_value + " "; - std::string delimiter = " "; - std::stringstream single_connection; - int converted_connection; - - size_t position = 0; - - bool result = true; - - // find the position of the first space in the connection list string - while ((position = modified_attribute_value.find(delimiter)) != std::string::npos) { - // the string upto the space represent a single connection, so grab the substring - single_connection << modified_attribute_value.substr(0, position); - - // convert the connection to an integer - single_connection >> converted_connection; - - /* we expect the connection list to be a string of integers seperated by spaces, where each integer represents a router id that the current router is connected to. So we make sure that the router id was an integer. - */ - if (single_connection.fail()) { - // if we are here, then an integer was not supplied - result = false; - break; - } - - // check the case where a duplicate connection was provided - if (std::find(connection_list.begin(), connection_list.end(), converted_connection) != connection_list.end()) { - archfpga_throw(loc_data.filename_c_str(), loc_data.line(router_tag), - "The router with id:'%d' was included multiple times in the connection list for another router.", converted_connection); - } - - // make sure that the current router isn't connected to itself - if (router_id == converted_connection) { - archfpga_throw(loc_data.filename_c_str(), loc_data.line(router_tag), - "The router with id:%d was added to its own connection list. A router cannot connect to itself.", router_id); - } - - // if we are here then a legal router id was supplied, so store it - connection_list.push_back(converted_connection); - // update the connection information for the current router in the connection list - update_router_info_in_arch(converted_connection, true, routers_in_arch_info); - - // before we process the next router connection, we need to delete the substring (current router connection) - modified_attribute_value.erase(0, position + delimiter.length()); - // clear the buffer that stores the router connection in a string format for the next iteration - single_connection.clear(); - } - - return result; -} - -/* Each router needs a sperate tag in the architecture description - * to declare it. The number of declarations for each router in the - * architecture file is updated here. - * - * Additionally, for any given topology, a router can connect to other routers. - * THe number of connections for each router is also updated here. - * - */ -static void update_router_info_in_arch(int router_id, bool router_updated_as_a_connection, std::map>& routers_in_arch_info) { - // get the corresponding router info for the given router id - std::map>::iterator curr_router_info = routers_in_arch_info.find(router_id); - - // check if the router previously existed in the router indo database - if (curr_router_info == routers_in_arch_info.end()) { - // case where the router did not exist previosuly, so we add it here and also get a reference to it - // initially a router has no declarations or connections - curr_router_info = routers_in_arch_info.insert(std::pair>(router_id, std::pair(0, 0))).first; - } - - // case where the current router was provided while parsing the connections of another router - if (router_updated_as_a_connection) { - // since we are within the case where the current router is being processed as a connection to another router we just increment its number of connections - (curr_router_info->second.second)++; - - } else { - // since we are within the case where the current router is processed from a tag, we just increment its number of declarations - (curr_router_info->second.first)++; - } - - return; -} - -/* - * Verify each router in the noc by checking whether they satisfy the following conditions: - * - The router has only one declaration in the arch file - * - The router has atleast one connection to another router - * If any of the conditions above are not met, then an error is thrown. - */ -static void verify_noc_topology(std::map>& routers_in_arch_info) { - for (auto router_info = routers_in_arch_info.begin(); router_info != routers_in_arch_info.end(); router_info++) { - // case where the router was included in the architecture and had no connections to other routers - if ((router_info->second.first == 1) && (router_info->second.second == 0)) { - archfpga_throw("", -1, - "The router with id:'%d' is not connected to any other router in the NoC.", router_info->first); - - } // case where a router was found to be connected to another router but not declared using the tag in the arch file (ie. missing) - else if ((router_info->second.first == 0) && (router_info->second.second > 0)) { - archfpga_throw("", -1, - "The router with id:'%d' was found to be connected to another router but missing in the architecture file. Add the router using the tag.", router_info->first); - - } // case where the router was delcared multiple times in the architecture file (multiple tags for the same router) - else if (router_info->second.first > 1) { - archfpga_throw("", -1, - "The router with id:'%d' was included more than once in the architecture file. Routers should only be declared once.", router_info->first); - } - } - - return; -} +} \ No newline at end of file diff --git a/libs/libarchfpga/src/read_xml_arch_file.h b/libs/libarchfpga/src/read_xml_arch_file.h index 5021d031716..b6763493a4c 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.h +++ b/libs/libarchfpga/src/read_xml_arch_file.h @@ -9,8 +9,6 @@ extern "C" { /* special type indexes, necessary for initialization, everything afterwards * should use the pointers to these type indices*/ - -#define NUM_MODELS_IN_LIBRARY 4 #define EMPTY_TYPE_INDEX 0 /* function declarations */ diff --git a/libs/libarchfpga/src/read_xml_arch_file_noc_tag.cpp b/libs/libarchfpga/src/read_xml_arch_file_noc_tag.cpp new file mode 100644 index 00000000000..84fbb1226d0 --- /dev/null +++ b/libs/libarchfpga/src/read_xml_arch_file_noc_tag.cpp @@ -0,0 +1,673 @@ + +#include "read_xml_arch_file_noc_tag.h" + +#include "read_xml_util.h" +#include "pugixml_util.hpp" +#include "vtr_log.h" +#include "arch_error.h" + +/** + * @brief Process the tag under tag. + * + * Using tag, the user can specify a custom + * topology. + * + * @param topology_tag An XML node pointing to a tag. + * @param loc_data Points to the location in the xml file where the parser is reading. + * @param noc_ref To be filled with NoC router locations and their connectivity. + */ +static void process_topology(pugi::xml_node topology_tag, + const pugiutil::loc_data& loc_data, + t_noc_inf* noc_ref); + +/** + * @brief Process a tag under a tag. + * + * A tag contains multiple tags. Each tag has + * attributes that specify its location and connectivity to other NoC routers. + * + * @param router_tag An XML node pointing to a tag. + * @param loc_data Points to the location in the xml file where the parser is reading. + * @param noc_ref To be filled with the given router's location and connectivity information. + * @param routers_in_arch_info Stores router information that includes the number of connections + * a router has within a given topology and also the number of times a router was declared + * in the arch file using the tag. [router_id, [n_declarations, n_connections]] + */ +static void process_router(pugi::xml_node router_tag, + const pugiutil::loc_data& loc_data, + t_noc_inf* noc_ref, + std::map>& routers_in_arch_info); + +/** + * @brief Processes the tag under tag. + * + * Using the tag, the user can describe a NoC with + * mesh topology. + * + * @param mesh_topology_tag An XML tag pointing to a tag. + * @param loc_data Points to the location in the xml file where the parser is reading. + * @param noc_ref To be filled with NoC router locations and their connectivity. + */ +static void process_mesh_topology(pugi::xml_node mesh_topology_tag, + const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref); + + +/** + * Create routers and set their properties so that a mesh grid of routers is created. + * Then connect the routers together so that a mesh topology is created. + * + * @param mesh_topology_tag An XML tag pointing to a tag. + * @param loc_data Points to the location in the xml file where the parser is reading. + * @param noc_ref To be filled with NoC router locations and their connectivity. + * @param mesh_region_start_x The location the bottom left NoC router on the X-axis. + * @param mesh_region_end_x The location the top right NoC router on the X-axis. + * @param mesh_region_start_y The location the bottom left NoC router on the Y-axis. + * @param mesh_region_end_y The location the top right NoC router on the Y-axis. + * @param mesh_size The number of NoC routers in each row or column. + */ +static void generate_noc_mesh(pugi::xml_node mesh_topology_tag, + const pugiutil::loc_data& loc_data, + t_noc_inf* noc_ref, + double mesh_region_start_x, double mesh_region_end_x, + double mesh_region_start_y, double mesh_region_end_y, + int mesh_size); + +/** + * @brief Verify each router in the noc by checking whether they satisfy the following conditions: + * - The router has only one declaration in the arch file + * - The router has at least one connection to another router + * If any of the conditions above are not met, then an error is thrown. + * + * @param routers_in_arch_info Stores router information that includes the number of connections + * a router has within a given topology and also the number of times a router was declared + * in the arch file using the tag. [router_id, [n_declarations, n_connections]] + */ +static void verify_noc_topology(const std::map>& routers_in_arch_info); + +/** + * @brief Parses the connections field in tag under tag. + * The user provides the list of routers any given router is connected to + * by the router ids seperated by spaces. For example: + * connections="1 2 3 4 5" + * Go through the connections here and store them. Also make sure the list is legal. + * + * @param router_tag An XML node referring to a tag. + * @param loc_data Points to the location in the xml file where the parser is reading. + * @param router_id The id field of the given tag. + * @param connection_list Parsed connections of the given . To be filled by this + * function. + * @param connection_list_attribute_value Raw connections field of the given . + * @param routers_in_arch_info Stores router information that includes the number of connections + * a router has within a given topology and also the number of times a router was declared + * in the arch file using the tag. [router_id, [n_declarations, n_connections]] + * + * @return True if parsing the connection list was successful. + */ +static bool parse_noc_router_connection_list(pugi::xml_node router_tag, + const pugiutil::loc_data& loc_data, + int router_id, + std::vector& connection_list, + const std::string& connection_list_attribute_value, + std::map>& routers_in_arch_info); + +/** + * @brief Each router needs a separate tag in the architecture description file + * to declare it. The number of declarations for each router in the + * architecture file is updated here. Additionally, for any given topology, + * a router can connect to other routers. The number of connections for each router + * is also updated here. + * + * @param router_id The identifier of the router whose information needs to be updated. + * @param router_updated_as_a_connection Indicated whether the router id was seen in the + * connections field of a tag. + * @param routers_in_arch_info Stores router information that includes the number of connections + * a router has within a given topology and also the number of times a router was declared + * in the arch file using the tag. [router_id, [n_declarations, n_connections]] + */ +static void update_router_info_in_arch(int router_id, + bool router_updated_as_a_connection, + std::map>& routers_in_arch_info); + +/** + * @brief Process tag under tag. + * + * The user can override the default latency and bandwidth values + * for specific NoC routers and links using and + * tags under tag. + * + * @param noc_overrides_tag An XML node pointing to a tag. + * @param loc_data Points to the location in the xml file where the parser is reading. + * @param noc_ref To be filled with parsed overridden latencies and bandwidths. + */ +static void process_noc_overrides(pugi::xml_node noc_overrides_tag, + const pugiutil::loc_data& loc_data, + t_noc_inf& noc_ref); + +void process_noc_tag(pugi::xml_node noc_tag, + t_arch* arch, + const pugiutil::loc_data& loc_data) { + // a vector representing all the possible attributes within the noc tag + const std::vector expected_noc_attributes = {"link_bandwidth", "link_latency", "router_latency", "noc_router_tile_name"}; + + const std::vector expected_noc_children_tags = {"mesh", "topology"}; + + + // identifier that lets us know when we could not properly convert a string conversion value + std::string attribute_conversion_failure_string; + + // if we are here, then the user has a NoC in their architecture, so need to add it + arch->noc = new t_noc_inf; + t_noc_inf* noc_ref = arch->noc; + + /* process the noc attributes first */ + + // quick error check to make sure that we don't have unexpected attributes + pugiutil::expect_only_attributes(noc_tag, expected_noc_attributes, loc_data); + + // now go through and parse the required attributes for noc tag + + // variables below temporarily store the attribute values as string + // this is so that scientific notation can be used for these attributes + + auto link_bandwidth_intermediate_val = pugiutil::get_attribute(noc_tag, "link_bandwidth", loc_data, pugiutil::REQUIRED).as_string(); + noc_ref->link_bandwidth = std::atof(link_bandwidth_intermediate_val); + + auto link_latency_intermediate_val = pugiutil::get_attribute(noc_tag, "link_latency", loc_data, pugiutil::REQUIRED).as_string(); + noc_ref->link_latency = std::atof(link_latency_intermediate_val); + + auto router_latency_intermediate_val = pugiutil::get_attribute(noc_tag, "router_latency", loc_data, pugiutil::REQUIRED).as_string(); + noc_ref->router_latency = std::atof(router_latency_intermediate_val); + + noc_ref->noc_router_tile_name = pugiutil::get_attribute(noc_tag, "noc_router_tile_name", loc_data, pugiutil::REQUIRED).as_string(); + + // the noc parameters can only be non-zero positive values + if ((noc_ref->link_bandwidth <= 0.) || (noc_ref->link_latency <= 0.) || (noc_ref->router_latency <= 0.)) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(noc_tag), + "The link bandwidth, link latency and router latency for the NoC must be a positive non-zero value."); + } + + // check that the router tile name was supplied properly + if (!(noc_ref->noc_router_tile_name.compare(attribute_conversion_failure_string))) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(noc_tag), + "The noc router tile name must be a string."); + } + + /* We processed the NoC node, so now process the topology*/ + + // make sure that only the topology tag is found under NoC + pugiutil::expect_only_children(noc_tag, expected_noc_children_tags, loc_data); + + pugi::xml_node noc_mesh_topology = pugiutil::get_single_child(noc_tag, "mesh", loc_data, pugiutil::OPTIONAL); + + // we cannot check for errors related to number of routers and as well as whether a router is out of bounds (this will be done later) + // the chip still needs to be sized + + if (noc_mesh_topology) { + process_mesh_topology(noc_mesh_topology, loc_data, noc_ref); + } else { + pugi::xml_node noc_topology = pugiutil::get_single_child(noc_tag, "topology", loc_data, pugiutil::REQUIRED); + + process_topology(noc_topology, loc_data, noc_ref); + } + + pugi::xml_node noc_overrides = pugiutil::get_single_child(noc_tag, "overrides", loc_data, pugiutil::OPTIONAL); + if (noc_overrides) { + process_noc_overrides(noc_overrides, loc_data, *noc_ref); + } +} + +/* + * A NoC mesh is created based on the user supplied size and region location. + */ +static void process_mesh_topology(pugi::xml_node mesh_topology_tag, + const pugiutil::loc_data& loc_data, + t_noc_inf* noc_ref) { + + // identifier that lets us know when we could not properly convert an attribute value to a number + constexpr int ATTRIBUTE_CONVERSION_FAILURE = -1; + + // a list of attributes that should be found for the mesh tag + std::vector expected_router_attributes = {"startx", "endx", "starty", "endy", "size"}; + + // verify that only the acceptable attributes were supplied + pugiutil::expect_only_attributes(mesh_topology_tag, expected_router_attributes, loc_data); + + // go through the attributes and store their values + double mesh_region_start_x = pugiutil::get_attribute(mesh_topology_tag, "startx", loc_data, pugiutil::REQUIRED).as_double(ATTRIBUTE_CONVERSION_FAILURE); + double mesh_region_end_x = pugiutil::get_attribute(mesh_topology_tag, "endx", loc_data, pugiutil::REQUIRED).as_double(ATTRIBUTE_CONVERSION_FAILURE); + double mesh_region_start_y = pugiutil::get_attribute(mesh_topology_tag, "starty", loc_data, pugiutil::REQUIRED).as_double(ATTRIBUTE_CONVERSION_FAILURE); + double mesh_region_end_y = pugiutil::get_attribute(mesh_topology_tag, "endy", loc_data, pugiutil::REQUIRED).as_double(ATTRIBUTE_CONVERSION_FAILURE); + + int mesh_size = pugiutil::get_attribute(mesh_topology_tag, "size", loc_data, pugiutil::REQUIRED).as_int(ATTRIBUTE_CONVERSION_FAILURE); + + // verify that the attributes provided were legal + if ((mesh_region_start_x < 0) || (mesh_region_end_x < 0) || (mesh_region_start_y < 0) || (mesh_region_end_y < 0) || (mesh_size < 0)) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(mesh_topology_tag), + "The parameters for the mesh topology have to be positive values."); + } + + // now create the mesh topology for the noc + // create routers, make connections and determine positions + generate_noc_mesh(mesh_topology_tag, loc_data, noc_ref, mesh_region_start_x, mesh_region_end_x, mesh_region_start_y, mesh_region_end_y, mesh_size); +} + +static void generate_noc_mesh(pugi::xml_node mesh_topology_tag, + const pugiutil::loc_data& loc_data, + t_noc_inf* noc_ref, + double mesh_region_start_x, double mesh_region_end_x, + double mesh_region_start_y, double mesh_region_end_y, + int mesh_size) { + // check that the mesh size of the router is not 0 + if (mesh_size == 0) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(mesh_topology_tag), + "The NoC mesh size cannot be 0."); + } + + // calculating the vertical and horizontal distances between routers in the supplied region + // we decrease the mesh size by 1 when calculating the spacing so that the first and + // last routers of each row or column are positioned on the mesh boundary + /* + * For example: + * - If we had a mesh size of 3, then using 3 would result in a spacing that would result in + * one router positions being placed in either the start of the region or end of the region. + * This is because the distance calculation resulted in having 3 spaces between the ends of the region + * + * start end + *** *** *** *** + * + * - if we instead used 2 in the distance calculation, the resulting positions would result in + * having 2 routers positioned on the start and end of the region. + * This is beacuse we now specified 2 spaces between the region and this allows us to place 2 routers + * on the regions edges and one router in the center. + * + * start end + *** *** *** + * + * THe reasoning for this is to reduce the number of calculated router positions. + */ + double vertical_router_separation = (mesh_region_end_y - mesh_region_start_y) / (mesh_size - 1); + double horizontal_router_separation = (mesh_region_end_x - mesh_region_start_x) / (mesh_size - 1); + + t_router temp_router; + + // improper region check + if ((vertical_router_separation <= 0) || (horizontal_router_separation <= 0)) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(mesh_topology_tag), + "The NoC region is invalid."); + } + + // create routers and their connections + // start with router id 0 (bottom left of the chip) to the maximum router id (top right of the chip) + for (int j = 0; j < mesh_size; j++) { + for (int i = 0; i < mesh_size; i++) { + // assign router id + temp_router.id = (mesh_size * j) + i; + + // calculate router position + /* The first and last router of each column or row will be located on the mesh region boundary, + * the remaining routers will be placed within the region and seperated from other routers + * using the distance calculated previously. + */ + temp_router.device_x_position = (i * horizontal_router_separation) + mesh_region_start_x; + temp_router.device_y_position = (j * vertical_router_separation) + mesh_region_start_y; + + // assign connections + // check if there is a router to the left + if ((i - 1) >= 0) { + // add the left router as a connection + temp_router.connection_list.push_back((mesh_size * j) + i - 1); + } + + // check if there is a router to the top + if ((j + 1) <= (mesh_size - 1)) { + // add the top router as a connection + temp_router.connection_list.push_back((mesh_size * (j + 1)) + i); + } + + // check if there is a router to the right + if ((i + 1) <= (mesh_size - 1)) { + // add the router located to the right + temp_router.connection_list.push_back((mesh_size * j) + i + 1); + } + + // check of there is a router below + if ((j - 1) >= (0)) { + // add the bottom router as a connection + temp_router.connection_list.push_back((mesh_size * (j - 1)) + i); + } + + // add the router to the list + noc_ref->router_list.push_back(temp_router); + + // clear the current router information for the next router + temp_router.connection_list.clear(); + } + } +} + +/* + * Go through each router in the NoC and store the list of routers that connect to it. + */ +static void process_topology(pugi::xml_node topology_tag, + const pugiutil::loc_data& loc_data, + t_noc_inf* noc_ref) { + // The topology tag should have no attributes, check that + pugiutil::expect_only_attributes(topology_tag, {}, loc_data); + + /** + * Stores router information that includes the number of connections a router + * has within a given topology and also the number of times a router was declared + * in the arch file using the tag. + * key --> router id + * value.first --> the number of router declarations + * value.second --> the number of router connections + * This is used only for error checking. + */ + std::map> routers_in_arch_info; + + /* Now go through the children tags of topology, which is basically + * each router found within the NoC + */ + for (pugi::xml_node router : topology_tag.children()) { + // we can only have router tags within the topology + if (router.name() != std::string("router")) { + bad_tag(router, loc_data, topology_tag, {"router"}); + } else { + // current tag is a valid router, so process it + process_router(router, loc_data, noc_ref, routers_in_arch_info); + } + } + + // check whether any routers were supplied + if (noc_ref->router_list.empty()) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(topology_tag), + "No routers were supplied for the NoC."); + } + + // check that the topology of the noc was correctly described in the arch file + verify_noc_topology(routers_in_arch_info); +} + +/* + * Store the properties of a single router and then store the list of routers that connect to it. + */ +static void process_router(pugi::xml_node router_tag, + const pugiutil::loc_data& loc_data, + t_noc_inf* noc_ref, + std::map>& routers_in_arch_info) { + // identifier that lets us know when we could not properly convert an attribute value to an integer + constexpr int ATTRIBUTE_CONVERSION_FAILURE = -1; + + // an accepted list of attributes for the router tag + std::vector expected_router_attributes = {"id", "positionx", "positiony", "connections"}; + + // check that only the accepted router attributes are found in the tag + pugiutil::expect_only_attributes(router_tag, expected_router_attributes, loc_data); + + // variable to store current router info + t_router router_info; + + // store the router information from the attributes + router_info.id = pugiutil::get_attribute(router_tag, "id", loc_data, pugiutil::REQUIRED).as_int(ATTRIBUTE_CONVERSION_FAILURE); + + router_info.device_x_position = pugiutil::get_attribute(router_tag, "positionx", loc_data, pugiutil::REQUIRED).as_double(ATTRIBUTE_CONVERSION_FAILURE); + + router_info.device_y_position = pugiutil::get_attribute(router_tag, "positiony", loc_data, pugiutil::REQUIRED).as_double(ATTRIBUTE_CONVERSION_FAILURE); + + // verify whether the attribute information was legal + if ((router_info.id < 0) || (router_info.device_x_position < 0) || (router_info.device_y_position < 0)) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(router_tag), + "The router id, and position (x & y) for the router must be a positive number."); + } + + // get the current router connection list + std::string router_connection_list_attribute_value = pugiutil::get_attribute(router_tag, "connections", loc_data, pugiutil::REQUIRED).as_string(); + + // if the connections attribute was not provided, or it was empty, then we don't process it and throw a warning + if (!router_connection_list_attribute_value.empty()) { + // process the router connection list + bool router_connection_list_result = parse_noc_router_connection_list(router_tag, loc_data, router_info.id, + router_info.connection_list, + router_connection_list_attribute_value, + routers_in_arch_info); + + // check if the user provided a legal router connection list + if (!router_connection_list_result) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(router_tag), + "The 'connections' attribute for the router must be a list of integers seperated by spaces, " + "where each integer represents a router id that the current router is connected to."); + } + + } else { + VTR_LOGF_WARN(loc_data.filename_c_str(), loc_data.line(router_tag), + "The router with id:%d either has an empty 'connections' attribute " + "or does not have any associated connections to other routers in the NoC.\n", + router_info.id); + } + + // at this point the current router information was completely legal, so we store the newly created router within the noc + noc_ref->router_list.push_back(router_info); + + // update the number of declarations info for the current router (since we just finished processing one tag) + update_router_info_in_arch(router_info.id, false, routers_in_arch_info); +} + +static void verify_noc_topology(const std::map>& routers_in_arch_info) { + + for (const auto& [router_id, router_info] : routers_in_arch_info) { + const auto [n_declarations, n_connections] = router_info; + // case where the router was included in the architecture and had no connections to other routers + if (n_declarations == 1 && n_connections == 0) { + archfpga_throw("", -1, + "The router with id:'%d' is not connected to any other router in the NoC.", + router_id); + + } // case where a router was found to be connected to another router but not declared using the tag in the arch file (i.e. missing) + else if (n_declarations == 0 && n_connections > 0) { + archfpga_throw("", -1, + "The router with id:'%d' was found to be connected to another router " + "but missing in the architecture file. Add the router using the tag.", + router_id); + + } // case where the router was declared multiple times in the architecture file (multiple tags for the same router) + else if (n_declarations > 1) { + archfpga_throw("", -1, + "The router with id:'%d' was included more than once in the architecture file. " + "Routers should only be declared once.", + router_id); + } + } +} + +static bool parse_noc_router_connection_list(pugi::xml_node router_tag, + const pugiutil::loc_data& loc_data, + int router_id, + std::vector& connection_list, + const std::string& connection_list_attribute_value, + std::map>& routers_in_arch_info) { + // we wil be modifying the string so store it in a temporary variable + // additionally, we process substrings seperated by spaces, + // so we add a space at the end of the string to be able to process the last sub-string + std::string modified_attribute_value = connection_list_attribute_value + " "; + const std::string delimiter = " "; + std::stringstream single_connection; + int converted_connection; + + size_t position = 0; + + bool result = true; + + // find the position of the first space in the connection list string + while ((position = modified_attribute_value.find(delimiter)) != std::string::npos) { + // the string upto the space represent a single connection, so grab the substring + single_connection << modified_attribute_value.substr(0, position); + + // convert the connection to an integer + single_connection >> converted_connection; + + /* we expect the connection list to be a string of integers seperated by spaces, + * where each integer represents a router id that the current router is connected to. + * So we make sure that the router id was an integer. + */ + if (single_connection.fail()) { + // if we are here, then an integer was not supplied + result = false; + break; + } + + // check the case where a duplicate connection was provided + if (std::find(connection_list.begin(), connection_list.end(), converted_connection) != connection_list.end()) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(router_tag), + "The router with id:'%d' was included multiple times in the connection list for another router.", converted_connection); + } + + // make sure that the current router isn't connected to itself + if (router_id == converted_connection) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(router_tag), + "The router with id:%d was added to its own connection list. A router cannot connect to itself.", router_id); + } + + // if we are here then a legal router id was supplied, so store it + connection_list.push_back(converted_connection); + // update the connection information for the current router in the connection list + update_router_info_in_arch(converted_connection, true, routers_in_arch_info); + + // before we process the next router connection, we need to delete the substring (current router connection) + modified_attribute_value.erase(0, position + delimiter.length()); + // clear the buffer that stores the router connection in a string format for the next iteration + single_connection.clear(); + } + + return result; +} + +static void update_router_info_in_arch(int router_id, + bool router_updated_as_a_connection, + std::map>& routers_in_arch_info) { + // try to add the router + // if it was already added, get the existing one + auto [curr_router_info, _] = routers_in_arch_info.insert({router_id, {0, 0}}); + + auto& [n_declarations, n_connections] = curr_router_info->second; + + // case where the current router was provided while parsing the connections of another router + if (router_updated_as_a_connection) { + // since we are within the case where the current router is being processed as + // a connection to another router we just increment its number of connections + n_connections++; + + } else { + // since we are within the case where the current router is processed from a tag, + // we just increment its number of declarations + n_declarations++; + } +} + +static void process_noc_overrides(pugi::xml_node noc_overrides_tag, + const pugiutil::loc_data& loc_data, + t_noc_inf& noc_ref) { + // an accepted list of attributes for the router tag + const std::vector expected_router_attributes{"id", "latency"}; + // the list of expected values for link tag + const std::vector expected_link_override_attributes{"src", "dst", "latency", "bandwidth"}; + + for (pugi::xml_node override_tag : noc_overrides_tag.children()) { + std::string_view override_name = override_tag.name(); + + if (override_name == "router") { + // check that only the accepted router attributes are found in the tag + pugiutil::expect_only_attributes(override_tag, expected_router_attributes, loc_data); + + // store the router information from the attributes + int id = pugiutil::get_attribute(noc_overrides_tag, "id", loc_data, pugiutil::REQUIRED).as_int(-1); + + auto router_latency_override = pugiutil::get_attribute(override_tag, "latency", loc_data, pugiutil::REQUIRED).as_string(); + double latency = std::atof(router_latency_override); + + if (id < 0 || latency <= 0.0) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(override_tag), + "The latency override value (%g) for router with id:%d is not legal. " + "The router id must be non-negative and the latency must be positive.", + latency, id); + } + + auto it = std::find_if(noc_ref.router_list.begin(), noc_ref.router_list.end(), [id](const t_router& router) { + return router.id == id; + }); + + if (it == noc_ref.router_list.end()) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(override_tag), + "The router with id:%d could not be found in the topology.", + id); + } + + auto [_, success] = noc_ref.router_latency_overrides.insert({id, latency}); + if (!success) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(override_tag), + "The latency of the router with id:%d wad overridden once before.", + id); + } + + } else if (override_name == "link") { + // check that only the accepted link attributes are found in the tag + pugiutil::expect_only_attributes(override_tag, expected_link_override_attributes, loc_data); + + // store the router information from the attributes + int src = pugiutil::get_attribute(noc_overrides_tag, "src", loc_data, pugiutil::REQUIRED).as_int(-1); + int dst = pugiutil::get_attribute(noc_overrides_tag, "dst", loc_data, pugiutil::REQUIRED).as_int(-1); + + if (src < 0 || dst < 0) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(override_tag), + "The source and destination router ids (%d, %d) must be non-negative.", + src, dst); + } + + auto it = std::find_if(noc_ref.router_list.begin(), noc_ref.router_list.end(), [src, dst](const t_router& router) { + return router.id == src && + std::find(router.connection_list.begin(), router.connection_list.end(), dst) != router.connection_list.end(); + }); + + if (it == noc_ref.router_list.end()) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(override_tag), + "There is no links from the router with id:%d to the router with id:%d.", + src, dst); + } + + auto link_latency_override = pugiutil::get_attribute(override_tag, "latency", loc_data, pugiutil::REQUIRED).as_string(nullptr); + if (link_latency_override != nullptr) { + double latency = std::atof(link_latency_override); + if (latency <= 0.0) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(override_tag), + "The override link latency value for link (%d, %d) must be positive:%g." , + src, dst, latency); + } + + auto [_, success] = noc_ref.link_latency_overrides.insert({{src, dst}, latency}); + if (!success) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(override_tag), + "The latency for link (%d, %d) was overridden once before." , + src, dst); + } + } + + auto link_bandwidth_override = pugiutil::get_attribute(override_tag, "bandwidth", loc_data, pugiutil::REQUIRED).as_string(nullptr); + if (link_bandwidth_override != nullptr) { + double bandwidth = std::atof(link_latency_override); + if (bandwidth <= 0.0) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(override_tag), + "The override link bandwidth value for link (%d, %d) must be positive:%g." , + src, dst, bandwidth); + } + + auto [_, success] = noc_ref.link_bandwidth_overrides.insert({{src, dst}, bandwidth}); + if (!success) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(override_tag), + "The bandwidth for link (%d, %d) was overridden once before." , + src, dst); + } + } + } else { + bad_tag(override_tag, loc_data, noc_overrides_tag, {"router", "link"}); + } + } +} \ No newline at end of file diff --git a/libs/libarchfpga/src/read_xml_arch_file_noc_tag.h b/libs/libarchfpga/src/read_xml_arch_file_noc_tag.h new file mode 100644 index 00000000000..8309d8cdec9 --- /dev/null +++ b/libs/libarchfpga/src/read_xml_arch_file_noc_tag.h @@ -0,0 +1,20 @@ + +#ifndef VTR_READ_XML_ARCH_FILE_NOC_TAG_H +#define VTR_READ_XML_ARCH_FILE_NOC_TAG_H + +#include "pugixml.hpp" +#include "pugixml_loc.hpp" +#include "physical_types.h" + +/** + * @brief Parses NoC-related information under tag. + * @param noc_tag An XML node pointing to tag. + * @param arch High-level architecture information. This function fills + * arch->noc with NoC-related information. + * @param loc_data Points to the location in the xml file where the parser is reading. + */ +void process_noc_tag(pugi::xml_node noc_tag, + t_arch* arch, + const pugiutil::loc_data& loc_data); + +#endif //VTR_READ_XML_ARCH_FILE_NOC_TAG_H diff --git a/libs/libarchfpga/src/read_xml_util.cpp b/libs/libarchfpga/src/read_xml_util.cpp index 784d08a9b4f..fd2e76c4ad4 100644 --- a/libs/libarchfpga/src/read_xml_util.cpp +++ b/libs/libarchfpga/src/read_xml_util.cpp @@ -43,7 +43,7 @@ InstPort make_inst_port(pugi::xml_attribute attr, pugi::xml_node node, const pug void bad_tag(const pugi::xml_node node, const pugiutil::loc_data& loc_data, const pugi::xml_node parent_node, - const std::vector expected_tags) { + const std::vector& expected_tags) { std::string msg = "Unexpected tag "; msg += "<"; msg += node.name(); @@ -76,7 +76,7 @@ void bad_tag(const pugi::xml_node node, void bad_attribute(const pugi::xml_attribute attr, const pugi::xml_node node, const pugiutil::loc_data& loc_data, - const std::vector expected_attributes) { + const std::vector& expected_attributes) { std::string msg = "Unexpected attribute "; msg += "'"; msg += attr.name(); @@ -109,7 +109,7 @@ void bad_attribute(const pugi::xml_attribute attr, void bad_attribute_value(const pugi::xml_attribute attr, const pugi::xml_node node, const pugiutil::loc_data& loc_data, - const std::vector expected_values) { + const std::vector& expected_values) { std::string msg = "Invalid value '"; msg += attr.value(); msg += "'"; diff --git a/libs/libarchfpga/src/read_xml_util.h b/libs/libarchfpga/src/read_xml_util.h index 05a77ab0377..b5fa4fbf704 100644 --- a/libs/libarchfpga/src/read_xml_util.h +++ b/libs/libarchfpga/src/read_xml_util.h @@ -11,16 +11,16 @@ pugiutil::ReqOpt BoolToReqOpt(bool b); void bad_tag(const pugi::xml_node node, const pugiutil::loc_data& loc_data, const pugi::xml_node parent_node = pugi::xml_node(), - const std::vector expected_tags = std::vector()); + const std::vector& expected_tags = std::vector()); void bad_attribute(const pugi::xml_attribute attr, const pugi::xml_node node, const pugiutil::loc_data& loc_data, - const std::vector expected_attributes = std::vector()); + const std::vector& expected_attributes = std::vector()); void bad_attribute_value(const pugi::xml_attribute attr, const pugi::xml_node node, const pugiutil::loc_data& loc_data, - const std::vector expected_attributes = std::vector()); + const std::vector& expected_attributes = std::vector()); InstPort make_inst_port(std::string str, pugi::xml_node node, const pugiutil::loc_data& loc_data); InstPort make_inst_port(pugi::xml_attribute attr, pugi::xml_node node, const pugiutil::loc_data& loc_data); diff --git a/libs/libarchfpga/test/test_read_xml_arch_file.cpp b/libs/libarchfpga/test/test_read_xml_arch_file.cpp index adc9eab42d1..19da2315afe 100644 --- a/libs/libarchfpga/test/test_read_xml_arch_file.cpp +++ b/libs/libarchfpga/test/test_read_xml_arch_file.cpp @@ -2,8 +2,8 @@ #include "catch2/catch_test_macros.hpp" #include "catch2/matchers/catch_matchers_all.hpp" -// testting statuc functions so include whole source file it is in -#include "read_xml_arch_file.cpp" +// testing static functions so include whole source file it is in +#include "read_xml_arch_file_noc_tag.cpp" // for comparing floats #include "vtr_math.h" @@ -25,7 +25,7 @@ TEST_CASE("Updating router info in arch", "[NoC Arch Tests]") { it = test_router_list.find(router_id); - // check first that the router was newly added to the router databse + // check first that the router was newly added to the router database REQUIRE(it != test_router_list.end()); // no verify the components of the router parameter @@ -39,7 +39,7 @@ TEST_CASE("Updating router info in arch", "[NoC Arch Tests]") { it = test_router_list.find(router_id); - // check first that the router was newly added to the router databse + // check first that the router was newly added to the router database REQUIRE(it != test_router_list.end()); // no verify the components of the router parameter @@ -56,7 +56,7 @@ TEST_CASE("Updating router info in arch", "[NoC Arch Tests]") { it = test_router_list.find(router_id); - // check first that the router was newly added to the router databse + // check first that the router was newly added to the router database REQUIRE(it != test_router_list.end()); // no verify the components of the router parameter @@ -75,7 +75,7 @@ TEST_CASE("Updating router info in arch", "[NoC Arch Tests]") { it = test_router_list.find(router_id); - // check first that the router was newly added to the router databse + // check first that the router was newly added to the router database REQUIRE(it != test_router_list.end()); // no verify the components of the router parameter @@ -172,7 +172,7 @@ TEST_CASE("Verifying mesh topology creation", "[NoC Arch Tests]") { mesh_end_x = 4; mesh_end_y = 4; - // create the golden golden results + // create the golden results double golden_results_x[9]; double golden_results_y[9]; diff --git a/libs/libpugiutil/src/pugixml_util.cpp b/libs/libpugiutil/src/pugixml_util.cpp index d4d2a398246..1353f2114d1 100644 --- a/libs/libpugiutil/src/pugixml_util.cpp +++ b/libs/libpugiutil/src/pugixml_util.cpp @@ -81,7 +81,7 @@ size_t count_children(const pugi::xml_node node, child = child.next_sibling(child_name.c_str()); } - //Note that we don't do any error checking here since get_first_child does the existance check + //Note that we don't do any error checking here since get_first_child does the existence check return count; } @@ -150,7 +150,7 @@ void expect_child_node_count(const pugi::xml_node node, // child_names - expected attribute names // loc_data - XML file location data void expect_only_children(const pugi::xml_node node, - std::vector child_names, + const std::vector& child_names, const loc_data& loc_data) { for (auto child : node.children()) { std::string child_name = child.name(); @@ -161,7 +161,7 @@ void expect_only_children(const pugi::xml_node node, std::string msg = "Unexpected child '" + child_name + "'" + " of node '" + node.name() + "'."; - if (child_names.size() > 0) { + if (!child_names.empty()) { msg += " Expected (possibly) one of: "; for (size_t i = 0; i < child_names.size(); i++) { if (i != 0) { @@ -188,7 +188,7 @@ void expect_only_children(const pugi::xml_node node, // loc_data - XML file location data void expect_only_attributes(const pugi::xml_node node, std::vector attribute_names, - std::string explanation, + std::string_view explanation, const loc_data& loc_data) { for (auto attrib : node.attributes()) { std::string attrib_name = attrib.name(); @@ -205,7 +205,7 @@ void expect_only_attributes(const pugi::xml_node node, msg += "."; - if (attribute_names.size() > 0) { + if (!attribute_names.empty()) { msg += " Expected (possibly) one of: "; for (size_t i = 0; i < attribute_names.size(); i++) { if (i != 0) { @@ -225,13 +225,13 @@ void expect_only_attributes(const pugi::xml_node node, } //Throws a well formatted error if any attribute other than those named in 'attribute_names' are found on 'node'. -//Note this does not check whether the attribues in 'attribute_names' actually exist; for that use get_attribute(). +//Note this does not check whether the attributes in 'attribute_names' actually exist; for that use get_attribute(). // // node - The parent xml node // attribute_names - expected attribute names // loc_data - XML file location data void expect_only_attributes(const pugi::xml_node node, - std::vector attribute_names, + const std::vector& attribute_names, const loc_data& loc_data) { expect_only_attributes(node, attribute_names, "", loc_data); } @@ -254,7 +254,7 @@ size_t count_attributes(const pugi::xml_node node, return count; } -//Gets a named property on an node and returns it. +//Gets a named property on a node and returns it. // // node - The xml node // attr_name - The attribute name diff --git a/libs/libpugiutil/src/pugixml_util.hpp b/libs/libpugiutil/src/pugixml_util.hpp index 8e55f232bc0..3bb60779fc0 100644 --- a/libs/libpugiutil/src/pugixml_util.hpp +++ b/libs/libpugiutil/src/pugixml_util.hpp @@ -16,6 +16,7 @@ #include #include #include +#include #include "pugixml.hpp" @@ -138,7 +139,7 @@ void expect_child_node_count(const pugi::xml_node node, // child_names - expected attribute names // loc_data - XML file location data void expect_only_children(const pugi::xml_node node, - std::vector child_names, + const std::vector& child_names, const loc_data& loc_data); //Throws a well formatted error if any attribute other than those named in 'attribute_names' are found on 'node'. @@ -148,7 +149,7 @@ void expect_only_children(const pugi::xml_node node, // attribute_names - expected attribute names // loc_data - XML file location data void expect_only_attributes(const pugi::xml_node node, - std::vector attribute_names, + const std::vector& attribute_names, const loc_data& loc_data); //Throws a well formatted error if any attribute other than those named in 'attribute_names' are found on 'node' with an additional explanation. @@ -159,7 +160,7 @@ void expect_only_attributes(const pugi::xml_node node, // loc_data - XML file location data void expect_only_attributes(const pugi::xml_node node, std::vector attribute_names, - std::string explanation, + std::string_view explanation, const loc_data& loc_data); //Counts the number of attributes on the specified node @@ -171,7 +172,7 @@ size_t count_attributes(const pugi::xml_node node, const loc_data& loc_data, const ReqOpt req_opt = REQUIRED); -//Gets a named property on an node and returns it. +//Gets a named property on a node and returns it. // // node - The xml node // attr_name - The attribute name diff --git a/libs/libvtrutil/src/vtr_string_interning.h b/libs/libvtrutil/src/vtr_string_interning.h index 3af949701b2..bbf22766170 100644 --- a/libs/libvtrutil/src/vtr_string_interning.h +++ b/libs/libvtrutil/src/vtr_string_interning.h @@ -11,7 +11,7 @@ * * This string internment has an additional feature that is splitting the * input string into "parts" based on '.', which happens to be the feature - * seperator for FASM. This means the string "TILE.CLB.A" and "TILE.CLB.B" + * separator for FASM. This means the string "TILE.CLB.A" and "TILE.CLB.B" * would be made up of the intern ids for {"TILE", "CLB", "A"} and * {"TILE", "CLB", "B"} respectively, allowing some internal deduplication. * @@ -20,14 +20,14 @@ * * Interned strings (interned_string) that come from the same internment * object (string_internment) can safely be checked for equality and hashed - * without touching the underlying string. Lexigraphical comprisions (e.g. <) + * without touching the underlying string. Lexigraphical comparisons (e.g. <) * requires reconstructing the string. * * Basic usage: * -# Create a string_internment * -# Invoke string_internment::intern_string, which returns the - * interned_string object that is the interned string's unique idenfier. - * This idenfier can be checked for equality or hashed. If + * interned_string object that is the interned string's unique identifier. + * This identifier can be checked for equality or hashed. If * string_internment::intern_string is called with the same string, a value * equivalent interned_string object will be returned. * -# If the original string is required, interned_string::get can be invoked diff --git a/vpr/src/base/setup_noc.cpp b/vpr/src/base/setup_noc.cpp index a2975b9683c..b2eabc33842 100644 --- a/vpr/src/base/setup_noc.cpp +++ b/vpr/src/base/setup_noc.cpp @@ -1,18 +1,19 @@ -#include #include #include "setup_noc.h" -#include "vtr_assert.h" +#include "globals.h" #include "vpr_error.h" #include "vtr_math.h" #include "echo_files.h" -void setup_noc(const t_arch& arch) { - // variable to store all the noc router tiles within the FPGA device - // physical routers - std::vector noc_router_tiles; +// a default condition that helps keep track of whether a physical router has been assigned to a logical router or not +static constexpr int PHYSICAL_ROUTER_NOT_ASSIGNED = -1; +// a default index used for initialization purposes. No router will have a negative index +static constexpr int INVALID_PHYSICAL_ROUTER_INDEX = -1; + +void setup_noc(const t_arch& arch) { // get references to global variables auto& device_ctx = g_vpr_ctx.device(); auto& noc_ctx = g_vpr_ctx.mutable_noc(); @@ -25,17 +26,22 @@ void setup_noc(const t_arch& arch) { // go through the FPGA grid and find the noc router tiles // then store the position - identify_and_store_noc_router_tile_positions(device_ctx.grid, noc_router_tiles, arch.noc->noc_router_tile_name); + auto noc_router_tiles = identify_and_store_noc_router_tile_positions(device_ctx.grid, arch.noc->noc_router_tile_name); // check whether the noc topology information provided uses more than the number of available routers in the FPGA if (noc_router_tiles.size() < arch.noc->router_list.size()) { - VPR_FATAL_ERROR(VPR_ERROR_OTHER, "The Provided NoC topology information in the architecture file has more number of routers than what is available in the FPGA device."); - } else if (noc_router_tiles.size() > arch.noc->router_list.size()) // check whether the noc topology information provided is using all the routers in the FPGA - { - VPR_FATAL_ERROR(VPR_ERROR_OTHER, "The Provided NoC topology information in the architecture file uses less number of routers than what is available in the FPGA device."); - } else if (noc_router_tiles.empty()) // case where no physical router tiles were found - { - VPR_FATAL_ERROR(VPR_ERROR_OTHER, "No physical NoC routers were found on the FPGA device. Either the provided name for the physical router tile was incorrect or the FPGA device has no routers."); + VPR_FATAL_ERROR(VPR_ERROR_OTHER, + "The Provided NoC topology information in the architecture file " + "has more number of routers than what is available in the FPGA device."); + } else if (noc_router_tiles.size() > arch.noc->router_list.size()) { + // check whether the noc topology information provided is using all the routers in the FPGA + VPR_FATAL_ERROR(VPR_ERROR_OTHER, + "The Provided NoC topology information in the architecture file " + "uses less number of routers than what is available in the FPGA device."); + } else if (noc_router_tiles.empty()) { // case where no physical router tiles were found + VPR_FATAL_ERROR(VPR_ERROR_OTHER, + "No physical NoC routers were found on the FPGA device. " + "Either the provided name for the physical router tile was incorrect or the FPGA device has no routers."); } // store the reference to device grid with @@ -45,8 +51,10 @@ void setup_noc(const t_arch& arch) { // generate noc model generate_noc(arch, noc_ctx, noc_router_tiles); - // store the general noc properties - noc_ctx.noc_model.set_noc_link_bandwidth(arch.noc->link_bandwidth); + /* store the general noc properties + * noc_ctx.noc_model.set_noc_link_bandwidth(...) is not called because all + * link bandwidths were set when create_noc_links(...) was called. + */ noc_ctx.noc_model.set_noc_link_latency(arch.noc->link_latency); noc_ctx.noc_model.set_noc_router_latency(arch.noc->router_latency); @@ -54,25 +62,18 @@ void setup_noc(const t_arch& arch) { if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_NOC_MODEL)) { noc_ctx.noc_model.echo_noc(getEchoFileName(E_ECHO_NOC_MODEL)); } - - return; } -void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, std::vector& noc_router_tiles, const std::string& noc_router_tile_name) { +std::vector identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, + std::string_view noc_router_tile_name) { const int num_layers = device_grid.get_num_layers(); - int curr_tile_width; - int curr_tile_height; - int curr_tile_width_offset; - int curr_tile_height_offset; - std::string curr_tile_name; + const int grid_width = (int)device_grid.width(); + const int grid_height = (int)device_grid.height(); - double curr_tile_centroid_x; - double curr_tile_centroid_y; + std::vector noc_router_tiles; // go through the device for (int layer_num = 0; layer_num < num_layers; layer_num++) { - int grid_width = (int)device_grid.width(); - int grid_height = (int)device_grid.height(); for (int i = 0; i < grid_width; i++) { for (int j = 0; j < grid_height; j++) { // get some information from the current tile @@ -80,34 +81,39 @@ void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, int width_offset = device_grid.get_width_offset({i, j, layer_num}); int height_offset = device_grid.get_height_offset({i, j, layer_num}); - curr_tile_name.assign(type->name); - curr_tile_width_offset = width_offset; - curr_tile_height_offset = height_offset; + std::string_view curr_tile_name = type->name; + int curr_tile_width_offset = width_offset; + int curr_tile_height_offset = height_offset; - curr_tile_height = type->height; - curr_tile_width = type->width; + int curr_tile_height = type->height; + int curr_tile_width = type->width; /* * Only store the tile position if it is a noc router. - * Additionally, since a router tile can span multiple grid locations, we only add the tile if the height and width offset are zero (this prevents the router from being added multiple times for each grid location it spans). + * Additionally, since a router tile can span multiple grid locations, + * we only add the tile if the height and width offset are zero (this prevents the router from being added multiple times for each grid location it spans). */ - if (!(noc_router_tile_name.compare(curr_tile_name)) && !curr_tile_width_offset && !curr_tile_height_offset) { + if (noc_router_tile_name == curr_tile_name && !curr_tile_width_offset && !curr_tile_height_offset) { // calculating the centroid position of the current tile - curr_tile_centroid_x = (curr_tile_width - 1) / (double)2 + i; - curr_tile_centroid_y = (curr_tile_height - 1) / (double)2 + j; + double curr_tile_centroid_x = (curr_tile_width - 1) / (double)2 + i; + double curr_tile_centroid_y = (curr_tile_height - 1) / (double)2 + j; noc_router_tiles.emplace_back(i, j, layer_num, curr_tile_centroid_x, curr_tile_centroid_y); } } } } + + return noc_router_tiles; } -void generate_noc(const t_arch& arch, NocContext& noc_ctx, std::vector& noc_router_tiles) { - // refrernces to the noc +void generate_noc(const t_arch& arch, + NocContext& noc_ctx, + const std::vector& noc_router_tiles) { + // references to the noc NocStorage* noc_model = &noc_ctx.noc_model; // reference to the noc description - const t_noc_inf* noc_info = arch.noc; + const t_noc_inf& noc_info = *arch.noc; // initialize the noc noc_model->clear_noc(); @@ -120,25 +126,16 @@ void generate_noc(const t_arch& arch, NocContext& noc_ctx, std::vectorfinished_building_noc(); - - return; } -void create_noc_routers(const t_noc_inf& noc_info, NocStorage* noc_model, std::vector& noc_router_tiles) { +void create_noc_routers(const t_noc_inf& noc_info, + NocStorage* noc_model, + const std::vector& noc_router_tiles) { // keep track of the shortest distance between a user described router (noc description in the arch file) and a physical router on the FPGA double shortest_distance; - double curr_calculated_distance; // stores the index of a physical router within the noc_router_tiles that is closest to a given user described router int closest_physical_router; - // information regarding physical router position - double curr_physical_router_pos_x; - double curr_physical_router_pos_y; - - // information regarding logical router position - double curr_logical_router_position_x; - double curr_logical_router_position_y; - // keep track of the index of each physical router (this helps uniquely identify them) int curr_physical_router_index = 0; @@ -147,39 +144,40 @@ void create_noc_routers(const t_noc_inf& noc_info, NocStorage* noc_model, std::v int error_case_physical_router_index_2; // keep track of the router assignments (store the user router id that was assigned to each physical router tile) - // this is used in error checking, after determining the closest physical router for a user described router in the arch file, the datastructure below can be used to check if that physical router was already assigned previously + // this is used in error checking, after determining the closest physical router for a user described router in the arch file, + // the datastructure below can be used to check if that physical router was already assigned previously std::vector router_assignments; router_assignments.resize(noc_router_tiles.size(), PHYSICAL_ROUTER_NOT_ASSIGNED); // Below we create all the routers within the NoC // // go through each user described router in the arch file and assign it to a physical router on the FPGA - for (auto logical_router = noc_info.router_list.begin(); logical_router != noc_info.router_list.end(); logical_router++) { - // assign the shortest distance to a large value (this is done so that the first distance calculated and we can replace this) - shortest_distance = LLONG_MAX; - + for (const auto& logical_router : noc_info.router_list) { + // assign the shortest distance to a large value (this is done so that the first distance calculated, and we can replace this) + shortest_distance = std::numeric_limits::max(); // get position of the current logical router - curr_logical_router_position_x = logical_router->device_x_position; - curr_logical_router_position_y = logical_router->device_y_position; + double curr_logical_router_position_x = logical_router.device_x_position; + double curr_logical_router_position_y = logical_router.device_y_position; closest_physical_router = 0; // the starting index of the physical router list curr_physical_router_index = 0; - // initialze the router ids that track the error case where two physical router tiles have the same distance to a user described router - // we initialize it to a in-valid index, so that it reflects the situation where we never hit this case + // initialize the router ids that track the error case where two physical router tiles have the same distance to a user described router + // we initialize it to an invalid index, so that it reflects the situation where we never hit this case error_case_physical_router_index_1 = INVALID_PHYSICAL_ROUTER_INDEX; error_case_physical_router_index_2 = INVALID_PHYSICAL_ROUTER_INDEX; // determine the physical router tile that is closest to the current user described router in the arch file - for (auto& physical_router : noc_router_tiles) { + for (const auto& physical_router : noc_router_tiles) { // get the position of the current physical router tile on the FPGA device - curr_physical_router_pos_x = physical_router.tile_centroid_x; - curr_physical_router_pos_y = physical_router.tile_centroid_y; + double curr_physical_router_pos_x = physical_router.tile_centroid_x; + double curr_physical_router_pos_y = physical_router.tile_centroid_y; - // use euclidean distance to calculate the length between the current user described router and the physical router - curr_calculated_distance = sqrt(pow(abs(curr_physical_router_pos_x - curr_logical_router_position_x), 2.0) + pow(abs(curr_physical_router_pos_y - curr_logical_router_position_y), 2.0)); + // use Euclidean distance to calculate the length between the current user described router and the physical router + double curr_calculated_distance = std::hypot(curr_physical_router_pos_x - curr_logical_router_position_x, + curr_physical_router_pos_y - curr_logical_router_position_y); // if the current distance is the same as the previous shortest distance if (vtr::isclose(curr_calculated_distance, shortest_distance)) { @@ -187,8 +185,8 @@ void create_noc_routers(const t_noc_inf& noc_info, NocStorage* noc_model, std::v error_case_physical_router_index_1 = closest_physical_router; error_case_physical_router_index_2 = curr_physical_router_index; - } else if (curr_calculated_distance < shortest_distance) // case where the current logical router is closest to the physical router tile - { + // case where the current logical router is closest to the physical router tile + } else if (curr_calculated_distance < shortest_distance) { // update the shortest distance and then the closest router shortest_distance = curr_calculated_distance; closest_physical_router = curr_physical_router_index; @@ -202,32 +200,34 @@ void create_noc_routers(const t_noc_inf& noc_info, NocStorage* noc_model, std::v if (error_case_physical_router_index_1 == closest_physical_router) { VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Router with ID:'%d' has the same distance to physical router tiles located at position (%d,%d) and (%d,%d). Therefore, no router assignment could be made.", - logical_router->id, noc_router_tiles[error_case_physical_router_index_1].grid_width_position, noc_router_tiles[error_case_physical_router_index_1].grid_height_position, + logical_router.id, noc_router_tiles[error_case_physical_router_index_1].grid_width_position, noc_router_tiles[error_case_physical_router_index_1].grid_height_position, noc_router_tiles[error_case_physical_router_index_2].grid_width_position, noc_router_tiles[error_case_physical_router_index_2].grid_height_position); } // check if the current physical router was already assigned previously, if so then throw an error if (router_assignments[closest_physical_router] != PHYSICAL_ROUTER_NOT_ASSIGNED) { VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Routers with IDs:'%d' and '%d' are both closest to physical router tile located at (%d,%d) and the physical router could not be assigned multiple times.", - logical_router->id, router_assignments[closest_physical_router], noc_router_tiles[closest_physical_router].grid_width_position, + logical_router.id, router_assignments[closest_physical_router], noc_router_tiles[closest_physical_router].grid_width_position, noc_router_tiles[closest_physical_router].grid_height_position); } + auto it = noc_info.router_latency_overrides.find(logical_router.id); + double router_latency = (it == noc_info.router_latency_overrides.end()) ? noc_info.router_latency : it->second; + // at this point, the closest user described router to the current physical router was found // so add the router to the NoC - noc_model->add_router(logical_router->id, + noc_model->add_router(logical_router.id, noc_router_tiles[closest_physical_router].grid_width_position, noc_router_tiles[closest_physical_router].grid_height_position, - noc_router_tiles[closest_physical_router].layer_position); + noc_router_tiles[closest_physical_router].layer_position, + router_latency); // add the new assignment to the tracker - router_assignments[closest_physical_router] = logical_router->id; + router_assignments[closest_physical_router] = logical_router.id; } - - return; } -void create_noc_links(const t_noc_inf* noc_info, NocStorage* noc_model) { +void create_noc_links(const t_noc_inf& noc_info, NocStorage* noc_model) { // the ids used to represent the routers in the NoC are not the same as the ones provided by the user in the arch desc file. // while going through the router connections, the user provided router ids are converted and then stored below before being used in the links. NocRouterId source_router; @@ -237,19 +237,27 @@ void create_noc_links(const t_noc_inf* noc_info, NocStorage* noc_model) { noc_model->make_room_for_noc_router_link_list(); // go through each router and add its outgoing links to the NoC - for (const auto& router : noc_info->router_list) { + for (const auto& router : noc_info.router_list) { // get the converted id of the current source router source_router = noc_model->convert_router_id(router.id); // go through all the routers connected to the current one and add links to the noc - for (int conn_router_id : router.connection_list) { + for (const auto conn_router_id : router.connection_list) { // get the converted id of the currently connected sink router sink_router = noc_model->convert_router_id(conn_router_id); + // check if this link has an overridden latency + auto lat_it = noc_info.link_latency_overrides.find({router.id, conn_router_id}); + // use the link-specific latency if it has an overridden latency, otherwise use the NoC-wide link latency + double link_lat = (lat_it == noc_info.link_latency_overrides.end()) ? noc_info.link_latency : lat_it->second; + + // check if this link has an overridden bandwidth + auto bw_it = noc_info.link_bandwidth_overrides.find({router.id, conn_router_id}); + // use the link-specific bandwidth if it has an overridden bandwidth, otherwise use the NoC-wide link bandwidth + double link_bw = (bw_it == noc_info.link_bandwidth_overrides.end()) ? noc_info.link_bandwidth : bw_it->second; + // add the link to the Noc - noc_model->add_link(source_router, sink_router); + noc_model->add_link(source_router, sink_router, link_bw, link_lat); } } - - return; } diff --git a/vpr/src/base/setup_noc.h b/vpr/src/base/setup_noc.h index 62b3ae4d543..56434095fd7 100644 --- a/vpr/src/base/setup_noc.h +++ b/vpr/src/base/setup_noc.h @@ -16,14 +16,14 @@ * * Router Creation * --------------- - * Each router described in the archietcture file is created and + * Each router described in the architecture file is created and * added to the NoC. Since the routers represents physical tiles on * the FPGA, when the router is created, it is also assigned to a * corresponding physical router tile. * * Link Creation * ------------- - * The user describes a "connection list", which rerpesents an intended + * The user describes a "connection list", which represents an intended * connection between two routers in the NoC. Each link connects two * routers together. For each router, a number * of Links are created to connect it to another router in its "connection @@ -31,21 +31,11 @@ * */ -#include -#include +#include #include -#include "physical_types.h" #include "device_grid.h" -#include "globals.h" -#include "noc_storage.h" -#include "vpr_error.h" - -// a default condition that helps keep track of whether a physical router has been assigned to a logical router or not -#define PHYSICAL_ROUTER_NOT_ASSIGNED -1 - -// a deafult index used for initiailization purposes. No router will have a negative index -#define INVALID_PHYSICAL_ROUTER_INDEX -1 +#include "vpr_context.h" // a data structure to store the position information of a noc router in the FPGA device struct t_noc_router_tile_position { @@ -83,13 +73,14 @@ void setup_noc(const t_arch& arch); * stored in a list. * * @param device_grid The FPGA device description. - * @param list_of_noc_router_tiles Stores the grid position information - * for all NoC router tiles in the FPGA. * @param noc_router_tile_name The name used when describing the NoC router * tile in the FPGA architecture description * file. + * + * @return The grid position information for all NoC router tiles in the FPGA. */ -void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, std::vector& list_of_noc_router_tiles, const std::string& noc_router_tile_name); +std::vector identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, + std::string_view noc_router_tile_name); /** * @brief Creates NoC routers and adds them to the NoC model based @@ -104,10 +95,12 @@ void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, * @param list_of_noc_router_tiles Stores the grid position information * for all NoC router tiles in the FPGA. */ -void generate_noc(const t_arch& arch, NocContext& noc_ctx, std::vector& list_of_noc_router_tiles); +void generate_noc(const t_arch& arch, + NocContext& noc_ctx, + const std::vector& list_of_noc_router_tiles); /** - * @brief Go through the outers described by the user + * @brief Go through the routers described by the user * in the architecture description file and assigns it a corresponding * physical router tile in the FPGA. Each logical router has a grid * location, so the closest physical router to the grid location is then @@ -121,7 +114,9 @@ void generate_noc(const t_arch& arch, NocContext& noc_ctx, std::vector& list_of_noc_router_tiles); +void create_noc_routers(const t_noc_inf& noc_info, + NocStorage* noc_model, + const std::vector& list_of_noc_router_tiles); /** * @brief Goes through the topology information as described in the FPGA @@ -134,6 +129,6 @@ void create_noc_routers(const t_noc_inf& noc_info, NocStorage* noc_model, std::v * @param noc_model An internal model that describes the NoC. Contains a list of * routers and links that connect the routers together. */ -void create_noc_links(const t_noc_inf* noc_info, NocStorage* noc_model); +void create_noc_links(const t_noc_inf& noc_info, NocStorage* noc_model); #endif \ No newline at end of file diff --git a/vpr/src/draw/draw_noc.cpp b/vpr/src/draw/draw_noc.cpp index f664562f88a..e3d39ed4294 100644 --- a/vpr/src/draw/draw_noc.cpp +++ b/vpr/src/draw/draw_noc.cpp @@ -67,8 +67,6 @@ void draw_noc(ezgl::renderer* g) { draw_noc_links(g, noc_router_logical_type, noc_link_colors, noc_connection_marker_bbox, list_of_noc_link_shift_directions); draw_noc_connection_marker(g, router_list, noc_connection_marker_bbox); - - return; } /* @@ -78,55 +76,42 @@ void draw_noc_usage(vtr::vector& noc_link_colors) { t_draw_state* draw_state = get_draw_state_vars(); auto& noc_ctx = g_vpr_ctx.noc(); - // get the maximum badnwidth per link - double max_noc_link_bandwidth = noc_ctx.noc_model.get_noc_link_bandwidth(); - // check to see if a color map was already created previously if (draw_state->noc_usage_color_map == nullptr) { - // we havent created a color map yet for the noc link usage, so create it here + // we haven't created a color map yet for the noc link usage, so create it here // the color map creates a color spectrum that gradually changes from a dark to light color. Where a dark color represents low noc link usage (low bandwidth) and a light color represents high noc link usage (high bandwidth) // The color map needs a min and max value to generate the color range. // The noc usage is calculated by taking the ratio of the links current bandwidth over the maximum allowable bandwidth - // for the NoC, the min value is 0, since you cannot go lower than 0 badnwidth. + // for the NoC, the min value is 0, since you cannot go lower than 0 bandwidth. // The max value is going to be 1 and represents the case where the link is used to full capacity on the noc link (as provided by the user) draw_state->noc_usage_color_map = std::make_shared(0.0, 1.0); } - // get the list of links in the NoC - const vtr::vector& noc_link_list = noc_ctx.noc_model.get_noc_links(); - - // store each links bandwidth usage - double link_bandwidth_usage; - // represents the color to draw each noc link ezgl::color current_noc_link_color; - // now we need to determine the colors for each link - for (int link = 0; link < (int)noc_link_list.size(); link++) { - // get the current link id - NocLinkId link_id(link); + for (const auto& noc_link : noc_ctx.noc_model.get_noc_links()) { + NocLinkId link_id = noc_link.get_link_id(); - // only update the color of the link if it wasnt updated previously + // only update the color of the link if it wasn't updated previously if (noc_link_colors[link_id] == ezgl::BLACK) { // if we are here then the link was not updated previously, so assign the color here //get the current link bandwidth usage (ratio calculation) - link_bandwidth_usage = (noc_link_list[link_id].get_bandwidth_usage()) / max_noc_link_bandwidth; + double link_bandwidth_usage_ratio = (noc_link.get_bandwidth_usage()) / noc_link.get_bandwidth(); // check if the link is being overused and if it is then cap it at 1.0 - if (link_bandwidth_usage > 1.0) { - link_bandwidth_usage = 1.0; + if (link_bandwidth_usage_ratio > 1.0) { + link_bandwidth_usage_ratio = 1.0; } - // get the corresponding color that represents the link bandwidth usgae - current_noc_link_color = to_ezgl_color(draw_state->noc_usage_color_map->color(link_bandwidth_usage)); + // get the corresponding color that represents the link bandwidth usage + current_noc_link_color = to_ezgl_color(draw_state->noc_usage_color_map->color(link_bandwidth_usage_ratio)); // set the colors of the link noc_link_colors[link_id] = current_noc_link_color; } } - - return; } /* @@ -158,7 +143,7 @@ ezgl::rectangle get_noc_connection_marker_bbox(const t_logical_block_type_ptr no * We do the following to calculate the position of the marker: * 1. Get the area of the larger router tile * 2. Calculate the area of the marker (based on a predefined percentage of the area of the larger noc tile) - * 3. The marker is a square, so we can can calculate the lengths + * 3. The marker is a square, so we can calculate the lengths * of the sides of the marker * 4. Divide the side length by 2 and subtract this from the x & y coordinates of the center of the larger noc router tile. This is the bottom left corner of the rectangle. * 5. Then add the side length to the x & y coordinate of the center of the larger noc router tile. THis is the top right corner of the rectangle. @@ -188,15 +173,11 @@ void draw_noc_connection_marker(ezgl::renderer* g, const vtr::vectorget_router_layer_position(); + for (const auto & router : router_list) { + int router_grid_position_layer = router.get_router_layer_position(); t_draw_layer_display marker_box_visibility = draw_state->draw_layer_display[router_grid_position_layer]; if (!marker_box_visibility.visible) { @@ -206,8 +187,8 @@ void draw_noc_connection_marker(ezgl::renderer* g, const vtr::vectorset_color(ezgl::BLACK, marker_box_visibility.alpha); - router_grid_position_x = router->get_router_grid_position_x(); - router_grid_position_y = router->get_router_grid_position_y(); + int router_grid_position_x = router.get_router_grid_position_x(); + int router_grid_position_y = router.get_router_grid_position_y(); // get the coordinates to draw the marker given the current routers tile position updated_connection_marker_bbox = connection_marker_bbox + ezgl::point2d(draw_coords->tile_x[router_grid_position_x], draw_coords->tile_y[router_grid_position_y]); @@ -215,8 +196,6 @@ void draw_noc_connection_marker(ezgl::renderer* g, const vtr::vectorfill_rectangle(updated_connection_marker_bbox); } - - return; } /* @@ -307,8 +286,6 @@ void draw_noc_links(ezgl::renderer* g, t_logical_block_type_ptr noc_router_logic //draw a line between the center of the two routers this link connects g->draw_line(link_coords.start, link_coords.end); } - - return; } void determine_direction_to_shift_noc_links(vtr::vector& list_of_noc_link_shift_directions) { @@ -343,8 +320,6 @@ void determine_direction_to_shift_noc_links(vtr::vector list_of_noc_link_shift_directions[parallel_link] = NocLinkShift::BOTTOM_SHIFT; } } - - return; } NocLinkType determine_noc_link_type(ezgl::point2d link_start_point, ezgl::point2d link_end_point) { @@ -488,13 +463,11 @@ void shift_noc_link(noc_link_draw_coords& link_coords, NocLinkShift link_shift_d link_coords.start.y += noc_connection_marker_quarter_height; link_coords.end.y += noc_connection_marker_quarter_height; } - // dont change anything if we arent shifting at all + // don't change anything if we aren't shifting at all break; default: break; } - - return; } #endif \ No newline at end of file diff --git a/vpr/src/noc/bfs_routing.h b/vpr/src/noc/bfs_routing.h index 412569e8ad5..ca28a8ca3fd 100644 --- a/vpr/src/noc/bfs_routing.h +++ b/vpr/src/noc/bfs_routing.h @@ -42,7 +42,7 @@ class BFSRouting : public NocRouting { * Identifies the ending point of the route within the NoC.This represents a * physical router on the FPGA. * @param traffic_flow_id The unique ID for the traffic flow being routed. - * @param flow_route Stores the path returned by this fuction + * @param flow_route Stores the path returned by this function * as a series of NoC links found by * a NoC routing algorithm between two routers in a traffic flow. * The function will clear any diff --git a/vpr/src/noc/noc_link.cpp b/vpr/src/noc/noc_link.cpp index 59619418ca2..28340ff96d8 100644 --- a/vpr/src/noc/noc_link.cpp +++ b/vpr/src/noc/noc_link.cpp @@ -1,35 +1,35 @@ #include "noc_link.h" // constructor -NocLink::NocLink(NocLinkId link_id, NocRouterId source, NocRouterId sink, double bw) +NocLink::NocLink(NocLinkId link_id, NocRouterId source, NocRouterId sink, + double bw, double lat) : id(link_id) , source_router(source) , sink_router(sink) , bandwidth_usage(0.0) - , bandwidth(bw) {} + , bandwidth(bw) + , latency(lat) { } // getters -NocRouterId NocLink::get_source_router(void) const { +NocRouterId NocLink::get_source_router() const { return source_router; } -NocRouterId NocLink::get_sink_router(void) const { +NocRouterId NocLink::get_sink_router() const { return sink_router; } -double NocLink::get_bandwidth_usage(void) const { +double NocLink::get_bandwidth_usage() const { return bandwidth_usage; } //setters void NocLink::set_source_router(NocRouterId source) { source_router = source; - return; } void NocLink::set_sink_router(NocRouterId sink) { sink_router = sink; - return; } void NocLink::set_bandwidth_usage(double new_bandwidth_usage) { @@ -38,7 +38,6 @@ void NocLink::set_bandwidth_usage(double new_bandwidth_usage) { void NocLink::set_bandwidth(double new_bandwidth) { bandwidth = new_bandwidth; - return; } double NocLink::get_bandwidth() const { @@ -61,10 +60,15 @@ double NocLink::get_congested_bandwidth_ratio() const { return congested_bw_ratio; } +double NocLink::get_latency() const { + return latency; +} + NocLinkId NocLink::get_link_id() const { return id; } NocLink::operator NocLinkId() const { return get_link_id(); -} \ No newline at end of file +} + diff --git a/vpr/src/noc/noc_link.h b/vpr/src/noc/noc_link.h index 8f940d269c2..38d8cec42de 100644 --- a/vpr/src/noc/noc_link.h +++ b/vpr/src/noc/noc_link.h @@ -50,10 +50,12 @@ class NocLink { NocRouterId sink_router; /*!< The router which uses this link as an incoming edge*/ double bandwidth_usage; /*!< Represents the bandwidth of the data being transmitted on the link. Units in bits-per-second(bps)*/ - double bandwidth; /*!< Represents the maximum bits per second that can be transmitted over the link without causing congestion*/ + double bandwidth; /*!< Represents the maximum bits per second that can be transmitted over the link without causing congestion*/ + double latency; /*!< The zero-load latency of this link in seconds.*/ public: - NocLink(NocLinkId link_id, NocRouterId source_router, NocRouterId sink_router, double bw); + NocLink(NocLinkId link_id, NocRouterId source_router, NocRouterId sink_router, + double bw, double lat); // getters @@ -62,33 +64,33 @@ class NocLink { * edge * @return A unique id (NocRouterId) that identifies the source router of the link */ - NocRouterId get_source_router(void) const; + NocRouterId get_source_router() const; /** * @brief Provides the id of the router that has this link as an incoming * edge * @return A unique id (NocRouterId) that identifies the sink router of the link */ - NocRouterId get_sink_router(void) const; + NocRouterId get_sink_router() const; /** * @brief Provides the size of the data (bandwidth) being currently transmitted using the link. * @return A numeric value of the bandwidth usage of the link */ - double get_bandwidth_usage(void) const; + double get_bandwidth_usage() const; /** * @brief Returns the maximum bandwidth that the link can carry without congestion. * @return A numeric value of the bandwidth capacity of the link */ - double get_bandwidth(void) const; + double get_bandwidth() const; /** * @brief Calculates the extent to which the current bandwidth utilization * exceeds the link capacity. Any positive value means the link is congested. * @return A numeric value of the bandwidth over-utilization in the link */ - double get_congested_bandwidth(void) const; + double get_congested_bandwidth() const; /** * @brief Computes the congested bandwidth to bandwidth capacity ratio. @@ -96,6 +98,12 @@ class NocLink { */ double get_congested_bandwidth_ratio() const; + /** + * @brief Returns the zero-load latency of the link. + * @return double Zero-load latency of the link. + */ + double get_latency() const; + /** * @brief Returns the unique link ID. The ID can be used to index * vtr::vector instances. diff --git a/vpr/src/noc/noc_router.cpp b/vpr/src/noc/noc_router.cpp index b0aa166aac5..ab4bb4ea42a 100644 --- a/vpr/src/noc/noc_router.cpp +++ b/vpr/src/noc/noc_router.cpp @@ -1,33 +1,36 @@ #include "noc_router.h" // constructor -NocRouter::NocRouter(int id, int grid_position_x, int grid_position_y, int layer_position) +NocRouter::NocRouter(int id, + int grid_position_x, int grid_position_y, int layer_position, + double latency) : router_user_id(id) , router_grid_position_x(grid_position_x) , router_grid_position_y(grid_position_y) - , router_layer_position(layer_position) { + , router_layer_position(layer_position) + , router_latency(latency){ // initialize variables router_block_ref = ClusterBlockId(0); } // getters -int NocRouter::get_router_user_id(void) const { +int NocRouter::get_router_user_id() const { return router_user_id; } -int NocRouter::get_router_grid_position_x(void) const { +int NocRouter::get_router_grid_position_x() const { return router_grid_position_x; } -int NocRouter::get_router_grid_position_y(void) const { +int NocRouter::get_router_grid_position_y() const { return router_grid_position_y; } -int NocRouter::get_router_layer_position(void) const { +int NocRouter::get_router_layer_position() const { return router_layer_position; } -t_physical_tile_loc NocRouter::get_router_physical_location(void) const { +t_physical_tile_loc NocRouter::get_router_physical_location() const { const int x = get_router_grid_position_x(); const int y = get_router_grid_position_y(); const int layer = get_router_layer_position(); @@ -36,12 +39,15 @@ t_physical_tile_loc NocRouter::get_router_physical_location(void) const { return phy_loc; } -ClusterBlockId NocRouter::get_router_block_ref(void) const { +double NocRouter::get_latency() const { + return router_latency; +} + +ClusterBlockId NocRouter::get_router_block_ref() const { return router_block_ref; } // setters void NocRouter::set_router_block_ref(ClusterBlockId router_block_ref_id) { router_block_ref = router_block_ref_id; - return; } \ No newline at end of file diff --git a/vpr/src/noc/noc_router.h b/vpr/src/noc/noc_router.h index 0feb397bdd2..968ff5206b7 100644 --- a/vpr/src/noc/noc_router.h +++ b/vpr/src/noc/noc_router.h @@ -53,12 +53,17 @@ class NocRouter { * that the physical router is located*/ int router_layer_position; + /** The zero-load latency of this NoC router. */ + double router_latency; + /** A unique identifier that represents a router block in the * clustered netlist that is placed on the physical router*/ ClusterBlockId router_block_ref; public: - NocRouter(int id, int grid_position_x, int grid_position_y, int layer_position); + NocRouter(int id, + int grid_position_x, int grid_position_y, int layer_position, + double latency); // getters @@ -66,37 +71,43 @@ class NocRouter { * @brief Gets the unique id assigned by the user for the physical router * @return A numerical value (integer) that represents the physical router id */ - int get_router_user_id(void) const; + int get_router_user_id() const; /** * @brief Gets the horizontal position on the FPGA device that the physical router is located * @return A numerical value (integer) that represents horizontal position of the physical router */ - int get_router_grid_position_x(void) const; + int get_router_grid_position_x() const; /** * @brief Gets the vertical position on the FPGA device that the physical router is located * @return A numerical value (integer) that represents vertical position of the physical router */ - int get_router_grid_position_y(void) const; + int get_router_grid_position_y() const; /** * @brief Gets the layer number of the die the the physical router is located * @return A numerical value (integer) that represents layer position of the physical router */ - int get_router_layer_position(void) const; + int get_router_layer_position() const; /** * @brief Gets the physical location where the the physical router is located * @return t_physical_tile_loc that contains x-y coordinates and the layer number */ - t_physical_tile_loc get_router_physical_location(void) const; + t_physical_tile_loc get_router_physical_location() const; + + /** + * @brief Gets the zero-load latency of this NoC router. + * @return The zero-load latency in seconds. + */ + double get_latency() const; /** * @brief Gets the unique id of the router block that is current placed on the physical router * @return A ClusterBlockId that identifies a router block in the clustered netlist */ - ClusterBlockId get_router_block_ref(void) const; + ClusterBlockId get_router_block_ref() const; // setters /** diff --git a/vpr/src/noc/noc_storage.cpp b/vpr/src/noc/noc_storage.cpp index f4b0c1827ed..2f4f1ac7a45 100644 --- a/vpr/src/noc/noc_storage.cpp +++ b/vpr/src/noc/noc_storage.cpp @@ -11,7 +11,7 @@ const std::vector& NocStorage::get_noc_router_connections(NocRouterId return router_link_list[id]; } -const vtr::vector& NocStorage::get_noc_routers(void) const { +const vtr::vector& NocStorage::get_noc_routers() const { return router_storage; } @@ -19,30 +19,34 @@ int NocStorage::get_number_of_noc_routers(void) const { return router_storage.size(); } -const vtr::vector& NocStorage::get_noc_links(void) const { +const vtr::vector& NocStorage::get_noc_links() const { return link_storage; } -vtr::vector& NocStorage::get_mutable_noc_links(void) { +vtr::vector& NocStorage::get_mutable_noc_links() { return link_storage; } -int NocStorage::get_number_of_noc_links(void) const { +int NocStorage::get_number_of_noc_links() const { return link_storage.size(); } -double NocStorage::get_noc_link_bandwidth(void) const { - return noc_link_bandwidth; -} - -double NocStorage::get_noc_link_latency(void) const { +double NocStorage::get_noc_link_latency() const { return noc_link_latency; } -double NocStorage::get_noc_router_latency(void) const { +double NocStorage::get_noc_router_latency() const { return noc_router_latency; } +bool NocStorage::get_detailed_router_latency() const { + return detailed_router_latency_; +} + +bool NocStorage::get_detailed_link_latency() const { + return detailed_link_latency_; +} + const NocRouter& NocStorage::get_single_noc_router(NocRouterId id) const { return router_storage[id]; } @@ -52,7 +56,7 @@ NocRouter& NocStorage::get_single_mutable_noc_router(NocRouterId id) { } // get link properties -const NocLink& NocStorage::get_single_noc_link(NocLinkId id) const { + const NocLink& NocStorage::get_single_noc_link(NocLinkId id) const { return link_storage[id]; } @@ -89,10 +93,12 @@ NocRouterId NocStorage::get_router_at_grid_location(const t_pl_loc& hard_router_ // setters for the NoC -void NocStorage::add_router(int id, int grid_position_x, int grid_posistion_y, int layer_position) { +void NocStorage::add_router(int id, + int grid_position_x, int grid_posistion_y, int layer_position, + double latency) { VTR_ASSERT_MSG(!built_noc, "NoC already built, cannot modify further."); - router_storage.emplace_back(id, grid_position_x, grid_posistion_y, layer_position); + router_storage.emplace_back(id, grid_position_x, grid_posistion_y, layer_position, latency); /* Get the corresponding NocRouterId for the newly added router and * add it to the conversion table. @@ -107,55 +113,42 @@ void NocStorage::add_router(int id, int grid_position_x, int grid_posistion_y, i // get the key to identify the current router int router_key = generate_router_key_from_grid_location(grid_position_x, grid_posistion_y, layer_position); grid_location_to_router_id.insert(std::pair(router_key, converted_id)); - - return; } -void NocStorage::add_link(NocRouterId source, NocRouterId sink) { +void NocStorage::add_link(NocRouterId source, NocRouterId sink, double bandwidth, double latency) { VTR_ASSERT_MSG(!built_noc, "NoC already built, cannot modify further."); // the new link will be added to the back of the list, // so we can use the total number of links added so far as id NocLinkId added_link_id((int)link_storage.size()); - double link_bandwidth = get_noc_link_bandwidth(); - link_storage.emplace_back(added_link_id, source, sink, link_bandwidth); + link_storage.emplace_back(added_link_id, source, sink, bandwidth, latency); router_link_list[source].push_back(added_link_id); - - return; } void NocStorage::set_noc_link_bandwidth(double link_bandwidth) { - noc_link_bandwidth = link_bandwidth; - // Iterate over all links and set their bandwidth for (auto& link : link_storage) { - link.set_bandwidth(noc_link_bandwidth); + link.set_bandwidth(link_bandwidth); } - - return; } void NocStorage::set_noc_link_latency(double link_latency) { noc_link_latency = link_latency; - return; } void NocStorage::set_noc_router_latency(double router_latency) { noc_router_latency = router_latency; - return; } void NocStorage::set_device_grid_width(int grid_width) { device_grid_width = grid_width; - return; } void NocStorage::set_device_grid_spec(int grid_width, int grid_height) { device_grid_width = grid_width; layer_num_grid_locs = grid_width * grid_height; - return; } bool NocStorage::remove_link(NocRouterId src_router_id, NocRouterId sink_router_id) { @@ -164,7 +157,7 @@ bool NocStorage::remove_link(NocRouterId src_router_id, NocRouterId sink_router_ // check if the src router for the link to remove exists (within the id ranges). Otherwise, there is no point looking for the link if ((size_t)src_router_id < router_storage.size()) { - // get all the outgoing links of the provided sourcer router + // get all the outgoing links of the provided source router std::vector* source_router_outgoing_links = &router_link_list[src_router_id]; // keeps track of the position of each outgoing link for the provided src router. When the id of the link to remove is found, this index can be used to remove it from the outgoing link vector. @@ -202,26 +195,44 @@ bool NocStorage::remove_link(NocRouterId src_router_id, NocRouterId sink_router_ return link_removed_status; } -void NocStorage::finished_building_noc(void) { +void NocStorage::finished_building_noc() { VTR_ASSERT_MSG(!built_noc, "NoC already built, cannot modify further."); built_noc = true; - return; + returnable_noc_link_const_refs_.reserve(link_storage.size()); + + /* We go through all NoC routers in the router_storage and check if there are any + * two consecutive NoC routers whose latency is different. If such two routers are + * found, we set detailed_router_latency_ to True. + * + * The values of detailed_link_latency_ and detailed_link_bandwidth_ are determined + * in a similar way. + */ + + auto router_latency_it = std::adjacent_find(router_storage.begin(), router_storage.end(), + [](const NocRouter& a, const NocRouter& b) { + return a.get_latency() != b.get_latency(); + }); + detailed_router_latency_ = (router_latency_it != router_storage.end()); + + auto link_latency_it = std::adjacent_find(link_storage.begin(), link_storage.end(), + [](const NocLink& a, const NocLink& b) { + return a.get_latency() != b.get_latency(); + }); + detailed_link_latency_ = (link_latency_it != link_storage.end()); } -void NocStorage::clear_noc(void) { +void NocStorage::clear_noc() { router_storage.clear(); link_storage.clear(); router_link_list.clear(); grid_location_to_router_id.clear(); built_noc = false; - - return; } NocRouterId NocStorage::convert_router_id(int id) const { - std::unordered_map::const_iterator result = router_id_conversion_table.find(id); + auto result = router_id_conversion_table.find(id); if (result == router_id_conversion_table.end()) { VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Cannot convert router with id:%d. The router was not found within the NoC.", id); @@ -230,7 +241,17 @@ NocRouterId NocStorage::convert_router_id(int id) const { return result->second; } -void NocStorage::make_room_for_noc_router_link_list(void) { +int NocStorage::convert_router_id(NocRouterId id) const { + for (auto [user_id, router_id] : router_id_conversion_table) { + if (router_id == id) { + return user_id; + } + } + + VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Cannot convert router with id:%d. The router was not found within the NoC.", id); +} + +void NocStorage::make_room_for_noc_router_link_list() { VTR_ASSERT_MSG(!built_noc, "NoC already built, cannot modify further."); router_link_list.resize(router_storage.size()); } @@ -274,8 +295,6 @@ void NocStorage::echo_noc(char* file_name) const { fprintf(fp, "NoC Constraints:\n"); fprintf(fp, "--------------------------------------------------------------\n"); fprintf(fp, "\n"); - fprintf(fp, "Maximum NoC Link Bandwidth: %f\n", noc_link_bandwidth); - fprintf(fp, "\n"); fprintf(fp, "NoC Link Latency: %f\n", noc_link_latency); fprintf(fp, "\n"); fprintf(fp, "NoC Router Latency: %f\n", noc_router_latency); @@ -291,21 +310,23 @@ void NocStorage::echo_noc(char* file_name) const { fprintf(fp, "Router %d:\n", router.get_router_user_id()); // if the router tile is larger than a single grid, the position represents the bottom left corner of the tile fprintf(fp, "Equivalent Physical Tile Grid Position -> (%d,%d)\n", router.get_router_grid_position_x(), router.get_router_grid_position_y()); - fprintf(fp, "Router Connections ->"); + fprintf(fp, "Router Connections (destination router id, link bandwidth, link latency) ->"); auto& router_connections = this->get_noc_router_connections(this->convert_router_id(router.get_router_user_id())); // go through the outgoing links of the current router and print the connecting router for (auto router_connection : router_connections) { - const NocRouterId connecting_router_id = get_single_noc_link(router_connection).get_sink_router(); + const auto& link = get_single_noc_link(router_connection); + const NocRouterId connecting_router_id = link.get_sink_router(); - fprintf(fp, " %d", get_single_noc_router(connecting_router_id).get_router_user_id()); + fprintf(fp, " (%d, %g, %g)", + get_single_noc_router(connecting_router_id).get_router_user_id(), + link.get_bandwidth(), + link.get_latency()); } fprintf(fp, "\n\n"); } fclose(fp); - - return; } diff --git a/vpr/src/noc/noc_storage.h b/vpr/src/noc/noc_storage.h index 022471c21b1..8e10aad4260 100644 --- a/vpr/src/noc/noc_storage.h +++ b/vpr/src/noc/noc_storage.h @@ -116,11 +116,6 @@ class NocStorage { */ bool built_noc; - /** - * @brief Represents the maximum allowed bandwidth for the links in the NoC (in bps) - */ - double noc_link_bandwidth; - /** * @brief Represents the delay expected when going through a link (in * seconds) @@ -133,6 +128,28 @@ class NocStorage { */ double noc_router_latency; + /** + * @brief When set true, specifies that some NoC routers have different + * latencies than others. When set false, all the NoC routers have the same + * latency. + */ + bool detailed_router_latency_; + + /** + * @brief When set true, specifies that some NoC links have different + * latencies than others. When set false, all the NoC link have the same + * latency. + */ + bool detailed_link_latency_; + + /** + * @brief A constant reference to this vector is returned by get_noc_links(...). + * This is used to avoid memory allocation whenever get_noc_links(...) is called. + * The vector is mutable so that get_noc_links(...), which is a const method, can + * modify it. + */ + mutable std::vector> returnable_noc_link_const_refs_; + /** * @brief Internal reference to the device grid width. This is necessary * to compute a unique key for a given grid location which we can then use @@ -176,13 +193,13 @@ class NocStorage { * * @return A vector of routers. */ - const vtr::vector& get_noc_routers(void) const; + const vtr::vector& get_noc_routers() const; /** * @return An integer representing the total number of routers within the * NoC. */ - int get_number_of_noc_routers(void) const; + int get_number_of_noc_routers() const; /** * @brief Get all the links in the NoC. The links themselves cannot @@ -191,7 +208,7 @@ class NocStorage { * * @return A vector of links. */ - const vtr::vector& get_noc_links(void) const; + const vtr::vector& get_noc_links() const; /** * @brief Get all the links in the NoC. The links themselves can @@ -200,22 +217,13 @@ class NocStorage { * * @return A vector of links. */ - vtr::vector& get_mutable_noc_links(void); + vtr::vector& get_mutable_noc_links(); /** * @return An integer representing the total number of links within the * NoC. */ - int get_number_of_noc_links(void) const; - - /** - * @brief Get the maximum allowable bandwidth for a link - * within the NoC. - * - * @return a numeric value that represents the link bandwidth in bps - */ - - double get_noc_link_bandwidth(void) const; + int get_number_of_noc_links() const; /** * @brief Get the latency of traversing through a link in @@ -223,8 +231,7 @@ class NocStorage { * * @return a numeric value that represents the link latency in seconds */ - - double get_noc_link_latency(void) const; + double get_noc_link_latency() const; /** * @brief Get the latency of traversing through a router in @@ -232,8 +239,25 @@ class NocStorage { * * @return a numeric value that represents the router latency in seconds */ + double get_noc_router_latency() const; - double get_noc_router_latency(void) const; + /** + * @return True if some NoC routers have different latencies than others. + * False if all NoC routers have the same latency. + */ + bool get_detailed_router_latency() const; + + /** + * @return True if some NoC links have different latencies than others. + * False if all NoC links have the same latency. + */ + bool get_detailed_link_latency() const; + + /** + * @return True if some NoC links have different bandwidths than others. + * False if all NoC links have the same bandwidth. + */ + bool get_detailed_link_bandwidth() const; // getters for routers @@ -269,6 +293,20 @@ class NocStorage { */ const NocLink& get_single_noc_link(NocLinkId id) const; + /** + * + * @tparam Container The type of standard library container used to carry + * NoCLinkIds. This container type must be iterable in a range-based loop. + * @tparam Ts Used to help clang infer correct template types. GCC can compile + * without this extra template argument. + * @param noc_link_ids A standard container that contains NoCLinkIds of the + * requested NoC links + * @return A const + */ + template class Container, typename... Ts> + const std::vector>& get_noc_links(const Container& noc_link_ids) const; + + /** * @brief Given source and sink router identifiers, this function * finds a link connecting these routers and returns its identifier. @@ -322,7 +360,9 @@ class NocStorage { * @param grid_position_y The vertical position on the FPGA of the physical * tile that this router represents. */ - void add_router(int id, int grid_position_x, int grid_position_y, int layer_poisition); + void add_router(int id, + int grid_position_x, int grid_position_y, int layer_position, + double latency); /** * @brief Creates a new link and adds it to the NoC. The newly created @@ -336,43 +376,35 @@ class NocStorage { * @param sink A unique identifier for the router that the new link enters * into (incoming to the router) */ - void add_link(NocRouterId source, NocRouterId sink); + void add_link(NocRouterId source, NocRouterId sink, double bandwidth, double latency); /** - * @brief Set the maximum allowable bandwidth for a link - * within the NoC. - * + * @brief Set the maximum allowable bandwidth for all links + * within the NoC */ - void set_noc_link_bandwidth(double link_bandwidth); /** * @brief Set the latency of traversing through a link in * the NoC. - * */ - void set_noc_link_latency(double link_latency); /** * @brief Set the latency of traversing through a router in * the NoC. - * */ - void set_noc_router_latency(double router_latency); /** * @brief Set the internal reference to the device * grid width. - * */ - void set_device_grid_width(int grid_width); void set_device_grid_spec(int grid_width, int grid_height); - // general utiliy functions + // general utility functions /** * @brief The link is removed from the outgoing vector of links for * the source router. The link is not removed from the vector of all @@ -400,18 +432,24 @@ class NocStorage { * NoC (routers and links cannot be added or removed). This function * should be called after building the NoC. Guarantees that * no future changes can be made. - * + * + * When the NoC building is finished, this function checks whether + * all links and routers have the same bandwidth and latency. + * If some NoC elements have different latencies or bandwidths than + * others, a flag is set to indicate that the detailed NoC model should be + * used. In the detailed model, instead of associating a single latency or + * bandwidth value with all NoC routers or links, each NoC router or link + * has its specific value. */ - void finished_building_noc(void); + void finished_building_noc(); /** * @brief Resets the NoC by clearing all internal datastructures. * This includes deleting all routers and links. Also all internal * IDs are removed (the is conversion table is cleared). It is * recommended to run this function before building the NoC. - * */ - void clear_noc(void); + void clear_noc(); /** * @brief Given a user id of a router, this function converts @@ -423,6 +461,13 @@ class NocStorage { */ NocRouterId convert_router_id(int id) const; + /** + * @brief Converts a NoCRouterID to the user router id. + * @param id The internal NoCRouterId + * @return The user provided router id; + */ + int convert_router_id(NocRouterId id) const; + /** * @brief The datastructure that stores the outgoing links to each * router is an 2-D Vector. When processing the links, they can be @@ -432,7 +477,7 @@ class NocStorage { * number of routers in the NoC. * */ - void make_room_for_noc_router_link_list(void); + void make_room_for_noc_router_link_list(); /** * @brief Two links are considered parallel when the source router of one @@ -470,10 +515,10 @@ class NocStorage { * @param grid_position_x The horizontal position on the FPGA of the physical * tile that this router represents. * - * @param grid_position_y The vertical position on the FPGA of the phyical + * @param grid_position_y The vertical position on the FPGA of the physical * tile that this router represents. * - * @param layer_position The layer number of the phyical + * @param layer_position The layer number of the physical * tile that this router represents. * * @return int Represents a unique key that can be used to identify a @@ -491,4 +536,18 @@ class NocStorage { void echo_noc(char* file_name) const; }; -#endif \ No newline at end of file + +template class Container, typename... Ts> +const std::vector>& NocStorage::get_noc_links(const Container& noc_link_ids) const { + returnable_noc_link_const_refs_.clear(); + + std::transform(noc_link_ids.begin(), noc_link_ids.end(), std::back_inserter(returnable_noc_link_const_refs_), + [this](const NocLinkId lid) { + return std::reference_wrapper(this->get_single_noc_link(lid)); + }); + + return returnable_noc_link_const_refs_; +} + +#endif + diff --git a/vpr/src/place/noc_place_utils.cpp b/vpr/src/place/noc_place_utils.cpp index 9c763c37b8f..f2c6be0fb8b 100644 --- a/vpr/src/place/noc_place_utils.cpp +++ b/vpr/src/place/noc_place_utils.cpp @@ -147,10 +147,7 @@ void find_affected_noc_routers_and_update_noc_costs(const t_pl_blocks_to_be_move } // Iterate over all affected links and calculate their new congestion cost and store it - for (const auto& link_id : affected_noc_links) { - // get the affected link - const auto& link = noc_ctx.noc_model.get_single_noc_link(link_id); - + for (const NocLink& link : noc_ctx.noc_model.get_noc_links(affected_noc_links)) { // calculate the new congestion cost for the link and store it proposed_link_congestion_costs[link] = calculate_link_congestion_cost(link); @@ -175,10 +172,7 @@ void commit_noc_costs() { } // Iterate over all the NoC links whose bandwidth utilization was affected by the proposed move - for (auto link_id : affected_noc_links) { - // get the affected link - const auto& link = noc_ctx.noc_model.get_single_noc_link(link_id); - + for (const NocLink& link : noc_ctx.noc_model.get_noc_links(affected_noc_links)) { // commit the new link congestion cost link_congestion_costs[link] = proposed_link_congestion_costs[link]; @@ -553,19 +547,47 @@ double calculate_traffic_flow_aggregate_bandwidth_cost(const std::vector calculate_traffic_flow_latency_cost(const std::vector& traffic_flow_route, const NocStorage& noc_model, const t_noc_traffic_flow& traffic_flow_info) { - // there will always be one more router than links in a traffic flow - int num_of_links_in_traffic_flow = traffic_flow_route.size(); - int num_of_routers_in_traffic_flow = num_of_links_in_traffic_flow + 1; - double max_latency = traffic_flow_info.max_traffic_flow_latency; - // latencies of the noc - double noc_link_latency = noc_model.get_noc_link_latency(); - double noc_router_latency = noc_model.get_noc_router_latency(); + double noc_link_latency_component = 0.0; + if (noc_model.get_detailed_link_latency()) { + for (const NocLink& link : noc_model.get_noc_links(traffic_flow_route)) { + double link_latency = link.get_latency(); + noc_link_latency_component += link_latency; + } + } else { + auto num_of_links_in_traffic_flow = (double)traffic_flow_route.size(); + double noc_link_latency = noc_model.get_noc_link_latency(); + noc_link_latency_component = noc_link_latency * num_of_links_in_traffic_flow; + } + + double noc_router_latency_component = 0.0; - // calculate the traffic flow latency - double latency = (noc_link_latency * num_of_links_in_traffic_flow) + (noc_router_latency * num_of_routers_in_traffic_flow); + if (noc_model.get_detailed_router_latency()) { + NocLinkId first_noc_link_id = traffic_flow_route[0]; + const NocLink& first_noc_link = noc_model.get_single_noc_link(first_noc_link_id); + NocRouterId source_noc_router_id = first_noc_link.get_source_router(); + const NocRouter& source_noc_router = noc_model.get_single_noc_router(source_noc_router_id); + noc_router_latency_component = source_noc_router.get_latency(); + + for (const NocLink& link : noc_model.get_noc_links(traffic_flow_route)) { + const NocRouterId sink_router_id = link.get_sink_router(); + const NocRouter& sink_router = noc_model.get_single_noc_router(sink_router_id); + double noc_router_latency = sink_router.get_latency(); + noc_router_latency_component += noc_router_latency; + } + } else { + // there will always be one more router than links in a traffic flow + auto num_of_routers_in_traffic_flow = (double)traffic_flow_route.size() + 1; + double noc_router_latency = noc_model.get_noc_router_latency(); + noc_router_latency_component = noc_router_latency * num_of_routers_in_traffic_flow; + } + + + // calculate the total traffic flow latency + double latency = noc_router_latency_component + noc_link_latency_component; // calculate the traffic flow latency overrun + double max_latency = traffic_flow_info.max_traffic_flow_latency; double latency_overrun = std::max(latency - max_latency, 0.); // scale the latency cost by its priority to indicate its importance diff --git a/vpr/src/place/noc_place_utils.h b/vpr/src/place/noc_place_utils.h index 7a0c3f565d2..0563a22f7bf 100644 --- a/vpr/src/place/noc_place_utils.h +++ b/vpr/src/place/noc_place_utils.h @@ -173,7 +173,10 @@ std::vector& route_traffic_flow(NocTrafficFlowId traffic_flow_id, * @param traffic_flow_bandwidth The bandwidth of a traffic flow. This will * be used to update bandwidth usage of the links. */ -void update_traffic_flow_link_usage(const std::vector& traffic_flow_route, NocStorage& noc_model, int inc_or_dec, double traffic_flow_bandwidth); +void update_traffic_flow_link_usage(const std::vector& traffic_flow_route, + NocStorage& noc_model, + int inc_or_dec, + double traffic_flow_bandwidth); /** * @brief Goes through all the traffic flows associated to a moved @@ -356,7 +359,8 @@ int check_noc_placement_costs(const t_placer_costs& costs, double error_toleranc * its priority. * @return The computed aggregate bandwidth for the provided traffic flow */ -double calculate_traffic_flow_aggregate_bandwidth_cost(const std::vector& traffic_flow_route, const t_noc_traffic_flow& traffic_flow_info); +double calculate_traffic_flow_aggregate_bandwidth_cost(const std::vector& traffic_flow_route, + const t_noc_traffic_flow& traffic_flow_info); /** * @brief Determines the latency cost of a routed traffic flow. diff --git a/vpr/test/test_bfs_routing.cpp b/vpr/test/test_bfs_routing.cpp index 92afda2798c..c9e527d7772 100644 --- a/vpr/test/test_bfs_routing.cpp +++ b/vpr/test/test_bfs_routing.cpp @@ -5,6 +5,9 @@ namespace { +constexpr double DUMMY_LATENCY = 1e-9; +constexpr double DUMMY_BANDWIDTH = 1e12; + TEST_CASE("test_route_flow", "[vpr_noc_bfs_routing]") { /* * Creating a test FPGA device below. The NoC itself will be @@ -29,7 +32,7 @@ TEST_CASE("test_route_flow", "[vpr_noc_bfs_routing]") { // add all the routers for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { - noc_model.add_router((i * 4) + j, j, i, 0); + noc_model.add_router((i * 4) + j, j, i, 0, DUMMY_LATENCY); } } @@ -40,19 +43,19 @@ TEST_CASE("test_route_flow", "[vpr_noc_bfs_routing]") { for (int j = 0; j < 4; j++) { // add a link to the left of the router if there exists another router there if ((j - 1) >= 0) { - noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) - 1)); + noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) - 1), DUMMY_BANDWIDTH, DUMMY_LATENCY); } // add a link to the top of the router if there exists another router there if ((i + 1) <= 3) { - noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) + 4)); + noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) + 4), DUMMY_BANDWIDTH, DUMMY_LATENCY); } // add a link to the right of the router if there exists another router there if ((j + 1) <= 3) { - noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) + 1)); + noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) + 1), DUMMY_BANDWIDTH, DUMMY_LATENCY); } // add a link to the bottom of the router if there exists another router there if ((i - 1) >= 0) { - noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) - 4)); + noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) - 4), DUMMY_BANDWIDTH, DUMMY_LATENCY); } } } @@ -97,12 +100,12 @@ TEST_CASE("test_route_flow", "[vpr_noc_bfs_routing]") { int number_of_links = noc_model.get_noc_links().size(); // add the diagonal links and also add them to the golden path - noc_model.add_link(NocRouterId(12), NocRouterId(9)); - golden_path.push_back(NocLinkId(number_of_links++)); - noc_model.add_link(NocRouterId(9), NocRouterId(6)); - golden_path.push_back(NocLinkId(number_of_links++)); - noc_model.add_link(NocRouterId(6), NocRouterId(3)); - golden_path.push_back(NocLinkId(number_of_links++)); + noc_model.add_link(NocRouterId(12), NocRouterId(9), DUMMY_BANDWIDTH, DUMMY_LATENCY); + golden_path.emplace_back(number_of_links++); + noc_model.add_link(NocRouterId(9), NocRouterId(6), DUMMY_BANDWIDTH, DUMMY_LATENCY); + golden_path.emplace_back(number_of_links++); + noc_model.add_link(NocRouterId(6), NocRouterId(3), DUMMY_BANDWIDTH, DUMMY_LATENCY); + golden_path.emplace_back(number_of_links++); // now run the routinjg algorithm // make sure that a legal route was found (no error should be thrown) diff --git a/vpr/test/test_noc_place_utils.cpp b/vpr/test/test_noc_place_utils.cpp index 5475205d933..81cc83bcf56 100644 --- a/vpr/test/test_noc_place_utils.cpp +++ b/vpr/test/test_noc_place_utils.cpp @@ -43,7 +43,11 @@ TEST_CASE("test_initial_noc_placement", "[noc_place_utils]") { // dist_2 is used to generate traffic flow bandwidths. // Setting the NoC link bandwidth to max() / 5 makes link congestion more likely to happen const double noc_link_bandwidth = dist_2.max() / 5; + constexpr double noc_link_latency = 1.0; + constexpr double noc_router_latency = 1.0; noc_ctx.noc_model.set_noc_link_bandwidth(noc_link_bandwidth); + noc_ctx.noc_model.set_noc_link_latency(noc_link_latency); + noc_ctx.noc_model.set_noc_router_latency(noc_router_latency); // individual router parameters int curr_router_id; @@ -66,7 +70,8 @@ TEST_CASE("test_initial_noc_placement", "[noc_place_utils]") { noc_ctx.noc_model.add_router(curr_router_id, router_grid_position_x, router_grid_position_y, - 0); + 0, + noc_router_latency); } noc_ctx.noc_model.make_room_for_noc_router_link_list(); @@ -76,19 +81,19 @@ TEST_CASE("test_initial_noc_placement", "[noc_place_utils]") { for (int j = 0; j < MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST; j++) { // add a link to the left of the router if there exists another router there if ((j - 1) >= 0) { - noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) - 1)); + noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) - 1), noc_link_bandwidth, noc_router_latency); } // add a link to the top of the router if there exists another router there if ((i + 1) <= MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST - 1) { - noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) + MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST)); + noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) + MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST), noc_link_bandwidth, noc_router_latency); } // add a link to the right of the router if there exists another router there if ((j + 1) <= MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST - 1) { - noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) + 1)); + noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) + 1), noc_link_bandwidth, noc_router_latency); } // add a link to the bottom of the router if there exists another router there if ((i - 1) >= 0) { - noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) - MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST)); + noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) - MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST), noc_link_bandwidth, noc_router_latency); } } } @@ -235,7 +240,11 @@ TEST_CASE("test_initial_comp_cost_functions", "[noc_place_utils]") { // dist_2 is used to generate traffic flow bandwidths. // Setting the NoC link bandwidth to max() / 5 makes link congestion more likely to happen const double noc_link_bandwidth = dist_2.max() / 5; + constexpr double noc_link_latency = 1.0; + constexpr double noc_router_latency = 1.0; noc_ctx.noc_model.set_noc_link_bandwidth(noc_link_bandwidth); + noc_ctx.noc_model.set_noc_link_latency(noc_link_latency); + noc_ctx.noc_model.set_noc_router_latency(noc_router_latency); // individual router parameters int curr_router_id; @@ -258,7 +267,8 @@ TEST_CASE("test_initial_comp_cost_functions", "[noc_place_utils]") { noc_ctx.noc_model.add_router(curr_router_id, router_grid_position_x, router_grid_position_y, - 0); + 0, + noc_router_latency); } noc_ctx.noc_model.make_room_for_noc_router_link_list(); @@ -268,19 +278,19 @@ TEST_CASE("test_initial_comp_cost_functions", "[noc_place_utils]") { for (int j = 0; j < MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST; j++) { // add a link to the left of the router if there exists another router there if ((j - 1) >= 0) { - noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) - 1)); + noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) - 1), noc_link_bandwidth, noc_link_latency); } // add a link to the top of the router if there exists another router there if ((i + 1) <= MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST - 1) { - noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) + MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST)); + noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) + MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST), noc_link_bandwidth, noc_link_latency); } // add a link to the right of the router if there exists another router there if ((j + 1) <= MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST - 1) { - noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) + 1)); + noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) + 1), noc_link_bandwidth, noc_link_latency); } // add a link to the bottom of the router if there exists another router there if ((i - 1) >= 0) { - noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) - MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST)); + noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) - MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST), noc_link_bandwidth, noc_link_latency); } } } @@ -512,15 +522,16 @@ TEST_CASE("test_find_affected_noc_routers_and_update_noc_costs, test_commit_noc_ noc_opts.noc_latency_weighting = dist_3(double_engine); noc_opts.noc_congestion_weighting = dist_3(double_engine); + constexpr double link_bandwidth = 1.0; + // setting the NoC parameters noc_ctx.noc_model.set_noc_link_latency(1); noc_ctx.noc_model.set_noc_router_latency(1); - noc_ctx.noc_model.set_noc_link_bandwidth(1); + noc_ctx.noc_model.set_noc_link_bandwidth(link_bandwidth); // needs to be the same as above - double router_latency = noc_ctx.noc_model.get_noc_router_latency(); - double link_latency = noc_ctx.noc_model.get_noc_link_latency(); - double link_bandwidth = noc_ctx.noc_model.get_noc_link_bandwidth(); + const double router_latency = noc_ctx.noc_model.get_noc_router_latency(); + const double link_latency = noc_ctx.noc_model.get_noc_link_latency(); // keeps track of which hard router each cluster block is placed vtr::vector router_where_cluster_is_placed; @@ -537,7 +548,8 @@ TEST_CASE("test_find_affected_noc_routers_and_update_noc_costs, test_commit_noc_ noc_ctx.noc_model.add_router(curr_router_id, router_grid_position_x, router_grid_position_y, - 0); + 0, + router_latency); } noc_ctx.noc_model.make_room_for_noc_router_link_list(); @@ -547,19 +559,19 @@ TEST_CASE("test_find_affected_noc_routers_and_update_noc_costs, test_commit_noc_ for (int j = 0; j < MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST; j++) { // add a link to the left of the router if there exists another router there if ((j - 1) >= 0) { - noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) - 1)); + noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) - 1), link_bandwidth, link_latency); } // add a link to the top of the router if there exists another router there if ((i + 1) <= MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST - 1) { - noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) + MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST)); + noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) + MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST), link_bandwidth, link_latency); } // add a link to the right of the router if there exists another router there if ((j + 1) <= MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST - 1) { - noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) + 1)); + noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) + 1), link_bandwidth, link_latency); } // add a link to the bottom of the router if there exists another router there if ((i - 1) >= 0) { - noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) - MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST)); + noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) - MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST), link_bandwidth, link_latency); } } } @@ -1387,10 +1399,14 @@ TEST_CASE("test_revert_noc_traffic_flow_routes", "[noc_place_utils]") { noc_opts.noc_latency_weighting = dist_3(double_engine); noc_opts.noc_congestion_weighting = dist_3(double_engine); + constexpr double LINK_LATENCY = 1; + constexpr double LINK_BANDWIDTH = 1; + constexpr double ROUTER_LATENCY = 1; + // setting the NoC parameters - noc_ctx.noc_model.set_noc_link_latency(1); - noc_ctx.noc_model.set_noc_router_latency(1); - noc_ctx.noc_model.set_noc_link_bandwidth(1); + noc_ctx.noc_model.set_noc_link_latency(LINK_BANDWIDTH); + noc_ctx.noc_model.set_noc_router_latency(ROUTER_LATENCY); + noc_ctx.noc_model.set_noc_link_bandwidth(LINK_BANDWIDTH); // keeps track of which hard router each cluster block is placed vtr::vector router_where_cluster_is_placed; @@ -1407,7 +1423,8 @@ TEST_CASE("test_revert_noc_traffic_flow_routes", "[noc_place_utils]") { noc_ctx.noc_model.add_router(curr_router_id, router_grid_position_x, router_grid_position_y, - 0); + 0, + ROUTER_LATENCY); } noc_ctx.noc_model.make_room_for_noc_router_link_list(); @@ -1417,19 +1434,19 @@ TEST_CASE("test_revert_noc_traffic_flow_routes", "[noc_place_utils]") { for (int j = 0; j < MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST; j++) { // add a link to the left of the router if there exists another router there if ((j - 1) >= 0) { - noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) - 1)); + noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) - 1), LINK_BANDWIDTH, LINK_LATENCY); } // add a link to the top of the router if there exists another router there if ((i + 1) <= MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST - 1) { - noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) + MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST)); + noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) + MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST), LINK_BANDWIDTH, LINK_LATENCY); } // add a link to the right of the router if there exists another router there if ((j + 1) <= MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST - 1) { - noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) + 1)); + noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) + 1), LINK_BANDWIDTH, LINK_LATENCY); } // add a link to the bottom of the router if there exists another router there if ((i - 1) >= 0) { - noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) - MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST)); + noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) - MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST), LINK_BANDWIDTH, LINK_LATENCY); } } } @@ -1757,7 +1774,8 @@ TEST_CASE("test_check_noc_placement_costs", "[noc_place_utils]") { noc_ctx.noc_model.add_router(curr_router_id, router_grid_position_x, router_grid_position_y, - 0); + 0, + router_latency); } noc_ctx.noc_model.make_room_for_noc_router_link_list(); @@ -1767,19 +1785,19 @@ TEST_CASE("test_check_noc_placement_costs", "[noc_place_utils]") { for (int j = 0; j < MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST; j++) { // add a link to the left of the router if there exists another router there if ((j - 1) >= 0) { - noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) - 1)); + noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) - 1), link_bandwidth, link_latency); } // add a link to the top of the router if there exists another router there if ((i + 1) <= MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST - 1) { - noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) + MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST)); + noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) + MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST), link_bandwidth, link_latency); } // add a link to the right of the router if there exists another router there if ((j + 1) <= MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST - 1) { - noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) + 1)); + noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) + 1), link_bandwidth, link_latency); } // add a link to the bottom of the router if there exists another router there if ((i - 1) >= 0) { - noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) - MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST)); + noc_ctx.noc_model.add_link((NocRouterId)((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j), (NocRouterId)(((i * MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST) + j) - MESH_TOPOLOGY_SIZE_NOC_PLACE_UTILS_TEST), link_bandwidth, link_latency); } } } diff --git a/vpr/test/test_noc_storage.cpp b/vpr/test/test_noc_storage.cpp index 834d81b88a6..0578c438dac 100644 --- a/vpr/test/test_noc_storage.cpp +++ b/vpr/test/test_noc_storage.cpp @@ -13,6 +13,9 @@ namespace { +constexpr double DUMMY_LATENCY = 1e-9; +constexpr double DUMMY_BANDWIDTH = 1e12; + TEST_CASE("test_adding_routers_to_noc_storage", "[vpr_noc]") { // setup random number generation std::random_device device; @@ -44,10 +47,10 @@ TEST_CASE("test_adding_routers_to_noc_storage", "[vpr_noc]") { router_grid_position_y = router_number + dist(rand_num_gen); // add router to the golden vector - golden_set.emplace_back(router_number, router_grid_position_x, router_grid_position_y, 0); + golden_set.emplace_back(router_number, router_grid_position_x, router_grid_position_y, 0, DUMMY_LATENCY); // add tje router to the noc - test_noc.add_router(curr_router_id, router_grid_position_x, router_grid_position_y, 0); + test_noc.add_router(curr_router_id, router_grid_position_x, router_grid_position_y, 0, DUMMY_LATENCY); } // now verify that the routers were added properly by reading the routers back from the noc and comparing them to the golden set @@ -96,10 +99,10 @@ TEST_CASE("test_router_id_conversion", "[vpr_noc]") { router_grid_position_y = router_number + dist(rand_num_gen); // add router to the golden vector - golden_set.emplace_back(router_number, router_grid_position_x, router_grid_position_y, 0); + golden_set.emplace_back(router_number, router_grid_position_x, router_grid_position_y, 0, DUMMY_LATENCY); // add tje router to the noc - test_noc.add_router(curr_router_id, router_grid_position_x, router_grid_position_y, 0); + test_noc.add_router(curr_router_id, router_grid_position_x, router_grid_position_y, 0, DUMMY_LATENCY); } // now verify that the routers were added properly by reading the routers back from the noc and comparing them to the golden set @@ -150,7 +153,8 @@ TEST_CASE("test_add_link", "[vpr_noc]") { test_noc.add_router(router_id, curr_router_x_pos, curr_router_y_pos, - 0); + 0, + DUMMY_LATENCY); } // allocate the size for outgoing link vector for each router @@ -171,10 +175,10 @@ TEST_CASE("test_add_link", "[vpr_noc]") { noc_link_id_counter++; // add link to the golden reference - golden_set.emplace_back(link_id, source, sink, 0.0); + golden_set.emplace_back(link_id, source, sink, DUMMY_BANDWIDTH, DUMMY_LATENCY); // add the link to the NoC - test_noc.add_link(source, sink); + test_noc.add_link(source, sink, DUMMY_BANDWIDTH, DUMMY_LATENCY); total_num_of_links++; } @@ -235,7 +239,7 @@ TEST_CASE("test_router_link_list", "[vpr_noc]") { router_id = router_number; // add tje router to the noc - test_noc.add_router(router_id, curr_router_x_pos, curr_router_y_pos, 0); + test_noc.add_router(router_id, curr_router_x_pos, curr_router_y_pos, 0, DUMMY_LATENCY); } // allocate the size for outgoing link vector for each router @@ -250,7 +254,7 @@ TEST_CASE("test_router_link_list", "[vpr_noc]") { // makes sure we do not create a link for a router who acts as a sink and source if (source_router_id != sink_router_id) { // add the link to the NoC - test_noc.add_link(source, sink); + test_noc.add_link(source, sink, DUMMY_BANDWIDTH, DUMMY_LATENCY); // add the link id to the golden set golden_set[source].push_back((NocLinkId)curr_link_number); @@ -312,7 +316,8 @@ TEST_CASE("test_remove_link", "[vpr_noc]") { test_noc.add_router(router_id, curr_router_x_pos, curr_router_y_pos, - 0); + 0, + DUMMY_LATENCY); } // now go through and add the links to the NoC @@ -329,7 +334,7 @@ TEST_CASE("test_remove_link", "[vpr_noc]") { // makes sure we do not create a link for a router who acts as a sink and source if (source_router_id != sink_router_id) { // add the link to the NoC - test_noc.add_link(source, sink); + test_noc.add_link(source, sink, DUMMY_BANDWIDTH, DUMMY_LATENCY); } } } @@ -431,7 +436,8 @@ TEST_CASE("test_generate_router_key_from_grid_location", "[vpr_noc]") { test_noc.add_router(curr_router_id, router_grid_position_x, router_grid_position_y, - 0); + 0, + DUMMY_LATENCY); } // now verify the test function by identifying all the routers using their grid locations diff --git a/vpr/test/test_setup_noc.cpp b/vpr/test/test_setup_noc.cpp index b88949b11f3..0d36fa2af93 100644 --- a/vpr/test/test_setup_noc.cpp +++ b/vpr/test/test_setup_noc.cpp @@ -38,14 +38,11 @@ TEST_CASE("test_identify_and_store_noc_router_tile_positions", "[vpr_setup_noc]" router_tile.height = 2; router_tile.width = 2; - // name of the router physical tile - //std::string router_tile_name_string("router"); - // results from the test function std::vector list_of_routers; // make sure the test result is not corrupted - REQUIRE(list_of_routers.size() == 0); + REQUIRE(list_of_routers.empty()); SECTION("All routers are seperated by one or more grid spaces") { // in this test, the routers will be on the 4 corners of the FPGA @@ -120,7 +117,7 @@ TEST_CASE("test_identify_and_store_noc_router_tile_positions", "[vpr_setup_noc]" for (int i = 0; i < test_grid_width; i++) { for (int j = 0; j < test_grid_height; j++) { - // make sure the current tyle is not a router + // make sure the current tile is not a router if (test_grid[0][i][j].type == nullptr) { // assign the non-router tile as empty test_grid[0][i][j].type = &empty_tile; @@ -134,9 +131,9 @@ TEST_CASE("test_identify_and_store_noc_router_tile_positions", "[vpr_setup_noc]" DeviceGrid test_device = DeviceGrid(device_grid_name, test_grid); // call the test function - identify_and_store_noc_router_tile_positions(test_device, list_of_routers, std::string(router_tile_name)); + list_of_routers = identify_and_store_noc_router_tile_positions(test_device, router_tile_name); - // check that the physocal router tile positions were correctly determined + // check that the physical router tile positions were correctly determined // make sure that only 4 router tiles were found REQUIRE(list_of_routers.size() == 4); @@ -251,9 +248,9 @@ TEST_CASE("test_identify_and_store_noc_router_tile_positions", "[vpr_setup_noc]" DeviceGrid test_device = DeviceGrid(device_grid_name, test_grid); // call the test function - identify_and_store_noc_router_tile_positions(test_device, list_of_routers, std::string(router_tile_name)); + list_of_routers = identify_and_store_noc_router_tile_positions(test_device, router_tile_name); - // check that the physocal router tile positions were correctly determined + // check that the physical router tile positions were correctly determined // make sure that only 4 router tiles were found REQUIRE(list_of_routers.size() == 4); @@ -354,7 +351,7 @@ TEST_CASE("test_identify_and_store_noc_router_tile_positions", "[vpr_setup_noc]" for (int i = 0; i < test_grid_width; i++) { for (int j = 0; j < test_grid_height; j++) { - // make sure the current tyle is not a router + // make sure the current tile is not a router if (test_grid[0][i][j].type == nullptr) { // assign the non-router tile as empty test_grid[0][i][j].type = &empty_tile; @@ -368,9 +365,9 @@ TEST_CASE("test_identify_and_store_noc_router_tile_positions", "[vpr_setup_noc]" DeviceGrid test_device = DeviceGrid(device_grid_name, test_grid); // call the test function - identify_and_store_noc_router_tile_positions(test_device, list_of_routers, std::string(router_tile_name)); + list_of_routers = identify_and_store_noc_router_tile_positions(test_device, router_tile_name); - // check that the physocal router tile positions were correctly determined + // check that the physical router tile positions were correctly determined // make sure that only 4 router tiles were found REQUIRE(list_of_routers.size() == 4); @@ -418,17 +415,17 @@ TEST_CASE("test_create_noc_routers", "[vpr_setup_noc]") { * - router 8: (4,8) * - router 9: (8,8) */ - list_of_routers.push_back({0, 0, 0, 0.5, 1}); - list_of_routers.push_back({4, 0, 0, 4.5, 1}); - list_of_routers.push_back({8, 0, 0, 8.5, 1}); + list_of_routers.emplace_back(0, 0, 0, 0.5, 1); + list_of_routers.emplace_back(4, 0, 0, 4.5, 1); + list_of_routers.emplace_back(8, 0, 0, 8.5, 1); - list_of_routers.push_back({0, 4, 0, 0.5, 5}); - list_of_routers.push_back({4, 4, 0, 4.5, 5}); - list_of_routers.push_back({8, 4, 0, 8.5, 5}); + list_of_routers.emplace_back(0, 4, 0, 0.5, 5); + list_of_routers.emplace_back(4, 4, 0, 4.5, 5); + list_of_routers.emplace_back(8, 4, 0, 8.5, 5); - list_of_routers.push_back({0, 8, 0, 0.5, 9}); - list_of_routers.push_back({4, 8, 0, 4.5, 9}); - list_of_routers.push_back({8, 8, 0, 8.5, 9}); + list_of_routers.emplace_back(0, 8, 0, 0.5, 9); + list_of_routers.emplace_back(4, 8, 0, 4.5, 9); + list_of_routers.emplace_back(8, 8, 0, 8.5, 9); // create the noc model (to store the routers) NocStorage noc_model; @@ -437,13 +434,13 @@ TEST_CASE("test_create_noc_routers", "[vpr_setup_noc]") { t_noc_inf noc_info; // pointer to each logical router - t_router* temp_router = NULL; + t_router* temp_router = nullptr; - const vtr::vector* noc_routers = NULL; + const vtr::vector* noc_routers = nullptr; SECTION("Test create routers when logical routers match to exactly one physical router. The number of routers is less than whats on the FPGA.") { // start by creating all the logical routers - // this is similiar to the user provided a config file + // this is similar to the user provided a config file temp_router = new t_router; NocRouterId noc_router_id; @@ -481,9 +478,9 @@ TEST_CASE("test_create_noc_routers", "[vpr_setup_noc]") { REQUIRE(test_router.get_router_grid_position_y() == list_of_routers[router_id - 1].grid_height_position); } } - SECTION("Test create routers when logical routers match to exactly one physical router. The number of routers is exacrly the same as on the FPGA.") { + SECTION("Test create routers when logical routers match to exactly one physical router. The number of routers is exactly the same as on the FPGA.") { // start by creating all the logical routers - // this is similiar to the user provided a config file + // this is similar to the user provided a config file temp_router = new t_router; NocRouterId noc_router_id; @@ -523,7 +520,7 @@ TEST_CASE("test_create_noc_routers", "[vpr_setup_noc]") { } SECTION("Test create routers when a logical router can be matched to two physical routers. The number of routers is exactly the same as on the FPGA.") { // start by creating all the logical routers - // this is similiar to the user provided a config file + // this is similar to the user provided a config file temp_router = new t_router; NocRouterId noc_router_id; @@ -595,17 +592,17 @@ TEST_CASE("test_create_noc_links", "[vpr_setup_noc]") { * - router 8: (4,8) * - router 9: (8,8) */ - list_of_routers.push_back({0, 0, 0, 0.5, 1}); - list_of_routers.push_back({4, 0, 0, 4.5, 1}); - list_of_routers.push_back({8, 0, 0, 8.5, 1}); + list_of_routers.emplace_back(0, 0, 0, 0.5, 1); + list_of_routers.emplace_back(4, 0, 0, 4.5, 1); + list_of_routers.emplace_back(8, 0, 0, 8.5, 1); - list_of_routers.push_back({0, 4, 0, 0.5, 5}); - list_of_routers.push_back({4, 4, 0, 4.5, 5}); - list_of_routers.push_back({8, 4, 0, 8.5, 5}); + list_of_routers.emplace_back(0, 4, 0, 0.5, 5); + list_of_routers.emplace_back(4, 4, 0, 4.5, 5); + list_of_routers.emplace_back(8, 4, 0, 8.5, 5); - list_of_routers.push_back({0, 8, 0, 0.5, 9}); - list_of_routers.push_back({4, 8, 0, 4.5, 9}); - list_of_routers.push_back({8, 8, 0, 8.5, 9}); + list_of_routers.emplace_back(0, 8, 0, 0.5, 9); + list_of_routers.emplace_back(4, 8, 0, 4.5, 9); + list_of_routers.emplace_back(8, 8, 0, 8.5, 9); // create the noc model (to store the routers) NocStorage noc_model; @@ -618,10 +615,10 @@ TEST_CASE("test_create_noc_links", "[vpr_setup_noc]") { t_noc_inf noc_info; // pointer to each logical router - t_router* temp_router = NULL; + t_router* temp_router = nullptr; // start by creating all the logical routers - // this is similiar to the user provided a config file + // this is similar to the user provided a config file temp_router = new t_router; for (int router_id = 1; router_id < 10; router_id++) { @@ -635,7 +632,8 @@ TEST_CASE("test_create_noc_links", "[vpr_setup_noc]") { noc_model.add_router(router_id, list_of_routers[router_id - 1].grid_width_position, list_of_routers[router_id - 1].grid_height_position, - list_of_routers[router_id - 1].layer_position); + list_of_routers[router_id - 1].layer_position, + 1.0); } delete temp_router; @@ -676,7 +674,7 @@ TEST_CASE("test_create_noc_links", "[vpr_setup_noc]") { noc_info.router_list[8].connection_list.push_back(8); // call the function to test - create_noc_links(&noc_info, &noc_model); + create_noc_links(noc_info, &noc_model); NocRouterId current_source_router_id; NocRouterId current_destination_router_id; @@ -711,10 +709,10 @@ TEST_CASE("test_setup_noc", "[vpr_setup_noc]") { t_noc_inf noc_info; // pointer to each logical router - t_router* temp_router = NULL; + t_router* temp_router = nullptr; // start by creating all the logical routers - // this is similiar to the user provided a config file + // this is similar to the user provided a config file temp_router = new t_router; // datastructure to hold the list of physical tiles @@ -741,17 +739,17 @@ TEST_CASE("test_setup_noc", "[vpr_setup_noc]") { * - router 8: (4,8) * - router 9: (8,8) */ - list_of_routers.push_back({0, 0, 0, 0.5, 1}); - list_of_routers.push_back({4, 0, 0, 4.5, 1}); - list_of_routers.push_back({8, 0, 0, 8.5, 1}); + list_of_routers.emplace_back(0, 0, 0, 0.5, 1); + list_of_routers.emplace_back(4, 0, 0, 4.5, 1); + list_of_routers.emplace_back(8, 0, 0, 8.5, 1); - list_of_routers.push_back({0, 4, 0, 0.5, 5}); - list_of_routers.push_back({4, 4, 0, 4.5, 5}); - list_of_routers.push_back({8, 4, 0, 8.5, 5}); + list_of_routers.emplace_back(0, 4, 0, 0.5, 5); + list_of_routers.emplace_back(4, 4, 0, 4.5, 5); + list_of_routers.emplace_back(8, 4, 0, 8.5, 5); - list_of_routers.push_back({0, 8, 0, 0.5, 9}); - list_of_routers.push_back({4, 8, 0, 4.5, 9}); - list_of_routers.push_back({8, 8, 0, 8.5, 9}); + list_of_routers.emplace_back(0, 8, 0, 0.5, 9); + list_of_routers.emplace_back(4, 8, 0, 4.5, 9); + list_of_routers.emplace_back(8, 8, 0, 8.5, 9); for (int router_id = 1; router_id < 10; router_id++) { // we will have 9 logical routers that will take up all physical routers @@ -801,7 +799,7 @@ TEST_CASE("test_setup_noc", "[vpr_setup_noc]") { //assign the noc_info to the arch arch.noc = &noc_info; - // the architecture file has been setup to include the noc topology and we set the parameters below + // the architecture file has been setup to include the noc topology, and we set the parameters below noc_info.link_bandwidth = 67.8; noc_info.link_latency = 56.7; noc_info.router_latency = 2.3; @@ -923,7 +921,7 @@ TEST_CASE("test_setup_noc", "[vpr_setup_noc]") { REQUIRE_THROWS_WITH(setup_noc(arch), "The Provided NoC topology information in the architecture file has more number of routers than what is available in the FPGA device."); } - SECTION("Test setup_noc when there are no physical NoC routers on the FPGA.") { + SECTION("Test setup_noc when there are no physical NoC routers on the FPGA.") { // test device grid name std::string device_grid_name = "test"; @@ -958,7 +956,7 @@ TEST_CASE("test_setup_noc", "[vpr_setup_noc]") { for (int i = 0; i < test_grid_width; i++) { for (int j = 0; j < test_grid_height; j++) { - // make sure the current tyle is not a router + // make sure the current tile is not a router if (test_grid[0][i][j].type == nullptr) { // assign the non-router tile as empty test_grid[0][i][j].type = &empty_tile; @@ -974,6 +972,270 @@ TEST_CASE("test_setup_noc", "[vpr_setup_noc]") { REQUIRE_THROWS_WITH(setup_noc(arch), "No physical NoC routers were found on the FPGA device. Either the provided name for the physical router tile was incorrect or the FPGA device has no routers."); } + SECTION("Test setup_noc when there are overrides for NoC-wide latency and bandwidth values.") { + // test device grid name + std::string device_grid_name = "test"; + + // creating a reference for the empty tile name and router name + char empty_tile_name[6] = "empty"; + char router_tile_name[7] = "router"; + + // assign the name used when describing a router tile in the FPGA architecture description file + arch.noc->noc_router_tile_name.assign(router_tile_name); + + // device grid parameters + int test_grid_width = 10; + int test_grid_height = 10; + + // create the test device grid (10x10) + auto test_grid = vtr::NdMatrix({1, 10, 10}); + + // create an empty physical tile and assign its parameters + t_physical_tile_type empty_tile; + empty_tile.name = empty_tile_name; + empty_tile.height = 1; + empty_tile.width = 1; + + // create a router tile and assign its parameters + // the router will take up 4 grid spaces and be named "router" + t_physical_tile_type router_tile; + router_tile.name = router_tile_name; + router_tile.height = 2; + router_tile.width = 2; + + // (0, 0) + test_grid[0][0][0].type = &router_tile; + test_grid[0][0][0].height_offset = 0; + test_grid[0][0][0].width_offset = 0; + + test_grid[0][1][0].type = &router_tile; + test_grid[0][1][0].height_offset = 0; + test_grid[0][1][0].width_offset = 1; + + test_grid[0][0][1].type = &router_tile; + test_grid[0][0][1].height_offset = 1; + test_grid[0][0][1].width_offset = 0; + + test_grid[0][1][1].type = &router_tile; + test_grid[0][1][1].height_offset = 1; + test_grid[0][1][1].width_offset = 1; + + // (0, 4) + test_grid[0][0][4].type = &router_tile; + test_grid[0][0][4].height_offset = 0; + test_grid[0][0][4].width_offset = 0; + + test_grid[0][1][4].type = &router_tile; + test_grid[0][1][4].height_offset = 0; + test_grid[0][1][4].width_offset = 1; + + test_grid[0][0][5].type = &router_tile; + test_grid[0][0][5].height_offset = 1; + test_grid[0][0][5].width_offset = 0; + + test_grid[0][1][5].type = &router_tile; + test_grid[0][1][5].height_offset = 1; + test_grid[0][1][5].width_offset = 1; + + // (0, 8) + test_grid[0][0][8].type = &router_tile; + test_grid[0][0][8].height_offset = 0; + test_grid[0][0][8].width_offset = 0; + + test_grid[0][1][8].type = &router_tile; + test_grid[0][1][8].height_offset = 0; + test_grid[0][1][8].width_offset = 1; + + test_grid[0][0][9].type = &router_tile; + test_grid[0][0][9].height_offset = 1; + test_grid[0][0][9].width_offset = 0; + + test_grid[0][1][9].type = &router_tile; + test_grid[0][1][9].height_offset = 1; + test_grid[0][1][9].width_offset = 1; + + // (4, 0) + test_grid[0][4][0].type = &router_tile; + test_grid[0][4][0].height_offset = 0; + test_grid[0][4][0].width_offset = 0; + + test_grid[0][5][0].type = &router_tile; + test_grid[0][5][0].height_offset = 0; + test_grid[0][5][0].width_offset = 1; + + test_grid[0][4][1].type = &router_tile; + test_grid[0][4][1].height_offset = 1; + test_grid[0][4][1].width_offset = 0; + + test_grid[0][5][1].type = &router_tile; + test_grid[0][5][1].height_offset = 1; + test_grid[0][5][1].width_offset = 1; + + // (4, 4) + test_grid[0][4][4].type = &router_tile; + test_grid[0][4][4].height_offset = 0; + test_grid[0][4][4].width_offset = 0; + + test_grid[0][5][4].type = &router_tile; + test_grid[0][5][4].height_offset = 0; + test_grid[0][5][4].width_offset = 1; + + test_grid[0][4][5].type = &router_tile; + test_grid[0][4][5].height_offset = 1; + test_grid[0][4][5].width_offset = 0; + + test_grid[0][5][5].type = &router_tile; + test_grid[0][5][5].height_offset = 1; + test_grid[0][5][5].width_offset = 1; + + // (4, 8) + test_grid[0][4][8].type = &router_tile; + test_grid[0][4][8].height_offset = 0; + test_grid[0][4][8].width_offset = 0; + + test_grid[0][5][8].type = &router_tile; + test_grid[0][5][8].height_offset = 0; + test_grid[0][5][8].width_offset = 1; + + test_grid[0][4][9].type = &router_tile; + test_grid[0][4][9].height_offset = 1; + test_grid[0][4][9].width_offset = 0; + + test_grid[0][5][9].type = &router_tile; + test_grid[0][5][9].height_offset = 1; + test_grid[0][5][9].width_offset = 1; + + // (8, 0) + test_grid[0][8][0].type = &router_tile; + test_grid[0][8][0].height_offset = 0; + test_grid[0][8][0].width_offset = 0; + + test_grid[0][9][0].type = &router_tile; + test_grid[0][9][0].height_offset = 0; + test_grid[0][9][0].width_offset = 1; + + test_grid[0][8][1].type = &router_tile; + test_grid[0][8][1].height_offset = 1; + test_grid[0][8][1].width_offset = 0; + + test_grid[0][9][1].type = &router_tile; + test_grid[0][9][1].height_offset = 1; + test_grid[0][9][1].width_offset = 1; + + // (8, 4) + test_grid[0][8][4].type = &router_tile; + test_grid[0][8][4].height_offset = 0; + test_grid[0][8][4].width_offset = 0; + + test_grid[0][9][4].type = &router_tile; + test_grid[0][9][4].height_offset = 0; + test_grid[0][9][4].width_offset = 1; + + test_grid[0][8][5].type = &router_tile; + test_grid[0][8][5].height_offset = 1; + test_grid[0][8][5].width_offset = 0; + + test_grid[0][9][5].type = &router_tile; + test_grid[0][9][5].height_offset = 1; + test_grid[0][9][5].width_offset = 1; + + // (8, 8) + test_grid[0][8][8].type = &router_tile; + test_grid[0][8][8].height_offset = 0; + test_grid[0][8][8].width_offset = 0; + + test_grid[0][9][8].type = &router_tile; + test_grid[0][9][8].height_offset = 0; + test_grid[0][9][8].width_offset = 1; + + test_grid[0][8][9].type = &router_tile; + test_grid[0][8][9].height_offset = 1; + test_grid[0][8][9].width_offset = 0; + + test_grid[0][9][9].type = &router_tile; + test_grid[0][9][9].height_offset = 1; + test_grid[0][9][9].width_offset = 1; + + for (int i = 0; i < test_grid_width; i++) { + for (int j = 0; j < test_grid_height; j++) { + // make sure the current tyle is not a router + if (test_grid[0][i][j].type == nullptr) { + // assign the non-router tile as empty + test_grid[0][i][j].type = &empty_tile; + test_grid[0][i][j].width_offset = 0; + test_grid[0][i][j].height_offset = 0; + } + } + } + + std::random_device device; + std::mt19937 rand_num_gen(device()); + std::uniform_int_distribution dist(1, 9); + + constexpr double LINK_LATENCY_OVERRIDE = 142.2; + constexpr double LINK_BANDWIDTH_OVERRIDE = 727.4; + constexpr double ROUTER_LATENCY_OVERRIDE = 151.6; + REQUIRE(LINK_LATENCY_OVERRIDE != noc_info.link_latency); + REQUIRE(LINK_BANDWIDTH_OVERRIDE != noc_info.link_bandwidth); + REQUIRE(ROUTER_LATENCY_OVERRIDE != noc_info.router_latency); + + // add router latency overrides + for (int i = 0; i < 3; i++) { + int noc_router_user_id = dist(rand_num_gen); + noc_info.router_latency_overrides.insert({noc_router_user_id, ROUTER_LATENCY_OVERRIDE}); + } + + // add link latency overrides + for (int i = 0; i < 3; i++) { + int noc_router_user_id = dist(rand_num_gen); + size_t n_connections = noc_info.router_list[noc_router_user_id - 1].connection_list.size(); + int selected_connection = dist(rand_num_gen) % n_connections; + int neighbor_router_user_id = noc_info.router_list[noc_router_user_id - 1].connection_list[selected_connection]; + noc_info.link_latency_overrides.insert({{noc_router_user_id, neighbor_router_user_id}, LINK_LATENCY_OVERRIDE}); + } + + // add link bandwidth overrides + for (int i = 0; i < 3; i++) { + int noc_router_user_id = dist(rand_num_gen); + size_t n_connections = noc_info.router_list[noc_router_user_id - 1].connection_list.size(); + int selected_connection = dist(rand_num_gen) % n_connections; + int neighbor_router_user_id = noc_info.router_list[noc_router_user_id - 1].connection_list[selected_connection]; + noc_info.link_bandwidth_overrides.insert({{noc_router_user_id, neighbor_router_user_id}, LINK_BANDWIDTH_OVERRIDE}); + } + + device_ctx.grid = DeviceGrid(device_grid_name, test_grid); + + REQUIRE_NOTHROW(setup_noc(arch)); + + const auto& noc_model = g_vpr_ctx.noc().noc_model; + + // check NoC router latencies + for (const auto& noc_router : noc_model.get_noc_routers()) { + int router_user_id = noc_router.get_router_user_id(); + auto it = noc_info.router_latency_overrides.find(router_user_id); + double expected_latency = (it != noc_info.router_latency_overrides.end()) ? it->second : noc_info.router_latency; + REQUIRE(expected_latency == noc_router.get_latency()); + } + + // check NoC link latencies and bandwidth + for (const auto& noc_link : noc_model.get_noc_links()) { + NocRouterId src_router_id = noc_link.get_source_router(); + NocRouterId dst_router_id = noc_link.get_sink_router(); + int src_user_id = noc_model.convert_router_id(src_router_id); + int dst_user_id = noc_model.convert_router_id(dst_router_id); + + auto lat_it = noc_info.link_latency_overrides.find({src_user_id, dst_user_id}); + double expected_latency = (lat_it != noc_info.link_latency_overrides.end()) ? lat_it->second : noc_info.link_latency; + REQUIRE(expected_latency == noc_link.get_latency()); + + auto bw_it = noc_info.link_bandwidth_overrides.find({src_user_id, dst_user_id}); + double expected_bandwidth = (bw_it != noc_info.link_bandwidth_overrides.end()) ? bw_it->second : noc_info.link_bandwidth; + REQUIRE(expected_bandwidth == noc_link.get_bandwidth()); + } + + // remove noc storage + g_vpr_ctx.mutable_noc().noc_model.clear_noc(); + } } } // namespace \ No newline at end of file diff --git a/vpr/test/test_xy_routing.cpp b/vpr/test/test_xy_routing.cpp index b130d47b62f..789fb754bf5 100644 --- a/vpr/test/test_xy_routing.cpp +++ b/vpr/test/test_xy_routing.cpp @@ -5,6 +5,9 @@ namespace { +constexpr double DUMMY_LATENCY = 1e-9; +constexpr double DUMMY_BANDWIDTH = 1e12; + /** * @brief Compares two vectors of NocLinks. These vectors represent * two routes between a start and destination routers. This function @@ -53,7 +56,7 @@ TEST_CASE("test_route_flow", "[vpr_noc_xy_routing]") { // add all the routers for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { - noc_model.add_router((i * 4) + j, j, i, 0); + noc_model.add_router((i * 4) + j, j, i, 0, DUMMY_LATENCY); } } @@ -64,19 +67,19 @@ TEST_CASE("test_route_flow", "[vpr_noc_xy_routing]") { for (int j = 0; j < 4; j++) { // add a link to the left of the router if there exists another router there if ((j - 1) >= 0) { - noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) - 1)); + noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) - 1), DUMMY_BANDWIDTH, DUMMY_LATENCY); } // add a link to the top of the router if there exists another router there if ((i + 1) <= 3) { - noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) + 4)); + noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) + 4), DUMMY_BANDWIDTH, DUMMY_LATENCY); } // add a link to the right of the router if there exists another router there if ((j + 1) <= 3) { - noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) + 1)); + noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) + 1), DUMMY_BANDWIDTH, DUMMY_LATENCY); } // add a link to the bottom of the router if there exists another router there if ((i - 1) >= 0) { - noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) - 4)); + noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) - 4), DUMMY_BANDWIDTH, DUMMY_LATENCY); } } } @@ -243,7 +246,7 @@ TEST_CASE("test_route_flow when it fails in a mesh topology.", "[vpr_noc_xy_rout // add all the routers for (int i = 0; i < 4; i++) { for (int j = 0; j < 4; j++) { - noc_model.add_router((i * 4) + j, j, i, 0); + noc_model.add_router((i * 4) + j, j, i, 0, DUMMY_LATENCY); } } @@ -254,19 +257,19 @@ TEST_CASE("test_route_flow when it fails in a mesh topology.", "[vpr_noc_xy_rout for (int j = 0; j < 4; j++) { // add a link to the left of the router if there exists another router there if ((j - 1) >= 0) { - noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) - 1)); + noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) - 1), DUMMY_BANDWIDTH, DUMMY_LATENCY); } // add a link to the top of the router if there exists another router there if ((i + 1) <= 3) { - noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) + 4)); + noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) + 4), DUMMY_BANDWIDTH, DUMMY_LATENCY); } // add a link to the right of the router if there exists another router there if ((j + 1) <= 3) { - noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) + 1)); + noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) + 1), DUMMY_BANDWIDTH, DUMMY_LATENCY); } // add a link to the bottom of the router if there exists another router there if ((i - 1) >= 0) { - noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) - 4)); + noc_model.add_link((NocRouterId)((i * 4) + j), (NocRouterId)(((i * 4) + j) - 4), DUMMY_BANDWIDTH, DUMMY_LATENCY); } } } @@ -353,17 +356,17 @@ TEST_CASE("test_route_flow when it fails in a non mesh topology.", "[vpr_noc_xy_ // this will be set to the device grid width noc_model.set_device_grid_spec((int)4, 0); - noc_model.add_router(0, 0, 0, 0); - noc_model.add_router(1, 2, 2, 0); - noc_model.add_router(2, 1, 2, 0); - noc_model.add_router(3, 3, 0, 0); + noc_model.add_router(0, 0, 0, 0, DUMMY_LATENCY); + noc_model.add_router(1, 2, 2, 0, DUMMY_LATENCY); + noc_model.add_router(2, 1, 2, 0, DUMMY_LATENCY); + noc_model.add_router(3, 3, 0, 0, DUMMY_LATENCY); noc_model.make_room_for_noc_router_link_list(); // add the links - noc_model.add_link((NocRouterId)0, (NocRouterId)3); - noc_model.add_link((NocRouterId)3, (NocRouterId)0); - noc_model.add_link((NocRouterId)2, (NocRouterId)1); + noc_model.add_link((NocRouterId)0, (NocRouterId)3, DUMMY_BANDWIDTH, DUMMY_LATENCY); + noc_model.add_link((NocRouterId)3, (NocRouterId)0, DUMMY_BANDWIDTH, DUMMY_LATENCY); + noc_model.add_link((NocRouterId)2, (NocRouterId)1, DUMMY_BANDWIDTH, DUMMY_LATENCY); // now create the start and the destination routers of the route we want to test auto start_router_id = NocRouterId(3);