diff --git a/libs/libarchfpga/src/echo_arch.cpp b/libs/libarchfpga/src/echo_arch.cpp index 70456a8a204..6f71dbac818 100644 --- a/libs/libarchfpga/src/echo_arch.cpp +++ b/libs/libarchfpga/src/echo_arch.cpp @@ -185,13 +185,13 @@ void PrintArchInfo(FILE* Echo, const t_arch* arch) { } switch (arch->sb_type) { - case (WILTON): + case e_switch_block_type::WILTON: fprintf(Echo, "\tSwitch Block: type wilton fs %d\n", arch->Fs); break; - case (UNIVERSAL): + case (e_switch_block_type::UNIVERSAL): fprintf(Echo, "\tSwitch Block: type universal fs %d\n", arch->Fs); break; - case (SUBSET): + case e_switch_block_type::SUBSET: fprintf(Echo, "\tSwitch Block: type subset fs %d\n", arch->Fs); break; default: @@ -201,7 +201,7 @@ void PrintArchInfo(FILE* Echo, const t_arch* arch) { fprintf(Echo, "\tInput Connect Block Switch Name Within a Same Die: %s\n", arch->ipin_cblock_switch_name[ipin_cblock_switch_index_within_die].c_str()); //if there is more than one layer available, print the connection block switch name that is used for connection between two dice - for (const auto& layout : arch->grid_layouts) { + for (const t_grid_def& layout : arch->grid_layouts) { int num_layers = (int)layout.layers.size(); if (num_layers > 1) { fprintf(Echo, "\tInput Connect Block Switch Name Between Two Dice: %s\n", arch->ipin_cblock_switch_name[ipin_cblock_switch_index_between_dice].c_str()); @@ -257,14 +257,6 @@ void PrintArchInfo(FILE* Echo, const t_arch* arch) { //wire_switch == arch_opin_switch fprintf(Echo, "\t\t\t\ttype unidir mux_name for within die connections: %s\n", arch->switches[seg.arch_wire_switch].name.c_str()); - //if there is more than one layer available, print the segment switch name that is used for connection between two dice - for (const auto& layout : arch->grid_layouts) { - int num_layers = (int)layout.layers.size(); - if (num_layers > 1) { - fprintf(Echo, "\t\t\t\ttype unidir mux_name for between two dice connections: %s\n", - arch->switches[seg.arch_inter_die_switch].name.c_str()); - } - } } else { //Should be bidir fprintf(Echo, "\t\t\t\ttype bidir wire_switch %s arch_opin_switch %s\n", arch->switches[seg.arch_wire_switch].name.c_str(), diff --git a/libs/libarchfpga/src/logic_types.h b/libs/libarchfpga/src/logic_types.h index 07dbf5ac85e..55c0ea39f0d 100644 --- a/libs/libarchfpga/src/logic_types.h +++ b/libs/libarchfpga/src/logic_types.h @@ -31,7 +31,9 @@ enum class e_parallel_axis { /** Y_AXIS: Data that describes an y-directed wire segment (CHANY) */ Y_AXIS, /** BOTH_AXIS: Data that can be applied to both x-directed and y-directed wire segment */ - BOTH_AXIS + BOTH_AXIS, + /** Z_AXIS: Data that describes an z-directed wire segment (CHANZ) */ + Z_AXIS }; /* diff --git a/libs/libarchfpga/src/parse_switchblocks.cpp b/libs/libarchfpga/src/parse_switchblocks.cpp index 747cd4687c7..7209314371b 100644 --- a/libs/libarchfpga/src/parse_switchblocks.cpp +++ b/libs/libarchfpga/src/parse_switchblocks.cpp @@ -35,7 +35,7 @@ using vtr::t_formula_data; /*---- Functions for Parsing Switchblocks from Architecture ----*/ //Process the desired order of a wireconn -static void parse_switchpoint_order(const char* order, SwitchPointOrder& switchpoint_order); +static void parse_switchpoint_order(std::string_view order, e_switch_point_order& switchpoint_order); /** * @brief Parses an inline `` node using its attributes. @@ -86,7 +86,7 @@ static void parse_comma_separated_wire_points(const char* ch, std::vector& switches); @@ -282,13 +282,13 @@ static t_wire_switchpoints parse_wireconn_from_to_node(pugi::xml_node node, cons return wire_switchpoints; } -static void parse_switchpoint_order(const char* order, SwitchPointOrder& switchpoint_order) { - if (order == std::string("")) { - switchpoint_order = SwitchPointOrder::SHUFFLED; //Default - } else if (order == std::string("fixed")) { - switchpoint_order = SwitchPointOrder::FIXED; - } else if (order == std::string("shuffled")) { - switchpoint_order = SwitchPointOrder::SHUFFLED; +static void parse_switchpoint_order(std::string_view order, e_switch_point_order& switchpoint_order) { + if (order == "") { + switchpoint_order = e_switch_point_order::SHUFFLED; //Default + } else if (order == "fixed") { + switchpoint_order = e_switch_point_order::FIXED; + } else if (order == "shuffled") { + switchpoint_order = e_switch_point_order::SHUFFLED; } else { archfpga_throw(__FILE__, __LINE__, "Unrecognized switchpoint order '%s'", order); } @@ -328,19 +328,18 @@ static void parse_comma_separated_wire_points(const char* ch, std::vector #include #include -#include #include #include @@ -1686,28 +1685,6 @@ enum class SegResType { /// String versions of segment resource types constexpr std::array(SegResType::NUM_RES_TYPES)> RES_TYPE_STRING{"GCLK", "GENERAL"}; -/// Defines the type of switch block used in FPGA routing. -enum e_switch_block_type { - /// If the type is SUBSET, I use a Xilinx-like switch block where track i in one channel always - /// connects to track i in other channels. - SUBSET, - - /// If type is WILTON, I use a switch block where track i - /// does not always connect to track i in other channels. - /// See Steve Wilton, PhD Thesis, University of Toronto, 1996. - WILTON, - - /// The UNIVERSAL switch block is from Y. W. Chang et al, TODAES, Jan. 1996, pp. 80 - 101. - UNIVERSAL, - - /// The FULL switch block type allows for complete connectivity between tracks. - FULL, - - /// A CUSTOM switch block has also been added which allows a user to describe custom permutation functions and connection patterns. - /// See comment at top of SRC/route/build_switchblocks.c - CUSTOM -}; - enum e_Fc_type { ABSOLUTE, FRACTIONAL @@ -1746,14 +1723,14 @@ struct t_segment_inf { * specified in the architecture file. If -1, this value was not set in the * architecture file and arch_wire_switch should be used for "DEC_DIR" wire segments. */ - short arch_wire_switch_dec = -1; + short arch_wire_switch_dec = ARCH_FPGA_UNDEFINED_VAL; /** * @brief Same as arch_opin_switch but used only for decremental tracks if * it is specified in the architecture file. If -1, this value was not set in * the architecture file and arch_opin_switch should be used for "DEC_DIR" wire segments. */ - short arch_opin_switch_dec = -1; + short arch_opin_switch_dec = ARCH_FPGA_UNDEFINED_VAL; /** * @brief Index of the switch type that connects output pins (OPINs) to this @@ -1761,7 +1738,7 @@ struct t_segment_inf { * the switches from the architecture file, not the expanded list of switches * that is built at the end of build_rr_graph. */ - short arch_inter_die_switch = -1; + short arch_inter_die_switch = ARCH_FPGA_UNDEFINED_VAL; /** * @brief The fraction of logic blocks along its length to which this segment can connect. @@ -1783,7 +1760,7 @@ struct t_segment_inf { /// The capacitance of a routing track, per unit logic block length. float Cmetal; - enum e_directionality directionality; + e_directionality directionality; /** * @brief Defines what axis the segment is parallel to. See e_parallel_axis @@ -1841,7 +1818,6 @@ inline bool operator==(const t_segment_inf& a, const t_segment_inf& b) { && a.length == b.length && a.arch_wire_switch == b.arch_wire_switch && a.arch_opin_switch == b.arch_opin_switch - && a.arch_inter_die_switch == b.arch_inter_die_switch && a.frac_cb == b.frac_cb && a.frac_sb == b.frac_sb && a.longline == b.longline diff --git a/libs/libarchfpga/src/read_fpga_interchange_arch.cpp b/libs/libarchfpga/src/read_fpga_interchange_arch.cpp index d9ad5853570..984dddec11a 100644 --- a/libs/libarchfpga/src/read_fpga_interchange_arch.cpp +++ b/libs/libarchfpga/src/read_fpga_interchange_arch.cpp @@ -2328,7 +2328,7 @@ struct ArchReader { arch_->Chans.chan_y_dist.xpeak = 0; arch_->Chans.chan_y_dist.dc = 0; arch_->ipin_cblock_switch_name.push_back(std::string("generic")); - arch_->sb_type = WILTON; + arch_->sb_type = e_switch_block_type::WILTON; arch_->Fs = 3; default_fc_.specified = true; default_fc_.in_value_type = e_fc_value_type::FRACTIONAL; diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index 676c78d0d35..187f1b4b01b 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -345,8 +345,9 @@ static void process_clock_routing(pugi::xml_node parent, const std::vector& switches, pugiutil::loc_data& loc_data); -static std::vector process_segments(pugi::xml_node Parent, +static std::vector process_segments(pugi::xml_node parent, const std::vector& switches, + int num_layers, const bool timing_enabled, const bool switchblocklist_required, const pugiutil::loc_data& loc_data); @@ -457,13 +458,13 @@ void xml_read_arch(const char* ArchFile, Next = get_single_child(architecture, "switchlist", loc_data); arch->switches = process_switches(Next, timing_enabled, loc_data); - /* Process switchblocks. This depends on switches */ - bool switchblocklist_required = (arch->sb_type == CUSTOM); //require this section only if custom switchblocks are used + // Process switchblocks. This depends on switches + bool switchblocklist_required = (arch->sb_type == e_switch_block_type::CUSTOM); // require this section only if custom switchblocks are used SWITCHBLOCKLIST_REQD = BoolToReqOpt(switchblocklist_required); /* Process segments. This depends on switches */ Next = get_single_child(architecture, "segmentlist", loc_data); - arch->Segments = process_segments(Next, arch->switches, timing_enabled, switchblocklist_required, loc_data); + arch->Segments = process_segments(Next, arch->switches, num_of_avail_layers, timing_enabled, switchblocklist_required, loc_data); Next = get_single_child(architecture, "switchblocklist", loc_data, SWITCHBLOCKLIST_REQD); if (Next) { @@ -2069,7 +2070,7 @@ static void process_fc(pugi::xml_node Node, //Apply any matching overrides bool default_overriden = false; - for (const auto& fc_override : fc_overrides) { + for (const t_fc_override& fc_override : fc_overrides) { bool apply_override = false; if (!fc_override.port_name.empty() && !fc_override.seg_name.empty()) { //Both port and seg names are specified require exact match on both @@ -2931,13 +2932,13 @@ static void process_device(pugi::xml_node Node, t_arch* arch, t_default_fc_spec& Prop = get_attribute(Cur, "type", loc_data).value(); // Parse attribute 'type', representing the major connectivity pattern for switch blocks if (strcmp(Prop, "wilton") == 0) { - arch->sb_type = WILTON; + arch->sb_type = e_switch_block_type::WILTON; } else if (strcmp(Prop, "universal") == 0) { - arch->sb_type = UNIVERSAL; + arch->sb_type = e_switch_block_type::UNIVERSAL; } else if (strcmp(Prop, "subset") == 0) { - arch->sb_type = SUBSET; + arch->sb_type = e_switch_block_type::SUBSET; } else if (strcmp(Prop, "custom") == 0) { - arch->sb_type = CUSTOM; + arch->sb_type = e_switch_block_type::CUSTOM; custom_switch_block = true; } else { archfpga_throw(loc_data.filename_c_str(), loc_data.line(Cur), @@ -2970,11 +2971,11 @@ static void process_tileable_device_parameters(t_arch* arch, const pugiutil::loc std::string sub_type_str = get_attribute(cur, "sub_type", loc_data, BoolToReqOpt(false)).as_string(""); if (!sub_type_str.empty()) { if (sub_type_str == "wilton") { - arch->sb_sub_type = WILTON; + arch->sb_sub_type = e_switch_block_type::WILTON; } else if (sub_type_str == "universal") { - arch->sb_sub_type = UNIVERSAL; + arch->sb_sub_type = e_switch_block_type::UNIVERSAL; } else if (sub_type_str == "subset") { - arch->sb_sub_type = SUBSET; + arch->sb_sub_type = e_switch_block_type::SUBSET; } else { archfpga_throw(loc_data.filename_c_str(), loc_data.line(cur), "Unknown property %s for switch block subtype x\n", sub_type_str.c_str()); @@ -3803,8 +3804,9 @@ static void process_complex_blocks(pugi::xml_node Node, } } -static std::vector process_segments(pugi::xml_node Parent, +static std::vector process_segments(pugi::xml_node parent, const std::vector& switches, + int num_layers, const bool timing_enabled, const bool switchblocklist_required, const pugiutil::loc_data& loc_data) { @@ -3815,22 +3817,22 @@ static std::vector process_segments(pugi::xml_node Parent, pugi::xml_node SubElem; pugi::xml_node Node; - /* Count the number of segs and check they are in fact - * of segment elements. */ - int NumSegs = count_children(Parent, "segment", loc_data); + // Count the number of segs specified in the architecture file. + int num_segs = count_children(parent, "segment", loc_data); - /* Alloc segment list */ - if (NumSegs > 0) { - Segs.resize(NumSegs); + // Alloc segment list + if (num_segs > 0) { + Segs.resize(num_segs); } - /* Load the segments. */ - Node = get_first_child(Parent, "segment", loc_data); + // Load the segments. + Node = get_first_child(parent, "segment", loc_data); - bool x_axis_seg_found = false; /*Flags to see if we have any x-directed segment type specified*/ - bool y_axis_seg_found = false; /*Flags to see if we have any y-directed segment type specified*/ + bool x_axis_seg_found = false; // Flags to see if we have any x-directed segment type specified + bool y_axis_seg_found = false; // Flags to see if we have any y-directed segment type specified + bool z_axis_seg_found = false; // Flags to see if we have any z-directed segment type specified - for (int i = 0; i < NumSegs; ++i) { + for (int i = 0; i < num_segs; ++i) { /* Get segment name */ tmp = get_attribute(Node, "name", loc_data, ReqOpt::OPTIONAL).as_string(nullptr); if (tmp) { @@ -3885,16 +3887,19 @@ static std::vector process_segments(pugi::xml_node Parent, } else if (strcmp(tmp, "y") == 0) { Segs[i].parallel_axis = e_parallel_axis::Y_AXIS; y_axis_seg_found = true; + } else if (strcmp(tmp, "z") == 0) { + Segs[i].parallel_axis = e_parallel_axis::Z_AXIS; + z_axis_seg_found = true; } else { archfpga_throw(loc_data.filename_c_str(), loc_data.line(Node), - vtr::string_fmt("Unsopported parralel axis type: %s\n", tmp).c_str()); + vtr::string_fmt("Unsupported parallel axis type: %s\n", tmp).c_str()); } } else { x_axis_seg_found = true; y_axis_seg_found = true; } - /*Get segment resource type*/ + // Get segment resource type tmp = get_attribute(Node, "res_type", loc_data, ReqOpt::OPTIONAL).as_string(nullptr); if (tmp) { @@ -3903,7 +3908,7 @@ static std::vector process_segments(pugi::xml_node Parent, Segs[i].res_type = static_cast(std::distance(RES_TYPE_STRING.begin(), it)); } else { archfpga_throw(loc_data.filename_c_str(), loc_data.line(Node), - vtr::string_fmt("Unsopported segment res_type: %s\n", tmp).c_str()); + vtr::string_fmt("Unsupported segment res_type: %s\n", tmp).c_str()); } } @@ -3912,16 +3917,16 @@ static std::vector process_segments(pugi::xml_node Parent, * (*Segs)[i].Cmetal_per_m = get_attribute(Node, "Cmetal_per_m", false, * 0.);*/ - //Set of expected subtags (exact subtags are dependent on parameters) + // Set of expected subtags (exact subtags are dependent on parameters) std::vector expected_subtags; if (!Segs[i].longline) { - //Long line doesn't accpet or since it assumes full population + // Long line doesn't accept or since it assumes full population expected_subtags.emplace_back("sb"); expected_subtags.emplace_back("cb"); } - /* Get the type */ + // Get the type tmp = get_attribute(Node, "type", loc_data).value(); if (0 == strcmp(tmp, "bidir")) { Segs[i].directionality = BI_DIRECTIONAL; @@ -4089,7 +4094,12 @@ static std::vector process_segments(pugi::xml_node Parent, if (!x_axis_seg_found || !y_axis_seg_found) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(Node), - vtr::string_fmt("Atleast one segment per-axis needs to get specified if no segments with non-specified (default) axis attribute exist.").c_str()); + vtr::string_fmt("At least one segment per-axis needs to get specified if no segments with non-specified (default) axis attribute exist.").c_str()); + } + + if (num_layers > 1 && !z_axis_seg_found) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(Node), + vtr::string_fmt("At least one segment along Z axis needs to get specified if for 3D architectures.").c_str()); } return Segs; @@ -4164,7 +4174,11 @@ static void process_bend(pugi::xml_node Node, t_segment_inf& segment, const int part_len.push_back(list.size() + 1 - sum_len); } -static void calculate_custom_SB_locations(const pugiutil::loc_data& loc_data, const pugi::xml_node& SubElem, const int grid_width, const int grid_height, t_switchblock_inf& sb) { +static void calculate_custom_sb_locations(const pugiutil::loc_data& loc_data, + const pugi::xml_node& SubElem, + const int grid_width, + const int grid_height, + t_switchblock_inf& sb) { auto startx_attr = get_attribute(SubElem, "startx", loc_data, ReqOpt::OPTIONAL); auto endx_attr = get_attribute(SubElem, "endx", loc_data, ReqOpt::OPTIONAL); @@ -4177,24 +4191,24 @@ static void calculate_custom_SB_locations(const pugiutil::loc_data& loc_data, co auto incrx_attr = get_attribute(SubElem, "incrx", loc_data, ReqOpt::OPTIONAL); auto incry_attr = get_attribute(SubElem, "incry", loc_data, ReqOpt::OPTIONAL); - //parse the values from the architecture file and fill out SB region information + // parse the values from the architecture file and fill out SB region information vtr::FormulaParser p; vtr::t_formula_data vars; vars.set_var_value("W", grid_width); vars.set_var_value("H", grid_height); - sb.reg_x.start = startx_attr.empty() ? 0 : p.parse_formula(startx_attr.value(), vars); - sb.reg_y.start = starty_attr.empty() ? 0 : p.parse_formula(starty_attr.value(), vars); + sb.specified_loc.reg_x.start = startx_attr.empty() ? 0 : p.parse_formula(startx_attr.value(), vars); + sb.specified_loc.reg_y.start = starty_attr.empty() ? 0 : p.parse_formula(starty_attr.value(), vars); - sb.reg_x.end = endx_attr.empty() ? (grid_width - 1) : p.parse_formula(endx_attr.value(), vars); - sb.reg_y.end = endy_attr.empty() ? (grid_height - 1) : p.parse_formula(endy_attr.value(), vars); + sb.specified_loc.reg_x.end = endx_attr.empty() ? (grid_width - 1) : p.parse_formula(endx_attr.value(), vars); + sb.specified_loc.reg_y.end = endy_attr.empty() ? (grid_height - 1) : p.parse_formula(endy_attr.value(), vars); - sb.reg_x.repeat = repeatx_attr.empty() ? 0 : p.parse_formula(repeatx_attr.value(), vars); - sb.reg_y.repeat = repeaty_attr.empty() ? 0 : p.parse_formula(repeaty_attr.value(), vars); + sb.specified_loc.reg_x.repeat = repeatx_attr.empty() ? 0 : p.parse_formula(repeatx_attr.value(), vars); + sb.specified_loc.reg_y.repeat = repeaty_attr.empty() ? 0 : p.parse_formula(repeaty_attr.value(), vars); - sb.reg_x.incr = incrx_attr.empty() ? 1 : p.parse_formula(incrx_attr.value(), vars); - sb.reg_y.incr = incry_attr.empty() ? 1 : p.parse_formula(incry_attr.value(), vars); + sb.specified_loc.reg_x.incr = incrx_attr.empty() ? 1 : p.parse_formula(incrx_attr.value(), vars); + sb.specified_loc.reg_y.incr = incry_attr.empty() ? 1 : p.parse_formula(incry_attr.value(), vars); } /* Processes the switchblocklist section from the xml architecture file. @@ -4255,7 +4269,7 @@ static void process_switch_blocks(pugi::xml_node Parent, t_arch* arch, const pug } } - /* get the switchblock coordinate only if sb.location is set to E_XY_SPECIFIED*/ + // Get the switchblock coordinate only if sb.location is set to E_XY_SPECIFIED if (sb.location == e_sb_location::E_XY_SPECIFIED) { if (arch->device_layout == "auto") { archfpga_throw(loc_data.filename_c_str(), loc_data.line(SubElem), @@ -4270,22 +4284,22 @@ static void process_switch_blocks(pugi::xml_node Parent, t_arch* arch, const pug int grid_width = arch->grid_layouts.at(layout_index).width; int grid_height = arch->grid_layouts.at(layout_index).height; - /* Absolute location that this SB must be applied to, -1 if not specified*/ - sb.x = get_attribute(SubElem, "x", loc_data, ReqOpt::OPTIONAL).as_int(-1); - sb.y = get_attribute(SubElem, "y", loc_data, ReqOpt::OPTIONAL).as_int(-1); + // Absolute location that this SB must be applied to, -1 if not specified + sb.specified_loc.x = get_attribute(SubElem, "x", loc_data, ReqOpt::OPTIONAL).as_int(ARCH_FPGA_UNDEFINED_VAL); + sb.specified_loc.y = get_attribute(SubElem, "y", loc_data, ReqOpt::OPTIONAL).as_int(ARCH_FPGA_UNDEFINED_VAL); - //check if the absolute value is within the device grid width and height - if (sb.x >= grid_width || sb.y >= grid_height) { + // Check if the absolute value is within the device grid width and height + if (sb.specified_loc.x >= grid_width || sb.specified_loc.y >= grid_height) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(SubElem), - vtr::string_fmt("Location (%d,%d) is not valid within the grid! grid dimensions are: (%d,%d)\n", sb.x, sb.y, grid_width, grid_height).c_str()); + vtr::string_fmt("Location (%d,%d) is not valid within the grid! grid dimensions are: (%d,%d)\n", + sb.specified_loc.x, sb.specified_loc.y, grid_width, grid_height).c_str()); } - /* if the the switchblock exact location is not specified and a region is specified within the architecture file, - * we have to parse the region specification and apply the SB pattern to all the locations fall into the specified - * region based on device width and height. - */ - if (sb.x == -1 && sb.y == -1) { - calculate_custom_SB_locations(loc_data, SubElem, grid_width, grid_height, sb); + // if the switchblock exact location is not specified and a region is specified within the architecture file, + // we have to parse the region specification and apply the SB pattern to all the locations fall into the specified + // region based on device width and height. + if (sb.specified_loc.x == ARCH_FPGA_UNDEFINED_VAL && sb.specified_loc.y == ARCH_FPGA_UNDEFINED_VAL) { + calculate_custom_sb_locations(loc_data, SubElem, grid_width, grid_height, sb); } } @@ -4307,14 +4321,13 @@ static void process_switch_blocks(pugi::xml_node Parent, t_arch* arch, const pug static void process_cb_sb(pugi::xml_node Node, std::vector& list, const pugiutil::loc_data& loc_data) { const char* tmp = nullptr; - int i; int len = list.size(); // Check the type. We only support 'pattern' for now. // Should add frac back eventually. tmp = get_attribute(Node, "type", loc_data).value(); if (0 == strcmp(tmp, "pattern")) { - i = 0; + int i = 0; // Get the content string tmp = Node.child_value(); diff --git a/libs/libarchfpga/src/scatter_gather_types.h b/libs/libarchfpga/src/scatter_gather_types.h index dabc0e50998..5408cf560f0 100644 --- a/libs/libarchfpga/src/scatter_gather_types.h +++ b/libs/libarchfpga/src/scatter_gather_types.h @@ -7,7 +7,6 @@ * @brief Enumeration for the type field of an tag. With UNIDIR the gather pattern makes a mux which is connected by a node * to the scatter pattern of edges. With BIDIR, the structure is made symmetric with a gather mux and a scatter edge pattern on each end * of the node linking them. - * */ enum class e_scatter_gather_type { UNIDIR, ///< Unidirectional connection @@ -16,7 +15,6 @@ enum class e_scatter_gather_type { /** * @brief Struct containing information of an tag. An tag instantiates the scatter-gather pattern in some switchblock locations around the device. - * */ struct t_sg_location { e_sb_location type; ///< Type of locations that the pattern is instantiated at. @@ -41,7 +39,6 @@ struct t_sg_link { * @brief Struct containing information of a tag. When instantiated in the device using sg_locations, * a scatter-gather pattern defined by this struct gathers connections according to gather_pattern, moves through * the device using one of the sg_links and fans out or scatters the connections according to scatter_pattern. - * */ struct t_scatter_gather_pattern { std::string name; diff --git a/libs/libarchfpga/src/switchblock_types.h b/libs/libarchfpga/src/switchblock_types.h index 0d58d5091b6..0e1255d5311 100644 --- a/libs/libarchfpga/src/switchblock_types.h +++ b/libs/libarchfpga/src/switchblock_types.h @@ -15,6 +15,28 @@ enum e_directionality { BI_DIRECTIONAL }; +/// Defines the type of switch block used in FPGA routing. +enum class e_switch_block_type { + /// If the type is SUBSET, I use a Xilinx-like switch block where track i in one channel always + /// connects to track i in other channels. + SUBSET, + + /// If type is WILTON, I use a switch block where track i + /// does not always connect to track i in other channels. + /// See Steve Wilton, PhD Thesis, University of Toronto, 1996. + WILTON, + + /// The UNIVERSAL switch block is from Y. W. Chang et al, TODAES, Jan. 1996, pp. 80 - 101. + UNIVERSAL, + + /// The FULL switch block type allows for complete connectivity between tracks. + FULL, + + /// A CUSTOM switch block has also been added which allows a user to describe custom permutation functions and connection patterns. + /// See comment at top of SRC/route/build_switchblocks.c + CUSTOM +}; + /** * @brief At the intersection of routing channels, left, right, top and bottom specify the x- and y-directed channels * while above and under specify the switch block wires one a layer above or below the current one. above and below @@ -26,10 +48,7 @@ enum e_side : unsigned char { RIGHT = 1, BOTTOM = 2, LEFT = 3, - NUM_2D_SIDES = 4, - ABOVE = 5, - UNDER = 7, - NUM_3D_SIDES = 6, + NUM_2D_SIDES = 4 }; inline const std::unordered_map CHAR_SIDE_MAP = { @@ -40,22 +59,12 @@ inline const std::unordered_map CHAR_SIDE_MAP = { {'B', BOTTOM}, {'b', BOTTOM}, {'L', LEFT}, - {'l', LEFT}, - {'A', ABOVE}, - {'a', ABOVE}, - {'U', UNDER}, - {'u', UNDER}}; + {'l', LEFT}}; constexpr std::array TOTAL_2D_SIDES = {{TOP, RIGHT, BOTTOM, LEFT}}; // Set of all side orientations constexpr std::array TOTAL_2D_SIDE_STRINGS = {{"TOP", "RIGHT", "BOTTOM", "LEFT"}}; // String versions of side orientations -constexpr std::array TOTAL_3D_SIDES = {{TOP, RIGHT, BOTTOM, LEFT, ABOVE, UNDER}}; // Set of all side orientations including different layers -constexpr std::array TOTAL_3D_SIDE_STRINGS = {{"TOP", "RIGHT", "BOTTOM", "LEFT", "ABOVE", "UNDER"}}; // String versions of side orientations including different layers - -/** - * @brief Specifies what part of the FPGA a custom switchblock should be built in (i.e. perimeter, core, everywhere) - * - */ +/// @brief Specifies what part of the FPGA a custom switchblock should be built in (i.e. perimeter, core, everywhere) enum class e_sb_location { E_PERIMETER = 0, E_CORNER, @@ -84,7 +93,6 @@ struct t_sb_loc_spec { /** * @brief represents a connection between two sides of a switchblock - * */ class SBSideConnection { public: @@ -122,14 +130,13 @@ class SBSideConnection { } }; -enum class SwitchPointOrder { +enum class e_switch_point_order { FIXED, ///< Switchpoints are ordered as specified in architecture SHUFFLED ///< Switchpoints are shuffled (more diversity) }; /** * @brief A collection of switchpoints associated with a segment - * */ struct t_wire_switchpoints { std::string segment_name; ///< The type of segment @@ -138,15 +145,14 @@ struct t_wire_switchpoints { /** * @brief Used to list information about a set of track segments that should connect through a switchblock - * */ struct t_wireconn_inf { - std::vector from_switchpoint_set; ///< The set of segment/wirepoints representing the 'from' set (union of all t_wire_switchpoints in vector) - std::vector to_switchpoint_set; ///< The set of segment/wirepoints representing the 'to' set (union of all t_wire_switchpoints in vector) - SwitchPointOrder from_switchpoint_order = SwitchPointOrder::FIXED; ///< The desired from_switchpoint_set ordering - SwitchPointOrder to_switchpoint_order = SwitchPointOrder::FIXED; ///< The desired to_switchpoint_set ordering - int switch_override_indx = DEFAULT_SWITCH; ///< index in switch array of the switch used to override wire_switch of the 'to' set. - ///< DEFAULT_SWITCH is a sentinel value (i.e. the usual driving switch from a wire for the receiving wire will be used) + std::vector from_switchpoint_set; ///< The set of segment/wirepoints representing the 'from' set (union of all t_wire_switchpoints in vector) + std::vector to_switchpoint_set; ///< The set of segment/wirepoints representing the 'to' set (union of all t_wire_switchpoints in vector) + e_switch_point_order from_switchpoint_order = e_switch_point_order::FIXED; ///< The desired from_switchpoint_set ordering + e_switch_point_order to_switchpoint_order = e_switch_point_order::FIXED; ///< The desired to_switchpoint_set ordering + int switch_override_indx = DEFAULT_SWITCH; ///< index in switch array of the switch used to override wire_switch of the 'to' set. + ///< DEFAULT_SWITCH is a sentinel value (i.e. the usual driving switch from a wire for the receiving wire will be used) std::string num_conns_formula; /* Specifies how many connections should be made for this wireconn. * @@ -170,6 +176,15 @@ struct t_wireconn_inf { /* Use a map to index into the string permutation functions used to connect from one side to another */ typedef std::map> t_permutation_map; +struct t_specified_loc { + int x = -1; ///< The exact x-axis location that this SB is used, meaningful when type is set to E_XY_specified + int y = -1; ///< The exact y-axis location that this SB is used, meaningful when type is set to E_XY_specified + + // We can also define a region to apply this SB to all locations falls into this region using regular expression in the architecture file + t_sb_loc_spec reg_x; + t_sb_loc_spec reg_y; +}; + /** * @brief Lists all information about a particular switch block specified in the architecture file */ @@ -178,14 +193,9 @@ struct t_switchblock_inf { e_sb_location location; ///< where on the FPGA this switchblock should be built (i.e. perimeter, core, everywhere) e_directionality directionality; ///< the directionality of this switchblock (unidir/bidir) - int x = -1; ///< The exact x-axis location that this SB is used, meaningful when type is set to E_XY_specified - int y = -1; ///< The exact y-axis location that this SB is used, meaningful when type is set to E_XY_specified - - /* We can also define a region to apply this SB to all locations falls into this region using regular expression in the architecture file*/ - t_sb_loc_spec reg_x; - t_sb_loc_spec reg_y; - t_permutation_map permutation_map; ///< map holding the permutation functions attributed to this switchblock + t_specified_loc specified_loc; + std::vector wireconns; ///< list of wire types/groups this SB will connect }; diff --git a/libs/librrgraph/src/base/check_rr_graph.cpp b/libs/librrgraph/src/base/check_rr_graph.cpp index 4eebfa58cca..f3646c98ccb 100644 --- a/libs/librrgraph/src/base/check_rr_graph.cpp +++ b/libs/librrgraph/src/base/check_rr_graph.cpp @@ -234,11 +234,11 @@ void check_rr_graph(const RRGraphView& rr_graph, size_t inode = (size_t)rr_node; e_rr_type rr_type = rr_graph.node_type(rr_node); int ptc_num = rr_graph.node_ptc_num(rr_node); - int layer_num = rr_graph.node_layer(rr_node); + int layer_low = rr_graph.node_layer_low(rr_node); int xlow = rr_graph.node_xlow(rr_node); int ylow = rr_graph.node_ylow(rr_node); - t_physical_tile_type_ptr type = grid.get_physical_type({xlow, ylow, layer_num}); + t_physical_tile_type_ptr type = grid.get_physical_type({xlow, ylow, layer_low}); if (rr_type == e_rr_type::IPIN || rr_type == e_rr_type::OPIN) { // #TODO: No edges are added for internal pins. However, they need to be checked somehow! @@ -278,7 +278,7 @@ void check_rr_graph(const RRGraphView& rr_graph, if (has_adjacent_channel(rr_graph, grid, node)) { auto block_type = grid.get_physical_type({rr_graph.node_xlow(rr_node), rr_graph.node_ylow(rr_node), - rr_graph.node_layer(rr_node)}); + rr_graph.node_layer_low(rr_node)}); std::string pin_name = block_type_pin_index_to_name(block_type, rr_graph.node_pin_num(rr_node), is_flat); /* Print error messages for all the sides that a node may appear */ for (const e_side& node_side : TOTAL_2D_SIDES) { @@ -315,10 +315,10 @@ static bool rr_node_is_global_clb_ipin(const RRGraphView& rr_graph, const Device /* Returns true if inode refers to a global CLB input pin node. */ t_physical_tile_type_ptr type = grid.get_physical_type({rr_graph.node_xlow(inode), rr_graph.node_ylow(inode), - rr_graph.node_layer(inode)}); + rr_graph.node_layer_low(inode)}); if (rr_graph.node_type(inode) != e_rr_type::IPIN) - return (false); + return false; int ipin = rr_graph.node_pin_num(inode); @@ -330,7 +330,7 @@ void check_rr_node(const RRGraphView& rr_graph, const DeviceGrid& grid, const VibDeviceGrid& vib_grid, const t_chan_width& chan_width, - const enum e_route_type route_type, + const e_route_type route_type, const int inode, bool is_flat) { //Make sure over-flow doesn't happen @@ -347,7 +347,8 @@ void check_rr_node(const RRGraphView& rr_graph, int xhigh = rr_graph.node_xhigh(rr_node); int ylow = rr_graph.node_ylow(rr_node); int yhigh = rr_graph.node_yhigh(rr_node); - int layer_num = rr_graph.node_layer(rr_node); + int layer_low = rr_graph.node_layer_low(rr_node); + int layer_high = rr_graph.node_layer_high(rr_node); int ptc_num = rr_graph.node_ptc_num(rr_node); int capacity = rr_graph.node_capacity(rr_node); RRIndexedDataId cost_index = rr_graph.node_cost_index(rr_node); @@ -362,9 +363,9 @@ void check_rr_node(const RRGraphView& rr_graph, "in check_rr_node: rr endpoints (%d,%d) and (%d,%d) are out of range.\n", xlow, ylow, xhigh, yhigh); } - if (layer_num < 0 || layer_num > grid_layers - 1) { + if (layer_low < 0 || layer_high > grid_layers - 1) { VPR_FATAL_ERROR(VPR_ERROR_ROUTE, - "in check_rr_node: rr endpoints layer_num (%d) is out of range.\n", layer_num); + "in check_rr_node: rr endpoints layer range (%d, %d) is out of range.\n", layer_low, layer_high); } if (ptc_num < 0) { @@ -378,7 +379,7 @@ void check_rr_node(const RRGraphView& rr_graph, } // Check that the segment is within the array and such. - t_physical_tile_type_ptr type = grid.get_physical_type({xlow, ylow, layer_num}); + t_physical_tile_type_ptr type = grid.get_physical_type({xlow, ylow, layer_low}); switch (rr_type) { case e_rr_type::SOURCE: @@ -398,7 +399,7 @@ void check_rr_node(const RRGraphView& rr_graph, "in check_rr_node: node %d (type %d) is at an illegal clb location (%d, %d).\n", inode, rr_type, xlow, ylow); } - vtr::Rect tile_bb = grid.get_tile_bb({xlow, ylow, layer_num}); + vtr::Rect tile_bb = grid.get_tile_bb({xlow, ylow, layer_low}); if (xlow < tile_bb.xmin() || ylow < tile_bb.ymin() || xhigh > tile_bb.xmax() || yhigh > tile_bb.ymax()) { VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "in check_rr_node: node %d (type %d) has endpoints (%d,%d) and (%d,%d), which is outside the bounds of the grid tile containing it.\n", inode, rr_type, xlow, ylow, xhigh, yhigh); @@ -441,7 +442,7 @@ void check_rr_node(const RRGraphView& rr_graph, break; case e_rr_type::CHANZ: - if (xhigh != xlow || yhigh != ylow || xhigh > grid_width - 1 || ylow < 1 || yhigh > grid_height - 1) { + if (xhigh != xlow || yhigh != ylow || xhigh > grid_width - 1 || yhigh > grid_height - 1) { VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "Error in check_rr_node: CHANZ out of range for endpoints (%d,%d) and (%d,%d)\n", xlow, ylow, xhigh, yhigh); } @@ -464,7 +465,7 @@ void check_rr_node(const RRGraphView& rr_graph, int mux_max_ptc = -1; const VibInf* vib_type = nullptr; if (vib_grid.get_num_layers() > 0) { - vib_type = vib_grid.get_vib(layer_num, xlow, ylow); + vib_type = vib_grid.get_vib(layer_low, xlow, ylow); } if (vib_type) { mux_max_ptc = (int)vib_type->get_first_stages().size(); diff --git a/libs/librrgraph/src/base/check_rr_graph.h b/libs/librrgraph/src/base/check_rr_graph.h index e436e92f247..8fd6dffbda9 100644 --- a/libs/librrgraph/src/base/check_rr_graph.h +++ b/libs/librrgraph/src/base/check_rr_graph.h @@ -39,6 +39,6 @@ void check_rr_node(const RRGraphView& rr_graph, const DeviceGrid& grid, const VibDeviceGrid& vib_grid, const t_chan_width& chan_width, - const enum e_route_type route_type, + const e_route_type route_type, const int inode, bool is_flat); diff --git a/libs/librrgraph/src/base/get_parallel_segs.cpp b/libs/librrgraph/src/base/get_parallel_segs.cpp index b9c0ad81a2c..9f3738d8959 100644 --- a/libs/librrgraph/src/base/get_parallel_segs.cpp +++ b/libs/librrgraph/src/base/get_parallel_segs.cpp @@ -6,7 +6,13 @@ std::vector get_parallel_segs(const std::vector& s bool keep_original_index /* = false */) { std::vector result; for (size_t i = 0; i < segment_inf.size(); ++i) { - if (segment_inf[i].parallel_axis == parallel_axis || segment_inf[i].parallel_axis == e_parallel_axis::BOTH_AXIS) { + e_parallel_axis seg_axis = segment_inf[i].parallel_axis; + + // Keep this segment if: + // 1. Its axis exactly matches the requested parallel_axis, OR + // 2. The requested axis is X or Y (not Z), and the segment is marked BOTH_AXIS. + if (seg_axis == parallel_axis + || (parallel_axis != e_parallel_axis::Z_AXIS && seg_axis == e_parallel_axis::BOTH_AXIS)) { result.push_back(segment_inf[i]); if (!keep_original_index) { result.back().seg_index = i; diff --git a/libs/librrgraph/src/base/get_parallel_segs.h b/libs/librrgraph/src/base/get_parallel_segs.h index 47e64a575e2..19fc84be1c7 100644 --- a/libs/librrgraph/src/base/get_parallel_segs.h +++ b/libs/librrgraph/src/base/get_parallel_segs.h @@ -4,11 +4,11 @@ #include "physical_types.h" /** - * @brief Returns segments aligned with a given axis, including BOTH_AXIS segments. + * @brief Filters segments aligned with a given axis and records index mappings. * - * Filters the unified segment list (`segment_inf`) to include only segments matching - * the specified `parallel_axis` or marked as `BOTH_AXIS`. Also populates `seg_index_map` - * to map unified indices to axis-specific ones. + * Iterates through the unified segment list (`segment_inf`) and selects segments + * whose `parallel_axis` matches the requested `parallel_axis`. If the requested + * axis is not `Z_AXIS`, segments marked as `BOTH_AXIS` are also included. * * @param segment_inf Unified list of all segments. * @param seg_index_map Map from unified to axis-specific segment indices. diff --git a/libs/librrgraph/src/base/rr_graph_builder.cpp b/libs/librrgraph/src/base/rr_graph_builder.cpp index b446108cc1d..1196d7fdc3a 100644 --- a/libs/librrgraph/src/base/rr_graph_builder.cpp +++ b/libs/librrgraph/src/base/rr_graph_builder.cpp @@ -38,32 +38,32 @@ vtr::vector>& RRGraphBuilder::node_ptc_storage() { void RRGraphBuilder::add_node_to_all_locs(RRNodeId node) { e_rr_type node_type = node_storage_.node_type(node); short node_ptc_num = node_storage_.node_ptc_num(node); - short node_layer = node_storage_.node_layer(node); for (int ix = node_storage_.node_xlow(node); ix <= node_storage_.node_xhigh(node); ix++) { for (int iy = node_storage_.node_ylow(node); iy <= node_storage_.node_yhigh(node); iy++) { - - switch (node_type) { - case e_rr_type::SOURCE: - case e_rr_type::SINK: - case e_rr_type::CHANZ: - case e_rr_type::CHANY: - case e_rr_type::CHANX: - node_lookup_.add_node(node, node_layer, ix, iy, node_type, node_ptc_num, TOTAL_2D_SIDES[0]); - break; - - case e_rr_type::OPIN: - case e_rr_type::IPIN: - for (const e_side side : TOTAL_2D_SIDES) { - if (node_storage_.is_node_on_specific_side(node, side)) { - node_lookup_.add_node(node,node_layer, ix, iy, node_type, node_ptc_num, side); + for (int iz = node_storage_.node_layer_low(node); iz <= node_storage_.node_layer_high(node); iz++) { + switch (node_type) { + case e_rr_type::SOURCE: + case e_rr_type::SINK: + case e_rr_type::CHANZ: + case e_rr_type::CHANY: + case e_rr_type::CHANX: + node_lookup_.add_node(node, iz, ix, iy, node_type, node_ptc_num, TOTAL_2D_SIDES[0]); + break; + + case e_rr_type::OPIN: + case e_rr_type::IPIN: + for (const e_side side : TOTAL_2D_SIDES) { + if (node_storage_.is_node_on_specific_side(node, side)) { + node_lookup_.add_node(node,iz, ix, iy, node_type, node_ptc_num, side); + } } - } - break; + break; - default: - VTR_LOG_ERROR("Invalid node type for node '%lu' in the routing resource graph file", size_t(node)); - break; + default: + VTR_LOG_ERROR("Invalid node type for node '%lu' in the routing resource graph file", size_t(node)); + break; + } } } } @@ -78,7 +78,8 @@ RRNodeId RRGraphBuilder::create_node(int layer, int x, int y, e_rr_type type, in node_storage_.emplace_back(); node_tilable_track_nums_.emplace_back(); RRNodeId new_node = RRNodeId(node_storage_.size() - 1); - node_storage_.set_node_layer(new_node, layer); + node_storage_.set_node_layer_low(new_node, layer); + node_storage_.set_node_layer_high(new_node, layer); node_storage_.set_node_type(new_node, type); node_storage_.set_node_coordinates(new_node, x, y, x, y); node_storage_.set_node_ptc_num(new_node, ptc); @@ -287,7 +288,8 @@ void RRGraphBuilder::add_node_track_num(RRNodeId node, vtr::Point node_o } void RRGraphBuilder::add_track_node_to_lookup(RRNodeId node) { - VTR_ASSERT_MSG(node_storage_.node_type(node) == e_rr_type::CHANX || node_storage_.node_type(node) == e_rr_type::CHANY, "Update track node look-up is only valid to CHANX/CHANY nodes"); + VTR_ASSERT_MSG(node_storage_.node_type(node) == e_rr_type::CHANX || node_storage_.node_type(node) == e_rr_type::CHANY, + "Update track node look-up is only valid to CHANX/CHANY nodes"); // Compute the track id based on the (x, y) coordinate size_t x_start = std::min(node_storage_.node_xlow(node), node_storage_.node_xhigh(node)); @@ -310,7 +312,7 @@ void RRGraphBuilder::add_track_node_to_lookup(RRNodeId node) { if (e_rr_type::CHANX == node_type || e_rr_type::CHANY == node_type) { ptc = (node_type == e_rr_type::CHANX) ? node_tilable_track_nums_[node][x - node_storage_.node_xlow(node)] : node_tilable_track_nums_[node][y - node_storage_.node_ylow(node)]; - node_lookup_.add_node(node, node_storage_.node_layer(node), x, y, node_type, ptc); + node_lookup_.add_node(node, node_storage_.node_layer_low(node), x, y, node_type, ptc); } } } diff --git a/libs/librrgraph/src/base/rr_graph_builder.h b/libs/librrgraph/src/base/rr_graph_builder.h index 1b520274ea5..5e386f19039 100644 --- a/libs/librrgraph/src/base/rr_graph_builder.h +++ b/libs/librrgraph/src/base/rr_graph_builder.h @@ -154,7 +154,7 @@ class RRGraphBuilder { * - valid geometry information: xlow/ylow/xhigh/yhigh * - a valid node type * - a valid node ptc number - * - a valid side (applicable to OPIN and IPIN nodes only + * - a valid side (applicable to OPIN and IPIN nodes only) */ void add_node_to_all_locs(RRNodeId node); @@ -238,11 +238,15 @@ class RRGraphBuilder { node_storage_.set_node_ptc_num(id, new_ptc_num); } - /** @brief set the layer number at which RRNodeId is located at */ - inline void set_node_layer(RRNodeId id, int layer){ - node_storage_.set_node_layer(id, layer); + /// @brief Set the low layer coordinate where the given node is located at. + inline void set_node_layer_low(RRNodeId id, int layer){ + node_storage_.set_node_layer_low(id, layer); } + /// @brief Set the high layer coordinate where the given node is located at. + inline void set_node_layer_high(RRNodeId id, int layer){ + node_storage_.set_node_layer_high(id, layer); + } /** @brief set_node_pin_num() is designed for logic blocks, which are IPIN and OPIN nodes */ inline void set_node_pin_num(RRNodeId id, int new_pin_num) { diff --git a/libs/librrgraph/src/base/rr_graph_storage.cpp b/libs/librrgraph/src/base/rr_graph_storage.cpp index f6d1899803e..a10b41b35e5 100644 --- a/libs/librrgraph/src/base/rr_graph_storage.cpp +++ b/libs/librrgraph/src/base/rr_graph_storage.cpp @@ -648,12 +648,16 @@ const char* t_rr_graph_storage::node_side_string(RRNodeId id) const { return TOTAL_2D_SIDE_STRINGS[side]; } } - /* Not found, return an invalid string*/ + // Not found, return an invalid string return TOTAL_2D_SIDE_STRINGS[NUM_2D_SIDES]; } -void t_rr_graph_storage::set_node_layer(RRNodeId id, short layer) { - node_layer_[id] = layer; +void t_rr_graph_storage::set_node_layer_low(RRNodeId id, short layer) { + node_layer_low_[id] = layer; +} + +void t_rr_graph_storage::set_node_layer_high(RRNodeId id, short layer) { + node_layer_high_[id] = layer; } void t_rr_graph_storage::set_node_ptc_num(RRNodeId id, int new_ptc_num) { @@ -871,7 +875,8 @@ t_rr_graph_view t_rr_graph_storage::view() const { vtr::make_const_array_view_id(node_ptc_), vtr::make_const_array_view_id(node_first_edge_), vtr::make_const_array_view_id(node_fan_in_), - vtr::make_const_array_view_id(node_layer_), + vtr::make_const_array_view_id(node_layer_low_), + vtr::make_const_array_view_id(node_layer_high_), node_name_, vtr::make_const_array_view_id(edge_src_node_), vtr::make_const_array_view_id(edge_dest_node_), diff --git a/libs/librrgraph/src/base/rr_graph_storage.h b/libs/librrgraph/src/base/rr_graph_storage.h index fbc59080bb5..b3ba964de80 100644 --- a/libs/librrgraph/src/base/rr_graph_storage.h +++ b/libs/librrgraph/src/base/rr_graph_storage.h @@ -244,12 +244,14 @@ class t_rr_graph_storage { return node_fan_in_[id]; } - /** @brief Find the layer number that RRNodeId is located at. - * it is zero if the FPGA only has one die. - * The layer number start from the base die (base die: 0, the die above it: 1, etc.) - */ - short node_layer(RRNodeId id) const{ - return node_layer_[id]; + /// @brief Returns the lowest layer where the given node is located at. + short node_layer_low(RRNodeId id) const { + return node_layer_low_[id]; + } + + /// @brief Returns the highest layer where the given node is located at. + short node_layer_high(RRNodeId id) const { + return node_layer_high_[id]; } /** @@ -540,8 +542,11 @@ class t_rr_graph_storage { node_ptc_.reserve(node_storage_.capacity()); node_ptc_.resize(node_storage_.size()); - node_layer_.reserve(node_storage_.capacity()); - node_layer_.resize(node_storage_.size()); + node_layer_low_.reserve(node_storage_.capacity()); + node_layer_low_.resize(node_storage_.size()); + + node_layer_high_.reserve(node_storage_.capacity()); + node_layer_high_.resize(node_storage_.size()); if (is_tileable_) { node_bend_start_.reserve(node_storage_.capacity()); @@ -558,7 +563,8 @@ class t_rr_graph_storage { VTR_ASSERT(!edges_read_); node_storage_.reserve(size); node_ptc_.reserve(size); - node_layer_.reserve(size); + node_layer_low_.reserve(size); + node_layer_high_.reserve(size); if (is_tileable_) { node_bend_start_.reserve(size); node_bend_end_.reserve(size); @@ -571,7 +577,8 @@ class t_rr_graph_storage { VTR_ASSERT(!edges_read_); node_storage_.resize(size); node_ptc_.resize(size); - node_layer_.resize(size); + node_layer_low_.resize(size); + node_layer_high_.resize(size); if (is_tileable_) { node_bend_start_.resize(size); node_bend_end_.resize(size); @@ -596,7 +603,8 @@ class t_rr_graph_storage { node_ptc_.clear(); node_first_edge_.clear(); node_fan_in_.clear(); - node_layer_.clear(); + node_layer_low_.clear(); + node_layer_high_.clear(); node_bend_start_.clear(); node_bend_end_.clear(); node_name_.clear(); @@ -634,7 +642,8 @@ class t_rr_graph_storage { node_ptc_.shrink_to_fit(); node_first_edge_.shrink_to_fit(); node_fan_in_.shrink_to_fit(); - node_layer_.shrink_to_fit(); + node_layer_low_.shrink_to_fit(); + node_layer_high_.shrink_to_fit(); node_bend_start_.shrink_to_fit(); node_bend_end_.shrink_to_fit(); @@ -650,7 +659,8 @@ class t_rr_graph_storage { VTR_ASSERT(!edges_read_); node_storage_.emplace_back(); node_ptc_.emplace_back(); - node_layer_.emplace_back(); + node_layer_low_.emplace_back(); + node_layer_high_.emplace_back(); if (is_tileable_) { node_bend_start_.emplace_back(); node_bend_end_.emplace_back(); @@ -676,7 +686,8 @@ class t_rr_graph_storage { void set_node_type(RRNodeId id, e_rr_type new_type); void set_node_name(RRNodeId id, const std::string& new_name); void set_node_coordinates(RRNodeId id, short x1, short y1, short x2, short y2); - void set_node_layer(RRNodeId id, short layer); + void set_node_layer_low(RRNodeId id, short layer); + void set_node_layer_high(RRNodeId id, short layer); void set_node_cost_index(RRNodeId, RRIndexedDataId new_cost_index); void set_node_bend_start(RRNodeId id, size_t bend_start); void set_node_bend_end(RRNodeId id, size_t bend_end); @@ -902,13 +913,15 @@ class t_rr_graph_storage { /** @brief Fan in counts for each RR node. */ vtr::vector node_fan_in_; - /** @brief - * Layer number that each RR node is located at - * Layer number refers to the die that the node belongs to. The layer number of base die is zero and die above it one, etc. - * This data is also considered as a hot data since it is used in inner loop of router, but since it didn't fit nicely into t_rr_node_data due to alignment issues, we had to store it - *in a separate vector. - */ - vtr::vector node_layer_; + // Layer number refers to the die that the node belongs to. + // The layer number of base die is zero and die above it one, etc. + // This data is also considered as a hot data since it is used in inner loop of router, + // but since it didn't fit nicely into t_rr_node_data due to alignment issues, we had to store it in a separate vector. + + /// @brief The lowest layer number where a given node is located at. + vtr::vector node_layer_low_; + /// @brief The highest layer number where a given node is located at. + vtr::vector node_layer_high_; /** * @brief Stores the assigned names for the RRNode IDs. @@ -1012,7 +1025,8 @@ class t_rr_graph_view { const vtr::array_view_id node_ptc, const vtr::array_view_id node_first_edge, const vtr::array_view_id node_fan_in, - const vtr::array_view_id node_layer, + const vtr::array_view_id node_layer_low, + const vtr::array_view_id node_layer_high, const std::unordered_map& node_name, const vtr::array_view_id edge_src_node, const vtr::array_view_id edge_dest_node, @@ -1024,7 +1038,8 @@ class t_rr_graph_view { , node_ptc_(node_ptc) , node_first_edge_(node_first_edge) , node_fan_in_(node_fan_in) - , node_layer_(node_layer) + , node_layer_low_(node_layer_low) + , node_layer_high_(node_layer_high) , node_name_(node_name) , edge_src_node_(edge_src_node) , edge_dest_node_(edge_dest_node) @@ -1091,14 +1106,14 @@ class t_rr_graph_view { return node_fan_in_[id]; } - /** - * @brief Retrieve the layer (die) number where the given RRNodeId is located. - * - * @param id The RRNodeId for which to retrieve the layer number. - * @return The layer number (die) where the RRNodeId is located. - */ - short node_layer(RRNodeId id) const{ - return node_layer_[id]; + /// @brief Retrieve the lowest layer (die) number where the given RRNodeId is located. + char node_layer_low(RRNodeId id) const { + return node_layer_low_[id]; + } + + /// @brief Retrieve the highest layer (die) number where the given RRNodeId is located. + char node_layer_high(RRNodeId id) const { + return node_layer_high_[id]; } /** @@ -1230,7 +1245,8 @@ class t_rr_graph_view { vtr::array_view_id node_ptc_; vtr::array_view_id node_first_edge_; vtr::array_view_id node_fan_in_; - vtr::array_view_id node_layer_; + vtr::array_view_id node_layer_low_; + vtr::array_view_id node_layer_high_; const std::unordered_map& node_name_; vtr::array_view_id edge_src_node_; vtr::array_view_id edge_dest_node_; diff --git a/libs/librrgraph/src/base/rr_graph_type.h b/libs/librrgraph/src/base/rr_graph_type.h index a3362b248ef..bcdb6c48f54 100644 --- a/libs/librrgraph/src/base/rr_graph_type.h +++ b/libs/librrgraph/src/base/rr_graph_type.h @@ -38,12 +38,12 @@ enum class e_graph_type { * * This map is used to translate indices from the unified segment vector * (`segment_inf` in the device context, which contains all segments regardless of axis) - * to axis-specific segment vectors (`segment_inf_x` or `segment_inf_y`), based on the - * segment's parallel axis. + * to axis-specific segment vectors (`segment_inf_x` or `segment_inf_y` or `segment_inf_z`), + * based on the segment's parallel axis. * * Each entry maps a unified segment index to a pair containing: * - The index in the corresponding axis-specific segment vector - * - The axis of the segment (X or Y) + * - The axis of the segment (X/Y/Z) * * @see get_parallel_segs for more details. */ diff --git a/libs/librrgraph/src/base/rr_graph_utils.cpp b/libs/librrgraph/src/base/rr_graph_utils.cpp index 614961c4c67..dcafc96fc55 100644 --- a/libs/librrgraph/src/base/rr_graph_utils.cpp +++ b/libs/librrgraph/src/base/rr_graph_utils.cpp @@ -6,7 +6,7 @@ #include "rr_graph_view.h" #include "librrgraph_types.h" -/* +/** * @brief Walk backwards from origin SINK, and insert all cluster-edge IPINs to which origin is connected to sink_ipins * * @param rr_graph @@ -154,8 +154,9 @@ void rr_set_sink_locs(const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_buil for (size_t node = 0; node < rr_graph.num_nodes(); ++node) { auto node_id = RRNodeId(node); - if (rr_graph.node_type((RRNodeId)node_id) != e_rr_type::SINK) + if (rr_graph.node_type(node_id) != e_rr_type::SINK) { continue; + } int node_xlow = rr_graph.node_xlow(node_id); int node_ylow = rr_graph.node_ylow(node_id); @@ -164,13 +165,16 @@ void rr_set_sink_locs(const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_buil // Skip "0x0" nodes; either the tile is 1x1, or we have seen the node on a previous call of this function // and its new location has already been set - if ((node_xhigh - node_xlow) == 0 && (node_yhigh - node_ylow) == 0) + if ((node_xhigh - node_xlow) == 0 && (node_yhigh - node_ylow) == 0) { continue; + } + + const int node_layer = rr_graph.node_layer_low(node_id); + VTR_ASSERT(node_layer == rr_graph.node_layer_high(node_id)); - int node_layer = rr_graph.node_layer(node_id); int node_ptc = rr_graph.node_ptc_num(node_id); - t_physical_tile_loc tile_loc = {node_xlow, node_ylow, node_layer}; + t_physical_tile_loc tile_loc{node_xlow, node_ylow, node_layer}; t_physical_tile_type_ptr tile_type = grid.get_physical_type(tile_loc); vtr::Rect tile_bb = grid.get_tile_bb(tile_loc); @@ -240,8 +244,8 @@ bool inter_layer_connections_limited_to_opin(const RRGraphView& rr_graph) { for (const RRNodeId from_node : rr_graph.nodes()) { for (t_edge_size edge : rr_graph.edges(from_node)) { RRNodeId to_node = rr_graph.edge_sink_node(from_node, edge); - int from_layer = rr_graph.node_layer(from_node); - int to_layer = rr_graph.node_layer(to_node); + int from_layer = rr_graph.node_layer_low(from_node); + int to_layer = rr_graph.node_layer_low(to_node); if (from_layer != to_layer) { if (rr_graph.node_type(from_node) != e_rr_type::OPIN) { @@ -272,6 +276,11 @@ bool chanx_chany_nodes_are_adjacent(const RRGraphView& rr_graph, RRNodeId node1, RRNodeId chanx_node = node1; RRNodeId chany_node = node2; + // If CHANX and CHANY nodes are not in the same layer, they are not adjacent + if (rr_graph.node_layer_low(chanx_node) != rr_graph.node_layer_low(chany_node)) { + return false; + } + // Check vertical (Y) adjacency if (rr_graph.node_ylow(chany_node) > rr_graph.node_ylow(chanx_node) + 1 || rr_graph.node_yhigh(chany_node) < rr_graph.node_ylow(chanx_node)) { @@ -332,13 +341,11 @@ bool chan_same_type_are_adjacent(const RRGraphView& rr_graph, RRNodeId node1, RR int xhigh1 = rr_graph.node_xhigh(node1); int ylow1 = rr_graph.node_ylow(node1); int yhigh1 = rr_graph.node_yhigh(node1); - int layer1 = rr_graph.node_layer(node1); int xlow2 = rr_graph.node_xlow(node2); int xhigh2 = rr_graph.node_xhigh(node2); int ylow2 = rr_graph.node_ylow(node2); int yhigh2 = rr_graph.node_yhigh(node2); - int layer2 = rr_graph.node_layer(node2); if (type == e_rr_type::CHANX) { if (ylow1 != ylow2) { @@ -376,8 +383,7 @@ bool chan_same_type_are_adjacent(const RRGraphView& rr_graph, RRNodeId node1, RR } else if (type == e_rr_type::CHANZ) { // Same X/Y span, adjacent layer bool same_xy = (xlow1 == xlow2 && xhigh1 == xhigh2 && ylow1 == ylow2 && yhigh1 == yhigh2); - bool adjacent_layer = std::abs(layer1 - layer2) == 1; - return same_xy && adjacent_layer; + return same_xy; } else { VTR_ASSERT_MSG(false, "Unexpected RR node type in chan_same_type_are_adjacent().\n"); } diff --git a/libs/librrgraph/src/base/rr_graph_view.h b/libs/librrgraph/src/base/rr_graph_view.h index 4fb23504939..ca825d15642 100644 --- a/libs/librrgraph/src/base/rr_graph_view.h +++ b/libs/librrgraph/src/base/rr_graph_view.h @@ -25,7 +25,10 @@ * 5. A short (metal connection). * * - * @note Despite the RRGraph containing millions of edges, there are only a few switch types. Therefore, all switch details, including R and C, are stored using a flyweight pattern (rr_switch_inf) rather than being directly embedded in the edge-related data of the RRGraph. Each edge stores the ID of its associated switch for easy lookup. + * @note Despite the RRGraph containing millions of edges, there are only a few switch types. + * Therefore, all switch details, including R and C, are stored using a flyweight pattern (rr_switch_inf) + * rather than being directly embedded in the edge-related data of the RRGraph. + * Each edge stores the ID of its associated switch for easy lookup. * * * \internal @@ -225,10 +228,14 @@ class RRGraphView { return node_storage_.node_yhigh(node); } - /** @brief Return the layer num of a specified node. - */ - inline short node_layer(RRNodeId node) const { - return node_storage_.node_layer(node); + /// @brief Returns the highest layer where a node is located at. + inline char node_layer_high(RRNodeId node) const { + return node_storage_.node_layer_high(node); + } + + /// @brief Returns the lowest layer where a node is located at. + inline char node_layer_low(RRNodeId node) const { + return node_storage_.node_layer_low(node); } /** @@ -368,7 +375,6 @@ class RRGraphView { std::string coordinate_string = node_type_string(node); //write the component's type as a routing resource node coordinate_string += ":" + std::to_string(size_t(node)) + " "; //add the index of the routing resource node - int node_layer_num = node_layer(node); if (node_type(node) == e_rr_type::OPIN || node_type(node) == e_rr_type::IPIN) { coordinate_string += "side: ("; //add the side of the routing resource node for (const e_side& node_side : TOTAL_2D_SIDES) { @@ -382,12 +388,12 @@ class RRGraphView { // and the end to the lower coordinate start_x = " (" + std::to_string(node_xhigh(node)) + ","; //start and end coordinates are the same for OPINs and IPINs start_y = std::to_string(node_yhigh(node)) + ","; - start_layer_str = std::to_string(node_layer_num) + ")"; + start_layer_str = std::to_string(node_layer_low(node)) + ")"; } else if (node_type(node) == e_rr_type::SOURCE || node_type(node) == e_rr_type::SINK) { // For SOURCE and SINK the starting and ending coordinate are identical, so just use start start_x = " (" + std::to_string(node_xhigh(node)) + ","; start_y = std::to_string(node_yhigh(node)) + ","; - start_layer_str = std::to_string(node_layer_num) + ")"; + start_layer_str = std::to_string(node_layer_low(node)) + ")"; } else if (node_type(node) == e_rr_type::CHANX || node_type(node) == e_rr_type::CHANY || node_type(node) == e_rr_type::CHANZ) { //for channels, we would like to describe the component with segment specific information RRIndexedDataId cost_index = node_cost_index(node); int seg_index = rr_indexed_data_[cost_index].seg_index; @@ -401,19 +407,19 @@ class RRGraphView { start_x = " (" + std::to_string(node_xhigh(node)) + ","; //start coordinates have large value start_y = std::to_string(node_yhigh(node)) + ","; - start_layer_str = std::to_string(node_layer_num) + ")"; + start_layer_str = std::to_string(node_layer_high(node)) + ")"; end_x = " (" + std::to_string(node_xlow(node)) + ","; //end coordinates have smaller value end_y = std::to_string(node_ylow(node)) + ","; - end_layer_str = std::to_string(node_layer_num) + ")"; + end_layer_str = std::to_string(node_layer_low(node)) + ")"; } else { // signal travels in increasing direction, stays at same point, or can travel both directions start_x = " (" + std::to_string(node_xlow(node)) + ","; //start coordinates have smaller value start_y = std::to_string(node_ylow(node)) + ","; - start_layer_str = std::to_string(node_layer_num) + ")"; + start_layer_str = std::to_string(node_layer_low(node)) + ")"; end_x = " (" + std::to_string(node_xhigh(node)) + ","; //end coordinates have larger value end_y = std::to_string(node_yhigh(node)) + ","; - end_layer_str = std::to_string(node_layer_num) + ")"; //layer number + end_layer_str = std::to_string(node_layer_high(node)) + ")"; //layer number if (node_direction(node) == Direction::BIDIR) { arrow = " <->"; //indicate that signal can travel both direction } diff --git a/libs/librrgraph/src/base/rr_node.cpp b/libs/librrgraph/src/base/rr_node.cpp index 4362d624ef2..629647dfe2e 100644 --- a/libs/librrgraph/src/base/rr_node.cpp +++ b/libs/librrgraph/src/base/rr_node.cpp @@ -1,11 +1,11 @@ #include "rr_node.h" #include "rr_graph_storage.h" -//Returns the max 'length' over the x or y direction +//Returns the max 'length' over the x or y or z direction short t_rr_node::length() const { - return std::max( - storage_->node_yhigh(id_) - storage_->node_ylow(id_), - storage_->node_xhigh(id_) - storage_->node_xlow(id_)); + return std::max({storage_->node_yhigh(id_) - storage_->node_ylow(id_), + storage_->node_xhigh(id_) - storage_->node_xlow(id_), + storage_->node_layer_high(id_) - storage_->node_layer_low(id_)}); } diff --git a/libs/librrgraph/src/base/rr_node.h b/libs/librrgraph/src/base/rr_node.h index a4e50a118c3..e44926013e8 100644 --- a/libs/librrgraph/src/base/rr_node.h +++ b/libs/librrgraph/src/base/rr_node.h @@ -20,7 +20,7 @@ // The RR graph has since been refactored into the t_rr_graph_storage object. // To prevent requiring all callsites where the std::vector to be // changed at once, t_rr_graph_storage implements an interface that appears -// similiar to std::vector, even though the underlying storage is +// similar to std::vector, even though the underlying storage is // no longer a array of t_rr_node's. // // The t_rr_node class forwards all data accesses to t_rr_graph_storage, and diff --git a/libs/librrgraph/src/base/rr_node_types.h b/libs/librrgraph/src/base/rr_node_types.h index 1cce4542f18..963b8c25d18 100644 --- a/libs/librrgraph/src/base/rr_node_types.h +++ b/libs/librrgraph/src/base/rr_node_types.h @@ -29,10 +29,10 @@ enum class e_rr_type : unsigned char { OPIN, /// @@ -275,8 +275,8 @@ constexpr const char *atok_lookup_t_grid_loc[] = {"block_type_id", "height_offse enum class gtok_t_grid_locs {GRID_LOC}; constexpr const char *gtok_lookup_t_grid_locs[] = {"grid_loc"}; -enum class atok_t_node_loc {LAYER, PTC, SIDE, XHIGH, XLOW, YHIGH, YLOW}; -constexpr const char *atok_lookup_t_node_loc[] = {"layer", "ptc", "side", "xhigh", "xlow", "yhigh", "ylow"}; +enum class atok_t_node_loc {LAYER_HIGH, LAYER_LOW, PTC, SIDE, XHIGH, XLOW, YHIGH, YLOW}; +constexpr const char *atok_lookup_t_node_loc[] = {"layer_high", "layer_low", "ptc", "side", "xhigh", "xlow", "yhigh", "ylow"}; enum class atok_t_node_timing {C, R}; @@ -1156,14 +1156,6 @@ inline atok_t_node_loc lex_attr_t_node_loc(const char *in, const std::function.").c_str()); @@ -1790,6 +1813,24 @@ inline enum_pin_type lex_enum_pin_type(const char *in, bool throw_on_invalid, co inline enum_node_type lex_enum_node_type(const char *in, bool throw_on_invalid, const std::function * report_error){ unsigned int len = strlen(in); switch(len){ + case 3: + switch(in[0]){ + case onechar('M', 0, 8): + switch(in[1]){ + case onechar('U', 0, 8): + switch(in[2]){ + case onechar('X', 0, 8): + return enum_node_type::MUX; + break; + default: break; + } + break; + default: break; + } + break; + default: break; + } + break; case 4: switch(*((triehash_uu32*)&in[0])){ case onechar('I', 0, 32) | onechar('P', 8, 32) | onechar('I', 16, 32) | onechar('N', 24, 32): @@ -2464,14 +2505,17 @@ inline void load_grid_loc_required_attributes(const pugi::xml_node &root, int * } inline void load_node_loc_required_attributes(const pugi::xml_node &root, int * xhigh, int * xlow, int * yhigh, int * ylow, const std::function * report_error){ - std::bitset<7> astate = 0; + std::bitset<8> astate = 0; for(pugi::xml_attribute attr = root.first_attribute(); attr; attr = attr.next_attribute()){ atok_t_node_loc in = lex_attr_t_node_loc(attr.name(), report_error); if(astate[(int)in] == 0) astate[(int)in] = 1; else noreturn_report(report_error, ("Duplicate attribute " + std::string(attr.name()) + " in .").c_str()); switch(in){ - case atok_t_node_loc::LAYER: - /* Attribute layer set after element init */ + case atok_t_node_loc::LAYER_HIGH: + /* Attribute layer_high set after element init */ + break; + case atok_t_node_loc::LAYER_LOW: + /* Attribute layer_low set after element init */ break; case atok_t_node_loc::PTC: /* Attribute ptc set after element init */ @@ -2494,7 +2538,7 @@ inline void load_node_loc_required_attributes(const pugi::xml_node &root, int * default: break; /* Not possible. */ } } - std::bitset<7> test_astate = astate | std::bitset<7>(0b0000101); + std::bitset<8> test_astate = astate | std::bitset<8>(0b00001011); if(!test_astate.all()) attr_error(test_astate, atok_lookup_t_node_loc, report_error); } @@ -3409,8 +3453,11 @@ inline void load_node_loc(const pugi::xml_node &root, T &out, Context &context, for(pugi::xml_attribute attr = root.first_attribute(); attr; attr = attr.next_attribute()){ atok_t_node_loc in = lex_attr_t_node_loc(attr.name(), report_error); switch(in){ - case atok_t_node_loc::LAYER: - out.set_node_loc_layer(load_int(attr.value(), report_error), context); + case atok_t_node_loc::LAYER_HIGH: + out.set_node_loc_layer_high(load_int(attr.value(), report_error), context); + break; + case atok_t_node_loc::LAYER_LOW: + out.set_node_loc_layer_low(load_int(attr.value(), report_error), context); break; case atok_t_node_loc::PTC: out.set_node_loc_ptc(attr.value(), context); @@ -4152,7 +4199,8 @@ inline void write_node(T &in, std::ostream &os, Context &context){ { auto child_context = in.get_node_loc(context); os << " @@ -230,6 +230,8 @@ inline enum_node_type conv_enum_node_type(ucap::NodeType e, const std::function< return enum_node_type::OPIN; case ucap::NodeType::IPIN: return enum_node_type::IPIN; + case ucap::NodeType::MUX: + return enum_node_type::MUX; default: (*report_error)("Unknown enum_node_type"); throw std::runtime_error("Unreachable!"); @@ -254,6 +256,8 @@ inline ucap::NodeType conv_to_enum_node_type(enum_node_type e) { return ucap::NodeType::OPIN; case enum_node_type::IPIN: return ucap::NodeType::IPIN; + case enum_node_type::MUX: + return ucap::NodeType::MUX; default: throw std::runtime_error("Unknown enum_node_type"); } @@ -765,7 +769,8 @@ inline void load_node_loc_capnp_type(const ucap::NodeLoc::Reader &root, T &out, (void)report_error; (void)stack; - out.set_node_loc_layer(root.getLayer(), context); + out.set_node_loc_layer_high(root.getLayerHigh(), context); + out.set_node_loc_layer_low(root.getLayerLow(), context); out.set_node_loc_ptc(root.getPtc().cStr(), context); out.set_node_loc_side(conv_enum_loc_side(root.getSide(), report_error), context); } @@ -1223,7 +1228,8 @@ inline void write_node_capnp_type(T &in, ucap::Node::Builder &root, Context &con { auto child_context = in.get_node_loc(context); auto node_loc = root.initLoc(); - node_loc.setLayer(in.get_node_loc_layer(child_context)); + node_loc.setLayerHigh(in.get_node_loc_layer_high(child_context)); + node_loc.setLayerLow(in.get_node_loc_layer_low(child_context)); node_loc.setPtc(in.get_node_loc_ptc(child_context)); if((bool)in.get_node_loc_side(child_context)) node_loc.setSide(conv_to_enum_loc_side(in.get_node_loc_side(child_context))); diff --git a/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_interface.h b/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_interface.h index 7050b45c9cd..bbaae2e5e5f 100644 --- a/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_interface.h +++ b/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_interface.h @@ -4,9 +4,9 @@ * https://github.com/duck2/uxsdcxx * Modify only if your build process doesn't involve regenerating this file. * - * Cmdline: uxsdcxx/uxsdcxx.py /home/soheil/vpr_repos/libs/librrgraph/src/io/rr_graph.xsd - * Input file: /home/soheil/vpr_repos/libs/librrgraph/src/io/rr_graph.xsd - * md5sum of input file: 5d51b89242fe6e463629ac43a72e4606 + * Cmdline: uxsdcxx/uxsdcxx.py /home/soheil/vtr/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd + * Input file: /home/soheil/vtr/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd + * md5sum of input file: 040903603053940a1b24392c38663b59 */ #include @@ -371,7 +371,8 @@ class RrGraphBase { /** Generated for complex type "node_loc": * - * + * + * * * * @@ -380,8 +381,10 @@ class RrGraphBase { * * */ - virtual inline int get_node_loc_layer(typename ContextTypes::NodeLocReadContext &ctx) = 0; - virtual inline void set_node_loc_layer(int layer, typename ContextTypes::NodeLocWriteContext &ctx) = 0; + virtual inline int get_node_loc_layer_high(typename ContextTypes::NodeLocReadContext &ctx) = 0; + virtual inline void set_node_loc_layer_high(int layer_high, typename ContextTypes::NodeLocWriteContext &ctx) = 0; + virtual inline int get_node_loc_layer_low(typename ContextTypes::NodeLocReadContext &ctx) = 0; + virtual inline void set_node_loc_layer_low(int layer_low, typename ContextTypes::NodeLocWriteContext &ctx) = 0; virtual inline const char * get_node_loc_ptc(typename ContextTypes::NodeLocReadContext &ctx) = 0; virtual inline void set_node_loc_ptc(const char * ptc, typename ContextTypes::NodeLocWriteContext &ctx) = 0; virtual inline enum_loc_side get_node_loc_side(typename ContextTypes::NodeLocReadContext &ctx) = 0; diff --git a/libs/librrgraph/src/io/rr_graph.xsd b/libs/librrgraph/src/io/rr_graph.xsd index bff9f16c3f4..0d513a34924 100644 --- a/libs/librrgraph/src/io/rr_graph.xsd +++ b/libs/librrgraph/src/io/rr_graph.xsd @@ -277,7 +277,8 @@ - + + diff --git a/libs/librrgraph/src/io/rr_graph_reader.cpp b/libs/librrgraph/src/io/rr_graph_reader.cpp index 875587695b8..ff0f8b9e4ae 100644 --- a/libs/librrgraph/src/io/rr_graph_reader.cpp +++ b/libs/librrgraph/src/io/rr_graph_reader.cpp @@ -65,8 +65,8 @@ void load_rr_file(RRGraphBuilder* rr_graph_builder, e_graph_type graph_type, const t_arch* arch, t_chan_width* chan_width, - const enum e_base_cost_type base_cost_type, - int* wire_to_rr_ipin_switch, + const e_base_cost_type base_cost_type, + RRSwitchId* wire_to_rr_ipin_switch, int* wire_to_rr_ipin_switch_between_dice, const char* read_rr_graph_name, std::string* loaded_rr_graph_filename, diff --git a/libs/librrgraph/src/io/rr_graph_reader.h b/libs/librrgraph/src/io/rr_graph_reader.h index 038addb22fc..1f3efbe2ae9 100644 --- a/libs/librrgraph/src/io/rr_graph_reader.h +++ b/libs/librrgraph/src/io/rr_graph_reader.h @@ -22,8 +22,8 @@ void load_rr_file(RRGraphBuilder* rr_graph_builder, e_graph_type graph_type, const t_arch* arch, t_chan_width* chan_width, - const enum e_base_cost_type base_cost_type, - int* wire_to_rr_ipin_switch, + const e_base_cost_type base_cost_type, + RRSwitchId* wire_to_rr_ipin_switch, int* wire_to_rr_ipin_switch_between_dice, const char* read_rr_graph_name, std::string* loaded_rr_graph_filename, diff --git a/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h b/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h index ea09e79a818..f8a4f36fda0 100644 --- a/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h +++ b/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h @@ -274,7 +274,7 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { RrGraphSerializer( const e_graph_type graph_type, const enum e_base_cost_type base_cost_type, - int* wire_to_rr_ipin_switch, + RRSwitchId* wire_to_rr_ipin_switch, int* wire_to_rr_ipin_switch_between_dice, bool do_check_rr_graph, const char* read_rr_graph_name, @@ -326,7 +326,7 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { , is_flat_(is_flat) { // Initialize internal data init_side_map(); - init_segment_inf_x_y(); + init_segment_inf_xyz(); curr_tmp_block_type_id = -1; curr_tmp_height_offset = -1; curr_tmp_width_offset = -1; @@ -391,9 +391,9 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { /** * @brief This function separates the segments in segment_inf_ based on whether their parallel axis - * is X or Y, and it stores them in segment_inf_x_ and segment_inf_y_. + * is X or Y or Z, and it stores them in segment_inf_x_ and segment_inf_y_ and segment_inf_z_. */ - void init_segment_inf_x_y(){ + void init_segment_inf_xyz(){ /* Create a temp copy to convert from vtr::vector to std::vector * This is required because the ``alloc_and_load_rr_indexed_data()`` function supports only std::vector data @@ -410,7 +410,7 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { t_unified_to_parallel_seg_index seg_index_map; segment_inf_x_ = get_parallel_segs(rr_segs, seg_index_map, e_parallel_axis::X_AXIS); segment_inf_y_ = get_parallel_segs(rr_segs, seg_index_map, e_parallel_axis::Y_AXIS); - + segment_inf_z_ = get_parallel_segs(rr_segs, seg_index_map, e_parallel_axis::Z_AXIS); } /** @@ -423,13 +423,16 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { int find_segment_index_along_axis(int segment_id, e_parallel_axis axis) const { const std::vector* segment_inf_vec_ptr; - if (axis == e_parallel_axis::X_AXIS) + if (axis == e_parallel_axis::X_AXIS) { segment_inf_vec_ptr = &segment_inf_x_; - else + } else if (axis == e_parallel_axis::Y_AXIS) { segment_inf_vec_ptr = &segment_inf_y_; + } else { + segment_inf_vec_ptr = &segment_inf_z_; + } - for(std::vector::size_type i=0; i < (*segment_inf_vec_ptr).size(); i++){ - if((*segment_inf_vec_ptr)[i].seg_index == segment_id) + for (size_t i = 0; i < segment_inf_vec_ptr->size(); i++){ + if ((*segment_inf_vec_ptr)[i].seg_index == segment_id) return static_cast(i); } @@ -699,7 +702,8 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { rr_graph_builder_->set_node_coordinates(node_id, xlow, ylow, xhigh, yhigh); // We set the layer num 0 - If it is specified in the XML, it will be overwritten - rr_graph_builder_->set_node_layer(node_id, 0); + rr_graph_builder_->set_node_layer_low(node_id, 0); + rr_graph_builder_->set_node_layer_high(node_id, 0); return inode; } @@ -717,8 +721,11 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { temp_string_ = rr_graph_builder_->node_ptc_nums_to_string(node.id()); return temp_string_.c_str(); } - inline int get_node_loc_layer(const t_rr_node& node) final { - return rr_graph_->node_layer(node.id()); + inline int get_node_loc_layer_low(const t_rr_node& node) final { + return rr_graph_->node_layer_low(node.id()); + } + inline int get_node_loc_layer_high(const t_rr_node& node) final { + return rr_graph_->node_layer_high(node.id()); } inline int get_node_loc_xhigh(const t_rr_node& node) final { return rr_graph_->node_xhigh(node.id()); @@ -733,13 +740,23 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { return rr_graph_->node_ylow(node.id()); } - inline void set_node_loc_layer(int layer_num, int& inode) final { - auto node = (*rr_nodes_)[inode]; + inline void set_node_loc_layer_low(int layer_num, int& inode) final { + const t_rr_node& node = (*rr_nodes_)[inode]; RRNodeId node_id = node.id(); + // Currently, we only support two layers + VTR_ASSERT(layer_num >= 0 && layer_num <= 1); + rr_graph_builder_->set_node_layer_low(node_id, layer_num); + } + + inline void set_node_loc_layer_high(int layer_num, int& inode) final { + const t_rr_node& node = (*rr_nodes_)[inode]; + RRNodeId node_id = node.id(); - VTR_ASSERT(layer_num >= 0); - rr_graph_builder_->set_node_layer(node_id, layer_num); + // Currently, we only support two layers + VTR_ASSERT(layer_num >= 0 && layer_num <= 1); + VTR_ASSERT(layer_num >= 0 && layer_num <= 1); + rr_graph_builder_->set_node_layer_high(node_id, layer_num); } inline void set_node_loc_side(uxsd::enum_loc_side side, int& inode) final { @@ -833,9 +850,8 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { rr_graph_builder_->set_node_cost_index(node_id, RRIndexedDataId(CHANX_COST_INDEX_START + segment_inf_x_.size() + seg_ind_y)); seg_index_[rr_graph.node_cost_index(node.id())] = segment_id; } else if (rr_graph.node_type(node.id()) == e_rr_type::CHANZ) { - // TODO: Don't use CHANX info - int seg_ind_z = find_segment_index_along_axis(segment_id, e_parallel_axis::X_AXIS); - rr_graph_builder_->set_node_cost_index(node_id, RRIndexedDataId(CHANX_COST_INDEX_START + seg_ind_z)); + int seg_ind_z = find_segment_index_along_axis(segment_id, e_parallel_axis::Z_AXIS); + rr_graph_builder_->set_node_cost_index(node_id, RRIndexedDataId(CHANX_COST_INDEX_START + segment_inf_x_.size() + segment_inf_y_.size() + seg_ind_z)); seg_index_[rr_graph.node_cost_index(node.id())] = segment_id; } return inode; @@ -1027,7 +1043,7 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { inline void* init_rr_graph_rr_nodes(void*& /*ctx*/) final { rr_nodes_->clear(); - seg_index_.resize(CHANX_COST_INDEX_START + segment_inf_x_.size() + segment_inf_y_.size(), -1); + seg_index_.resize(CHANX_COST_INDEX_START + segment_inf_x_.size() + segment_inf_y_.size() + segment_inf_z_.size(), -1); return nullptr; } inline void finish_rr_graph_rr_nodes(void*& /*ctx*/) final { @@ -1171,15 +1187,14 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { * use the pair data structure to keep the maximum*/ if (rr_graph.node_type(node.id()) == e_rr_type::CHANX || rr_graph.node_type(node.id()) == e_rr_type::CHANY) { if(rr_graph.node_type(RRNodeId(sink_node)) == e_rr_type::IPIN){ - if (rr_graph.node_layer(RRNodeId(sink_node)) == rr_graph.node_layer(RRNodeId(source_node))) { + if (rr_graph.node_layer_low(RRNodeId(sink_node)) == rr_graph.node_layer_low(RRNodeId(source_node))) { count_for_wire_to_ipin_switches[switch_id]++; if (count_for_wire_to_ipin_switches[switch_id] > most_frequent_switch.second) { most_frequent_switch.first = switch_id; most_frequent_switch.second = count_for_wire_to_ipin_switches[switch_id]; } - } - else{ - VTR_ASSERT(rr_graph.node_layer(RRNodeId(sink_node)) != rr_graph.node_layer(RRNodeId(source_node))); + } else{ + VTR_ASSERT(rr_graph.node_layer_low(RRNodeId(sink_node)) != rr_graph.node_layer_low(RRNodeId(source_node))); count_for_wire_to_ipin_switches_between_dice[switch_id]++; if(count_for_wire_to_ipin_switches_between_dice[switch_id] > most_frequent_switch_between_dice.second){ most_frequent_switch_between_dice.first = switch_id; @@ -1192,7 +1207,7 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { } VTR_ASSERT(wire_to_rr_ipin_switch_ != nullptr); - *wire_to_rr_ipin_switch_ = most_frequent_switch.first; + *wire_to_rr_ipin_switch_ = (RRSwitchId)most_frequent_switch.first; VTR_ASSERT(wire_to_rr_ipin_switch_between_dice_ != nullptr); *wire_to_rr_ipin_switch_between_dice_ = most_frequent_switch_between_dice.first; @@ -1825,6 +1840,7 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { temp_rr_segs, segment_inf_x_, segment_inf_y_, + segment_inf_z_, *rr_indexed_data_, *wire_to_rr_ipin_switch_, base_cost_type_, @@ -2176,7 +2192,7 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { std::array side_map_; // Output for loads, and constant data for writes. - int* wire_to_rr_ipin_switch_; + RRSwitchId* wire_to_rr_ipin_switch_; int* wire_to_rr_ipin_switch_between_dice_; t_chan_width* chan_width_; t_rr_graph_storage* rr_nodes_; @@ -2204,6 +2220,7 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { const vtr::vector& segment_inf_; std::vector segment_inf_x_; // [num_segs_along_x_axis-1:0] - vector of segment information for segments along the x-axis. std::vector segment_inf_y_; // [num_segs_along_y_axis-1:0] - vector of segment information for segments along the y-axis. + std::vector segment_inf_z_; // [num_segs_along_z_axis-1:0] - vector of segment information for segments along the z-axis. const std::vector& physical_tile_types_; const DeviceGrid& grid_; MetadataStorage* rr_node_metadata_; diff --git a/libs/librrgraph/src/utils/alloc_and_load_rr_indexed_data.cpp b/libs/librrgraph/src/utils/alloc_and_load_rr_indexed_data.cpp index 2007b713537..f63e453dc14 100644 --- a/libs/librrgraph/src/utils/alloc_and_load_rr_indexed_data.cpp +++ b/libs/librrgraph/src/utils/alloc_and_load_rr_indexed_data.cpp @@ -19,19 +19,48 @@ /******************* Subroutines local to this module ************************/ -static void load_rr_indexed_data_base_costs(const RRGraphView& rr_graph, vtr::vector& rr_indexed_data, enum e_base_cost_type base_cost_type, const bool echo_enabled, const char* echo_file_name); +static void load_rr_indexed_data_base_costs(const RRGraphView& rr_graph, + vtr::vector& rr_indexed_data, + e_base_cost_type base_cost_type, + const bool echo_enabled, + const char* echo_file_name); static float get_delay_normalization_fac(const vtr::vector& rr_indexed_data, const bool echo_enabled, const char* echo_file_name); static void load_rr_indexed_data_T_values(const RRGraphView& rr_graph, vtr::vector& rr_indexed_data); -static void calculate_average_switch(const RRGraphView& rr_graph, int inode, double& avg_switch_R, double& avg_switch_T, double& avg_switch_Cinternal, int& num_switches, int& num_shorts, short& buffered, vtr::vector>& fan_in_list); +/** + * @brief Computes average R, Tdel, and Cinternal of fan-in switches for a given node. + * + * Iterates over all incoming edges of @p inode, skipping SHORT switches, + * and averages their electrical properties. Also counts shorts, tracks the + * number of valid switches, and determines whether the node is buffered + * (true if any fan-in switch is buffered). + * + * @note It is not safe to assume that each node of the same wire type has the same switches with the same + * delays, therefore we take their average to take into account the possible differences + */ +static void calculate_average_switch(const RRGraphView& rr_graph, + RRNodeId inode, + double& avg_switch_R, + double& avg_switch_T, + double& avg_switch_Cinternal, + int& num_switches, + int& num_shorts, + short& buffered, + vtr::vector>& fan_in_list); static void fixup_rr_indexed_data_T_values(vtr::vector& rr_indexed_data, size_t num_segment); -static std::vector count_rr_segment_types(const RRGraphView& rr_graph, const vtr::vector& rr_indexed_data); +static std::vector count_rr_segment_types(const RRGraphView& rr_graph, + const vtr::vector& rr_indexed_data); -static void print_rr_index_info(const vtr::vector& rr_indexed_data, const char* fname, const std::vector& segment_inf, size_t y_chan_cost_offset); +static void print_rr_index_info(const vtr::vector& rr_indexed_data, + const char* fname, + const std::vector& segment_inf, + size_t y_chan_cost_offset, + size_t z_chan_cost_offset); /******************** Subroutine definitions *********************************/ @@ -53,23 +82,23 @@ void alloc_and_load_rr_indexed_data(const RRGraphView& rr_graph, const std::vector& segment_inf, const std::vector& segment_inf_x, const std::vector& segment_inf_y, + const std::vector& segment_inf_z, vtr::vector& rr_indexed_data, - int wire_to_ipin_switch, - enum e_base_cost_type base_cost_type, + RRSwitchId wire_to_ipin_switch, + e_base_cost_type base_cost_type, const bool echo_enabled, const char* echo_file_name) { - (void)segment_inf; - int total_num_segment = segment_inf_x.size() + segment_inf_y.size(); - /*CHAX & CHANY segment lsit sizes may differ. but if we're using uniform channels, they - * will each have size equal to segment_inf.size()*/ + const size_t total_num_segment = segment_inf_x.size() + segment_inf_y.size() + segment_inf_z.size(); + + // CHAX & CHANY segment list sizes may differ, but if we're using uniform channels, they will have equal sizes int num_rr_indexed_data = CHANX_COST_INDEX_START + total_num_segment; rr_indexed_data.resize(num_rr_indexed_data); - /* For rr_types that aren't CHANX or CHANY, base_cost is valid, but most * - * * other fields are invalid. For IPINs, the T_linear field is also valid; * - * * all other fields are invalid. For SOURCES, SINKs and OPINs, all fields * - * * other than base_cost are invalid. Mark invalid fields as OPEN for safety. */ - + // For rr_types that aren't CHANX/CHANY/CHANZ, base_cost is valid, but most + // other fields are invalid. For IPINs, the T_linear field is also valid; + // all other fields are invalid. For SOURCES, SINKs and OPINs, all fields + // other than base_cost are invalid. Mark invalid fields as LIBRRGRAPH_UNDEFINED_VAL + // for safety. for (int i = SOURCE_COST_INDEX; i <= IPIN_COST_INDEX; i++) { rr_indexed_data[RRIndexedDataId(i)].ortho_cost_index = LIBRRGRAPH_UNDEFINED_VAL; rr_indexed_data[RRIndexedDataId(i)].seg_index = LIBRRGRAPH_UNDEFINED_VAL; @@ -80,7 +109,7 @@ void alloc_and_load_rr_indexed_data(const RRGraphView& rr_graph, } //TODO: SM: IPIN t_linear assumes wire_to_ipin_switch which corresponds to within die switch connection - rr_indexed_data[RRIndexedDataId(IPIN_COST_INDEX)].T_linear = rr_graph.rr_switch_inf(RRSwitchId(wire_to_ipin_switch)).Tdel; + rr_indexed_data[RRIndexedDataId(IPIN_COST_INDEX)].T_linear = rr_graph.rr_switch_inf(wire_to_ipin_switch).Tdel; std::vector ortho_costs = find_ortho_cost_index(rr_graph, segment_inf_x, segment_inf_y, e_parallel_axis::X_AXIS); @@ -96,41 +125,37 @@ void alloc_and_load_rr_indexed_data(const RRGraphView& rr_graph, * std::move(y_costs.begin(), y_costs.end(), std::back_inserter(ortho_costs)); */ - /* X-directed segments*/ - - for (size_t iseg = 0; iseg < segment_inf_x.size(); ++iseg) { - int index = iseg + CHANX_COST_INDEX_START; - - rr_indexed_data[RRIndexedDataId(index)].ortho_cost_index = ortho_costs[iseg]; - - int length; - if (segment_inf_x[iseg].longline) - length = grid.width(); - else - length = std::min(segment_inf_x[iseg].length, grid.width()); - - rr_indexed_data[RRIndexedDataId(index)].inv_length = 1. / length; - /*We use the index fo the segment in the **unified** seg_inf vector not iseg which is relative - * to parallel axis segments vector */ - rr_indexed_data[RRIndexedDataId(index)].seg_index = segment_inf_x[iseg].seg_index; - } - - /* Y-directed segments*/ - - for (size_t iseg = segment_inf_x.size(); iseg < ortho_costs.size(); ++iseg) { - int index = iseg + CHANX_COST_INDEX_START; - rr_indexed_data[RRIndexedDataId(index)].ortho_cost_index = ortho_costs[iseg]; + for (size_t iseg = 0; iseg < total_num_segment; ++iseg) { + RRIndexedDataId index = RRIndexedDataId(iseg + CHANX_COST_INDEX_START); + + const t_segment_inf* seg_ptr = nullptr; + int offset = 0; + + if (iseg < segment_inf_x.size()) { + // X-directed + seg_ptr = &segment_inf_x[iseg]; + rr_indexed_data[index].ortho_cost_index = ortho_costs[iseg]; + } else if (iseg < segment_inf_x.size() + segment_inf_y.size()) { + // Y-directed + offset = iseg - segment_inf_x.size(); + seg_ptr = &segment_inf_y[offset]; + rr_indexed_data[index].ortho_cost_index = ortho_costs[iseg]; + } else { + // Z-directed + offset = iseg - segment_inf_x.size() - segment_inf_y.size(); + seg_ptr = &segment_inf_z[offset]; + rr_indexed_data[index].ortho_cost_index = LIBRRGRAPH_UNDEFINED_VAL; + } int length; - if (segment_inf_x[iseg - segment_inf_x.size()].longline) + if (seg_ptr->longline) { length = grid.width(); - else - length = std::min(segment_inf_y[iseg - segment_inf_x.size()].length, grid.width()); + } else { + length = std::min(seg_ptr->length, grid.width()); + } - rr_indexed_data[RRIndexedDataId(index)].inv_length = 1. / length; - /*We use the index fo the segment in the **unified** seg_inf vector not iseg which is relative - * to parallel axis segments vector */ - rr_indexed_data[RRIndexedDataId(index)].seg_index = segment_inf_y[iseg - segment_inf_x.size()].seg_index; + rr_indexed_data[index].inv_length = 1. / length; + rr_indexed_data[index].seg_index = seg_ptr->seg_index; } load_rr_indexed_data_T_values(rr_graph, rr_indexed_data); @@ -142,7 +167,9 @@ void alloc_and_load_rr_indexed_data(const RRGraphView& rr_graph, if (echo_enabled) { print_rr_index_info(rr_indexed_data, echo_file_name, - segment_inf, segment_inf_x.size()); + segment_inf, + segment_inf_x.size(), + segment_inf_x.size() + segment_inf_y.size()); } } @@ -160,12 +187,11 @@ std::vector find_ortho_cost_index(const RRGraphView& rr_graph, const std::vector& segment_inf_y, e_parallel_axis parallel_axis) { size_t num_segments = segment_inf_x.size() + segment_inf_y.size(); - std::vector> dest_nodes_count; - - // x segments are perpendicular to y segments - dest_nodes_count.resize(num_segments); + // dest_nodes_count[seg][perp_seg] counts how many times each segment type is connected to perpendicular segment types + std::vector> dest_nodes_count(num_segments); + // x segments are perpendicular to y segments for (size_t iseg = 0; iseg < segment_inf_x.size(); iseg++) { dest_nodes_count[iseg].resize(segment_inf_y.size()); } @@ -174,8 +200,6 @@ std::vector find_ortho_cost_index(const RRGraphView& rr_graph, dest_nodes_count[iseg].resize(segment_inf_x.size()); } - std::vector ortho_cost_indices(dest_nodes_count.size(), 0); - // Go through all rr_Nodes. Look at the ones with CHAN type. Count all outgoing edges to CHAN typed nodes from each CHAN type node. for (const RRNodeId rr_node : rr_graph.nodes()) { for (size_t iedge = 0; iedge < rr_graph.num_edges(rr_node); ++iedge) { @@ -194,23 +218,19 @@ std::vector find_ortho_cost_index(const RRGraphView& rr_graph, } else { dest_nodes_count[from_node_cost_index - CHANX_COST_INDEX_START][to_node_cost_index - CHANX_COST_INDEX_START]++; } - } else { - continue; } } } - for (size_t iseg = 0; iseg < segment_inf_x.size(); iseg++) { - dest_nodes_count[iseg].resize(segment_inf_y.size()); - } + std::vector ortho_cost_indices(num_segments, 0); for (size_t iseg = 0; iseg < segment_inf_x.size(); iseg++) { - ortho_cost_indices[iseg] = std::max_element(dest_nodes_count[iseg].begin(), dest_nodes_count[iseg].end()) - dest_nodes_count[iseg].begin(); + ortho_cost_indices[iseg] = std::ranges::max_element(dest_nodes_count[iseg]) - dest_nodes_count[iseg].begin(); ortho_cost_indices[iseg] += CHANX_COST_INDEX_START + segment_inf_x.size(); } for (size_t iseg = segment_inf_x.size(); iseg < num_segments; iseg++) { - ortho_cost_indices[iseg] = std::max_element(dest_nodes_count[iseg].begin(), dest_nodes_count[iseg].end()) - dest_nodes_count[iseg].begin(); + ortho_cost_indices[iseg] = std::ranges::max_element(dest_nodes_count[iseg]) - dest_nodes_count[iseg].begin(); ortho_cost_indices[iseg] += CHANX_COST_INDEX_START; } @@ -327,15 +347,12 @@ std::vector find_ortho_cost_index(const RRGraphView& rr_graph, static void load_rr_indexed_data_base_costs(const RRGraphView& rr_graph, vtr::vector& rr_indexed_data, - enum e_base_cost_type base_cost_type, + e_base_cost_type base_cost_type, const bool echo_enabled, const char* echo_file_name) { - /* Loads the base_cost member of rr_indexed_data according to the specified * - * base_cost_type. */ + // Loads the base_cost member of rr_indexed_data according to the specified base_cost_type. float delay_normalization_fac; - size_t index; - if (base_cost_type == DEMAND_ONLY || base_cost_type == DEMAND_ONLY_NORMALIZED_LENGTH) { delay_normalization_fac = 1.; } else { @@ -359,9 +376,9 @@ static void load_rr_indexed_data_base_costs(const RRGraphView& rr_graph, /* Load base costs for CHANX and CHANY segments */ float max_length = 0; - float min_length = 1; + const float min_length = 1; if (base_cost_type == DELAY_NORMALIZED_LENGTH_BOUNDED) { - for (index = CHANX_COST_INDEX_START; index < rr_indexed_data.size(); index++) { + for (size_t index = CHANX_COST_INDEX_START; index < rr_indexed_data.size(); index++) { float length = (1 / rr_indexed_data[RRIndexedDataId(index)].inv_length); max_length = std::max(max_length, length); } @@ -371,13 +388,11 @@ static void load_rr_indexed_data_base_costs(const RRGraphView& rr_graph, // perhaps consider lowering cost of wires which connect to IPINs // so they get explored earlier (same rational as lowering IPIN costs) - for (index = CHANX_COST_INDEX_START; index < rr_indexed_data.size(); index++) { + for (size_t index = CHANX_COST_INDEX_START; index < rr_indexed_data.size(); index++) { if (base_cost_type == DELAY_NORMALIZED || base_cost_type == DEMAND_ONLY) { rr_indexed_data[RRIndexedDataId(index)].base_cost = delay_normalization_fac; - } else if (base_cost_type == DELAY_NORMALIZED_LENGTH || base_cost_type == DEMAND_ONLY_NORMALIZED_LENGTH) { rr_indexed_data[RRIndexedDataId(index)].base_cost = delay_normalization_fac / rr_indexed_data[RRIndexedDataId(index)].inv_length; - } else if (base_cost_type == DELAY_NORMALIZED_LENGTH_BOUNDED) { float length = (1 / rr_indexed_data[RRIndexedDataId(index)].inv_length); if (max_length != min_length) { @@ -416,16 +431,20 @@ static void load_rr_indexed_data_base_costs(const RRGraphView& rr_graph, * router, the base_cost values will get changed all the time and being * * able to restore them from a saved version is useful. */ - for (index = 0; index < rr_indexed_data.size(); index++) { + for (size_t index = 0; index < rr_indexed_data.size(); index++) { rr_indexed_data[RRIndexedDataId(index)].saved_base_cost = rr_indexed_data[RRIndexedDataId(index)].base_cost; } } -static std::vector count_rr_segment_types(const RRGraphView& rr_graph, const vtr::vector& rr_indexed_data) { +static std::vector count_rr_segment_types(const RRGraphView& rr_graph, + const vtr::vector& rr_indexed_data) { std::vector rr_segment_type_counts; for (const RRNodeId id : rr_graph.nodes()) { - if (rr_graph.node_type(id) != e_rr_type::CHANX && rr_graph.node_type(id) != e_rr_type::CHANY) continue; + e_rr_type node_type = rr_graph.node_type(id); + if (!is_chanxy(node_type) && !is_chanz(node_type)) { + continue; + } RRIndexedDataId cost_index = rr_graph.node_cost_index(id); @@ -501,47 +520,41 @@ static void load_rr_indexed_data_T_values(const RRGraphView& rr_graph, vtr::vector> C_total(rr_indexed_data.size()); vtr::vector> R_total(rr_indexed_data.size()); - /* - * Not all wire-to-wire switches connecting from some wire segment will necessarily have the same delay. - * i.e. a mux with less inputs will have smaller delay than a mux with a greater number of inputs. - * So to account for these differences we will get the average R/Tdel/Cinternal values by first averaging - * them for a single wire segment, and then by averaging this value over all the average values corresponding - * to the switches node - */ + + // Not all wire-to-wire switches connecting from some wire segment will necessarily have the same delay. + // i.e. a mux with less inputs will have smaller delay than a mux with a greater number of inputs. + // So to account for these differences we will get the average R/Tdel/Cinternal values by first averaging + // them for a single wire segment, and then by averaging this value over all the average values corresponding + // to the switches node vtr::vector> switch_R_total(rr_indexed_data.size()); vtr::vector> switch_T_total(rr_indexed_data.size()); vtr::vector> switch_Cinternal_total(rr_indexed_data.size()); vtr::vector switches_buffered(rr_indexed_data.size(), LIBRRGRAPH_UNDEFINED_VAL); - /* - * Walk through the RR graph and collect all R and C values of all the nodes, - * as well as their fan-in switches R, T_del, and Cinternal values. - * - * The median of R and C values for each cost index is assigned to the indexed - * data. - */ + // Walk through the RR graph and collect all R and C values of all the nodes, + // as well as their fan-in switches R, T_del, and Cinternal values. + // The median of R and C values for each cost index is assigned to the indexed data. for (const RRNodeId rr_id : rr_graph.nodes()) { e_rr_type rr_type = rr_graph.node_type(rr_id); - if (rr_type != e_rr_type::CHANX && rr_type != e_rr_type::CHANY) { + if (!is_chanxy(rr_type) && !is_chanz(rr_type)) { continue; } - auto cost_index = rr_graph.node_cost_index(rr_id); - - auto node_cords = rr_graph.node_coordinate_to_string(RRNodeId(rr_id)); + RRIndexedDataId cost_index = rr_graph.node_cost_index(rr_id); - /* get average switch parameters */ + // Get average switch parameters double avg_switch_R = 0; double avg_switch_T = 0; double avg_switch_Cinternal = 0; int num_switches = 0; int num_shorts = 0; short buffered = LIBRRGRAPH_UNDEFINED_VAL; - calculate_average_switch(rr_graph, (size_t)rr_id, avg_switch_R, avg_switch_T, avg_switch_Cinternal, num_switches, num_shorts, buffered, fan_in_list); + calculate_average_switch(rr_graph, rr_id, avg_switch_R, avg_switch_T, avg_switch_Cinternal, num_switches, num_shorts, buffered, fan_in_list); if (num_switches == 0) { if (num_shorts == 0) { + std::string node_cords = rr_graph.node_coordinate_to_string(RRNodeId(rr_id)); VTR_LOG_WARN("Node: %d with RR_type: %s at Location:%s, had no out-going switches\n", rr_id, rr_graph.node_type_string(rr_id), node_cords.c_str()); } @@ -557,11 +570,11 @@ static void load_rr_indexed_data_T_values(const RRGraphView& rr_graph, switch_T_total[cost_index].push_back(avg_switch_T); switch_Cinternal_total[cost_index].push_back(avg_switch_Cinternal); if (buffered == LIBRRGRAPH_UNDEFINED_VAL) { - /* this segment does not have any outgoing edges to other general routing wires */ + // This segment does not have any outgoing edges to other general routing wires continue; } - /* need to make sure all wire switches of a given wire segment type have the same 'buffered' value */ + // Need to make sure all wire switches of a given wire segment type have the same 'buffered' value if (switches_buffered[cost_index] == LIBRRGRAPH_UNDEFINED_VAL) { switches_buffered[cost_index] = buffered; } else { @@ -578,9 +591,8 @@ static void load_rr_indexed_data_T_values(const RRGraphView& rr_graph, } unsigned num_occurences_of_no_instances_with_cost_index = 0; - for (size_t cost_index = CHANX_COST_INDEX_START; - cost_index < rr_indexed_data.size(); cost_index++) { - if (num_nodes_of_index[RRIndexedDataId(cost_index)] == 0) { /* Segments don't exist. */ + for (size_t cost_index = CHANX_COST_INDEX_START; cost_index < rr_indexed_data.size(); cost_index++) { + if (num_nodes_of_index[RRIndexedDataId(cost_index)] == 0) { // Segments don't exist. rr_indexed_data[RRIndexedDataId(cost_index)].T_linear = 0.0; rr_indexed_data[RRIndexedDataId(cost_index)].T_quadratic = 0.0; rr_indexed_data[RRIndexedDataId(cost_index)].C_load = 0.0; @@ -614,14 +626,13 @@ static void load_rr_indexed_data_T_values(const RRGraphView& rr_graph, + 0.5 * Rnode * (Cnode + Cinternalsw); rr_indexed_data[RRIndexedDataId(cost_index)].T_quadratic = 0.; rr_indexed_data[RRIndexedDataId(cost_index)].C_load = 0.; - } else { /* Pass transistor, does not have an internal capacitance*/ + } else { // Pass transistor, does not have an internal capacitance rr_indexed_data[RRIndexedDataId(cost_index)].C_load = Cnode; /* See Dec. 23, 1997 notes for deriviation of formulae. */ rr_indexed_data[RRIndexedDataId(cost_index)].T_linear = Tsw + 0.5 * Rsw * Cnode; - rr_indexed_data[RRIndexedDataId(cost_index)].T_quadratic = (Rsw + Rnode) * 0.5 - * Cnode; + rr_indexed_data[RRIndexedDataId(cost_index)].T_quadratic = (Rsw + Rnode) * 0.5 * Cnode; } } } @@ -631,15 +642,15 @@ static void load_rr_indexed_data_T_values(const RRGraphView& rr_graph, } } -/* - * This routine calculates the average R/Tdel/Cinternal values of all the switches corresponding - * to the fan-in edges of the input inode. - * - * It is not safe to assume that each node of the same wire type has the same switches with the same - * delays, therefore we take their average to take into account the possible differences - */ -static void calculate_average_switch(const RRGraphView& rr_graph, int inode, double& avg_switch_R, double& avg_switch_T, double& avg_switch_Cinternal, int& num_switches, int& num_shorts, short& buffered, vtr::vector>& fan_in_list) { - auto node = RRNodeId(inode); +static void calculate_average_switch(const RRGraphView& rr_graph, + RRNodeId inode, + double& avg_switch_R, + double& avg_switch_T, + double& avg_switch_Cinternal, + int& num_switches, + int& num_shorts, + short& buffered, + vtr::vector>& fan_in_list) { avg_switch_R = 0; avg_switch_T = 0; @@ -647,27 +658,30 @@ static void calculate_average_switch(const RRGraphView& rr_graph, int inode, dou num_switches = 0; num_shorts = 0; buffered = LIBRRGRAPH_UNDEFINED_VAL; - for (const auto& edge : fan_in_list[node]) { - /* want to get C/R/Tdel/Cinternal of switches that connect this track segment to other track segments */ - if (rr_graph.node_type(node) == e_rr_type::CHANX || rr_graph.node_type(node) == e_rr_type::CHANY) { - int switch_index = rr_graph.rr_nodes().edge_switch(edge); - if (rr_graph.rr_switch_inf(RRSwitchId(switch_index)).type() == SwitchType::SHORT) { + for (const RREdgeId edge : fan_in_list[inode]) { + // Want to get C/R/Tdel/Cinternal of switches that connect this track segment to other track segments + e_rr_type node_type = rr_graph.node_type(inode); + + if (is_chanxy(node_type) || is_chanz(node_type)) { + RRSwitchId switch_index = (RRSwitchId)rr_graph.rr_nodes().edge_switch(edge); + + if (rr_graph.rr_switch_inf(switch_index).type() == SwitchType::SHORT) { num_shorts++; continue; } - avg_switch_R += rr_graph.rr_switch_inf(RRSwitchId(switch_index)).R; - avg_switch_T += rr_graph.rr_switch_inf(RRSwitchId(switch_index)).Tdel; - avg_switch_Cinternal += rr_graph.rr_switch_inf(RRSwitchId(switch_index)).Cinternal; + avg_switch_R += rr_graph.rr_switch_inf(switch_index).R; + avg_switch_T += rr_graph.rr_switch_inf(switch_index).Tdel; + avg_switch_Cinternal += rr_graph.rr_switch_inf(switch_index).Cinternal; if (buffered == LIBRRGRAPH_UNDEFINED_VAL) { - if (rr_graph.rr_switch_inf(RRSwitchId(switch_index)).buffered()) { + if (rr_graph.rr_switch_inf(switch_index).buffered()) { buffered = 1; } else { buffered = 0; } - } else if (buffered != rr_graph.rr_switch_inf(RRSwitchId(switch_index)).buffered()) { + } else if (buffered != rr_graph.rr_switch_inf((switch_index)).buffered()) { // If a previous buffering state is inconsistent with the current one, // the node should be treated as buffered, as there are only two possible // values for the buffering state (except for the UNDEFINED case). @@ -698,15 +712,19 @@ static void fixup_rr_indexed_data_T_values(vtr::vector& rr_indexed_data, const char* fname, const std::vector& segment_inf, - size_t y_chan_cost_offset) { + size_t y_chan_cost_offset, + size_t z_chan_cost_offset) { std::ofstream out_file; out_file.open(fname, std::ios_base::app); @@ -739,7 +758,7 @@ static void print_rr_index_info(const vtr::vector& segment_inf, const std::vector& segment_inf_x, const std::vector& segment_inf_y, + const std::vector& segment_inf_z, vtr::vector& rr_indexed_data, - int wire_to_ipin_switch, - enum e_base_cost_type base_cost_type, + RRSwitchId wire_to_ipin_switch, + e_base_cost_type base_cost_type, const bool echo_enabled, const char* echo_file_name); diff --git a/libs/librrgraph/src/utils/describe_rr_node.cpp b/libs/librrgraph/src/utils/describe_rr_node.cpp index 16daa5c0718..2b439195296 100644 --- a/libs/librrgraph/src/utils/describe_rr_node.cpp +++ b/libs/librrgraph/src/utils/describe_rr_node.cpp @@ -30,7 +30,7 @@ std::string describe_rr_node(const RRGraphView& rr_graph, } else if (node_type == e_rr_type::IPIN || node_type == e_rr_type::OPIN) { t_physical_tile_type_ptr type = grid.get_physical_type({rr_graph.node_xlow(inode), rr_graph.node_ylow(inode), - rr_graph.node_layer(inode)}); + rr_graph.node_layer_low(inode)}); std::string pin_name = block_type_pin_index_to_name(type, rr_graph.node_pin_num(inode), is_flat); diff --git a/libs/libvtrcapnproto/gen/rr_graph_uxsdcxx.capnp b/libs/libvtrcapnproto/gen/rr_graph_uxsdcxx.capnp index 5df8cb2c04f..d43f8738382 100644 --- a/libs/libvtrcapnproto/gen/rr_graph_uxsdcxx.capnp +++ b/libs/libvtrcapnproto/gen/rr_graph_uxsdcxx.capnp @@ -2,11 +2,11 @@ # https://github.com/duck2/uxsdcxx # Modify only if your build process doesn't involve regenerating this file. # -# Cmdline: uxsdcxx/uxsdcap.py /home/soheil/vpr_repos/libs/librrgraph/src/io/rr_graph.xsd -# Input file: /home/soheil/vpr_repos/libs/librrgraph/src/io/rr_graph.xsd -# md5sum of input file: 5d51b89242fe6e463629ac43a72e4606 +# Cmdline: uxsdcxx/uxsdcap.py /home/soheil/vtr/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd +# Input file: /home/soheil/vtr/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd +# md5sum of input file: 040903603053940a1b24392c38663b59 -@0x8fe58c48975cfaf0; +@0xe7650575a8718aa2; using Cxx = import "/capnp/c++.capnp"; $Cxx.namespace("ucap"); @@ -41,6 +41,7 @@ enum NodeType { sink @5; opin @6; ipin @7; + mux @8; } enum NodeDirection { @@ -177,13 +178,14 @@ struct GridLocs { } struct NodeLoc { - layer @0 :Int32 = 0; - ptc @1 :Text; - side @2 :LocSide; - xhigh @3 :Int32; - xlow @4 :Int32; - yhigh @5 :Int32; - ylow @6 :Int32; + layerHigh @0 :Int32 = 0; + layerLow @1 :Int32 = 0; + ptc @2 :Text; + side @3 :LocSide; + xhigh @4 :Int32; + xlow @5 :Int32; + yhigh @6 :Int32; + ylow @7 :Int32; } struct NodeTiming { diff --git a/utils/fasm/test/test_fasm.cpp b/utils/fasm/test/test_fasm.cpp index 63767ccc1d1..ed125b30e5f 100644 --- a/utils/fasm/test/test_fasm.cpp +++ b/utils/fasm/test/test_fasm.cpp @@ -192,7 +192,7 @@ static std::string get_pin_feature (size_t inode) { // Get tile physical tile and the pin number int ilow = rr_graph.node_xlow(RRNodeId(inode)); int jlow = rr_graph.node_ylow(RRNodeId(inode)); - int layer_num = rr_graph.node_layer(RRNodeId(inode)); + int layer_num = rr_graph.node_layer_low(RRNodeId(inode)); auto physical_tile = device_ctx.grid.get_physical_type({ilow, jlow, layer_num}); int pin_num = rr_graph.node_pin_num(RRNodeId(inode)); diff --git a/vpr/src/analysis/timing_reports.cpp b/vpr/src/analysis/timing_reports.cpp index 0c7a408ab4a..f30e22a5d09 100644 --- a/vpr/src/analysis/timing_reports.cpp +++ b/vpr/src/analysis/timing_reports.cpp @@ -38,8 +38,8 @@ static t_bb get_net_bounding_box(const AtomNetId atom_net_id) { bb.xmax = rr_graph.node_xhigh(route_tree_root); bb.ymin = rr_graph.node_ylow(route_tree_root); bb.ymax = rr_graph.node_yhigh(route_tree_root); - bb.layer_min = rr_graph.node_layer(route_tree_root); - bb.layer_max = rr_graph.node_layer(route_tree_root); + bb.layer_min = rr_graph.node_layer_low(route_tree_root); + bb.layer_max = rr_graph.node_layer_high(route_tree_root); // Iterate over all nodes in the route tree and update the bounding box for (auto& rt_node : route_tree.all_nodes()) { @@ -51,8 +51,8 @@ static t_bb get_net_bounding_box(const AtomNetId atom_net_id) { bb.ymin = std::min(static_cast(rr_graph.node_ylow(inode)), bb.ymin); bb.ymax = std::max(static_cast(rr_graph.node_yhigh(inode)), bb.ymax); - bb.layer_min = std::min(static_cast(rr_graph.node_layer(inode)), bb.layer_min); - bb.layer_max = std::max(static_cast(rr_graph.node_layer(inode)), bb.layer_max); + bb.layer_min = std::min(static_cast(rr_graph.node_layer_low(inode)), bb.layer_min); + bb.layer_max = std::max(static_cast(rr_graph.node_layer_high(inode)), bb.layer_max); } return bb; }; diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index f986866ed05..34dc0e855f4 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -2848,12 +2848,6 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio .help("Controls the verbosity of routing's output. Higher values produce more output (useful for debugging routing problems)") .default_value("1") .show_in(argparse::ShowIn::HELP_ONLY); - route_grp.add_argument(args.custom_3d_sb_fanin_fanout, "--custom_3d_sb_fanin_fanout") - .help( - "Specifies the number of tracks that can drive a 3D switch block connection" - "and the number of tracks that can be driven by a 3D switch block connection") - .default_value("1") - .show_in(argparse::ShowIn::HELP_ONLY); auto& route_timing_grp = parser.add_argument_group("timing-driven routing options"); diff --git a/vpr/src/base/read_options.h b/vpr/src/base/read_options.h index 4f518ae7d10..5485f058c49 100644 --- a/vpr/src/base/read_options.h +++ b/vpr/src/base/read_options.h @@ -233,7 +233,6 @@ struct t_options { argparse::ArgValue flat_routing; argparse::ArgValue router_opt_choke_points; argparse::ArgValue route_verbosity; - argparse::ArgValue custom_3d_sb_fanin_fanout; /* Timing-driven router options only */ argparse::ArgValue astar_fac; diff --git a/vpr/src/base/read_route.cpp b/vpr/src/base/read_route.cpp index 188b9697f5e..59cfac94bf8 100644 --- a/vpr/src/base/read_route.cpp +++ b/vpr/src/base/read_route.cpp @@ -692,17 +692,14 @@ void print_route(const Netlist<>& net_list, e_rr_type rr_type = rr_graph.node_type(inode); int ilow = rr_graph.node_xlow(inode); int jlow = rr_graph.node_ylow(inode); - int layer_num = rr_graph.node_layer(inode); + int layer_low = rr_graph.node_layer_low(inode); - fprintf(fp, "Node:\t%zu\t%6s (%d,%d,%d) ", size_t(inode), - rr_graph.node_type_string(inode), ilow, jlow, layer_num); + fprintf(fp, "Node:\t%zu\t%6s (%d,%d,%d) ", size_t(inode), rr_graph.node_type_string(inode), ilow, jlow, layer_low); - if (ilow != rr_graph.node_xhigh(inode) - || jlow != rr_graph.node_yhigh(inode)) - fprintf(fp, "to (%d,%d,%d) ", rr_graph.node_xhigh(inode), - rr_graph.node_yhigh(inode), layer_num); + if (ilow != rr_graph.node_xhigh(inode) || jlow != rr_graph.node_yhigh(inode) || layer_low != rr_graph.node_layer_high(inode)) + fprintf(fp, "to (%d,%d,%d) ", rr_graph.node_xhigh(inode), rr_graph.node_yhigh(inode), rr_graph.node_layer_high(inode)); - t_physical_tile_type_ptr physical_tile = device_ctx.grid.get_physical_type({ilow, jlow, layer_num}); + t_physical_tile_type_ptr physical_tile = device_ctx.grid.get_physical_type({ilow, jlow, layer_low}); switch (rr_type) { case e_rr_type::IPIN: @@ -745,13 +742,13 @@ void print_route(const Netlist<>& net_list, if (!physical_tile->is_io() && (rr_type == e_rr_type::IPIN || rr_type == e_rr_type::OPIN)) { int pin_num = rr_graph.node_pin_num(inode); - int xoffset = device_ctx.grid.get_width_offset({ilow, jlow, layer_num}); - int yoffset = device_ctx.grid.get_height_offset({ilow, jlow, layer_num}); + int xoffset = device_ctx.grid.get_width_offset({ilow, jlow, layer_low}); + int yoffset = device_ctx.grid.get_height_offset({ilow, jlow, layer_low}); auto [sub_tile, sub_tile_rel_cap] = get_sub_tile_from_pin_physical_num(physical_tile, pin_num); int sub_tile_offset = sub_tile->capacity.low + sub_tile_rel_cap; ClusterBlockId iblock = grid_blocks.block_at_location({ilow - xoffset, jlow - yoffset, - sub_tile_offset, layer_num}); + sub_tile_offset, layer_low}); VTR_ASSERT(iblock); const t_pb_graph_pin* pb_pin; if (is_pin_on_tile(physical_tile, pin_num)) { diff --git a/vpr/src/base/setup_vpr.cpp b/vpr/src/base/setup_vpr.cpp index cbe0feed92a..ceeca6ffe3c 100644 --- a/vpr/src/base/setup_vpr.cpp +++ b/vpr/src/base/setup_vpr.cpp @@ -533,7 +533,6 @@ static void setup_router_opts(const t_options& Options, t_router_opts* RouterOpt RouterOpts->generate_rr_node_overuse_report = Options.generate_rr_node_overuse_report; RouterOpts->flat_routing = Options.flat_routing; RouterOpts->has_choke_point = Options.router_opt_choke_points; - RouterOpts->custom_3d_sb_fanin_fanout = Options.custom_3d_sb_fanin_fanout; RouterOpts->with_timing_analysis = Options.timing_analysis; RouterOpts->verify_route_file_switch_id = Options.verify_route_file_switch_id; diff --git a/vpr/src/base/stats.cpp b/vpr/src/base/stats.cpp index 033fed6f2c3..7ece122c4bc 100644 --- a/vpr/src/base/stats.cpp +++ b/vpr/src/base/stats.cpp @@ -63,13 +63,13 @@ static void get_channel_occupancy_stats(const Netlist<>& net_list, bool /***/); void routing_stats(const Netlist<>& net_list, bool full_stats, - enum e_route_type route_type, + e_route_type route_type, std::vector& segment_inf, float R_minW_nmos, float R_minW_pmos, float grid_logic_tile_area, - enum e_directionality directionality, - int wire_to_ipin_switch, + e_directionality directionality, + RRSwitchId wire_to_ipin_switch, bool is_flat) { auto& device_ctx = g_vpr_ctx.device(); auto& rr_graph = device_ctx.rr_graph; @@ -130,12 +130,12 @@ std::pair, vtr::NdMatrix> calculate_channel_width( const auto& device_ctx = g_vpr_ctx.device(); const auto& rr_graph = device_ctx.rr_graph; - auto chanx_width = vtr::NdMatrix({{(size_t)device_ctx.grid.get_num_layers(), + auto chanx_width = vtr::NdMatrix({{device_ctx.grid.get_num_layers(), device_ctx.grid.width(), device_ctx.grid.height()}}, 0); - auto chany_width = vtr::NdMatrix({{(size_t)device_ctx.grid.get_num_layers(), + auto chany_width = vtr::NdMatrix({{device_ctx.grid.get_num_layers(), device_ctx.grid.width(), device_ctx.grid.height()}}, 0); @@ -145,13 +145,13 @@ std::pair, vtr::NdMatrix> calculate_channel_width( if (rr_type == e_rr_type::CHANX) { int y = rr_graph.node_ylow(node_id); - int layer = rr_graph.node_layer(node_id); + int layer = rr_graph.node_layer_low(node_id); for (int x = rr_graph.node_xlow(node_id); x <= rr_graph.node_xhigh(node_id); x++) { chanx_width[layer][x][y] += rr_graph.node_capacity(node_id); } } else if (rr_type == e_rr_type::CHANY) { int x = rr_graph.node_xlow(node_id); - int layer = rr_graph.node_layer(node_id); + int layer = rr_graph.node_layer_low(node_id); for (int y = rr_graph.node_ylow(node_id); y <= rr_graph.node_yhigh(node_id); y++) { chany_width[layer][x][y] += rr_graph.node_capacity(node_id); } diff --git a/vpr/src/base/stats.h b/vpr/src/base/stats.h index 08b9e4d1d13..1f9efe45afd 100644 --- a/vpr/src/base/stats.h +++ b/vpr/src/base/stats.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include "netlist.h" #include "rr_graph_type.h" @@ -14,13 +15,13 @@ class DeviceGrid; */ void routing_stats(const Netlist<>& net_list, bool full_stats, - enum e_route_type route_type, + e_route_type route_type, std::vector& segment_inf, float R_minW_nmos, float R_minW_pmos, float grid_logic_tile_area, - enum e_directionality directionality, - int wire_to_ipin_switch, + e_directionality directionality, + RRSwitchId wire_to_ipin_switch, bool is_flat); /** diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index 2f3e788e189..91255a92324 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -1313,8 +1313,8 @@ struct t_router_opts { enum e_route_type route_type; int fixed_channel_width; int min_channel_width_hint; /// congested_rr_nodes = collect_congested_rr_nodes(); for (RRNodeId inode : congested_rr_nodes) { short occ = route_ctx.rr_node_route_inf[inode].occ(); short capacity = rr_graph.node_capacity(inode); @@ -333,7 +333,7 @@ void draw_congestion(ezgl::renderer* g) { //Draw each congested node for (RRNodeId inode : congested_rr_nodes) { - int layer_num = rr_graph.node_layer(inode); + int layer_num = rr_graph.node_layer_low(inode); int transparency_factor = get_rr_node_transparency(inode); if (!draw_state->draw_layer_display[layer_num].visible) continue; @@ -663,8 +663,8 @@ bool is_edge_valid_to_draw(RRNodeId current_node, RRNodeId prev_node) { t_draw_state* draw_state = get_draw_state_vars(); const RRGraphView& rr_graph = g_vpr_ctx.device().rr_graph; - int current_node_layer = rr_graph.node_layer(current_node); - int prev_node_layer = rr_graph.node_layer(prev_node); + int current_node_layer = rr_graph.node_layer_low(current_node); + int prev_node_layer = rr_graph.node_layer_low(prev_node); if (!(is_inter_cluster_node(rr_graph, current_node)) || !(is_inter_cluster_node(rr_graph, prev_node))) { return false; diff --git a/vpr/src/draw/draw_rr.cpp b/vpr/src/draw/draw_rr.cpp index 2bc7f81b168..a955543a340 100644 --- a/vpr/src/draw/draw_rr.cpp +++ b/vpr/src/draw/draw_rr.cpp @@ -358,7 +358,7 @@ void draw_rr_node(RRNodeId inode, const ezgl::color color, ezgl::renderer* g) { const RRGraphView& rr_graph = device_ctx.rr_graph; e_rr_type rr_type = rr_graph.node_type(inode); bool inode_inter_cluster = is_inter_cluster_node(rr_graph, inode); - int node_layer = rr_graph.node_layer(inode); + int node_layer = rr_graph.node_layer_low(inode); // For 3D architectures, draw only visible layers if (!draw_state->draw_layer_display[node_layer].visible) { @@ -480,7 +480,7 @@ void draw_get_rr_src_sink_coords(const t_rr_node& node, float* xcen, float* ycen RRNodeId rr_node = node.id(); t_physical_tile_type_ptr tile_type = device_ctx.grid.get_physical_type({rr_graph.node_xlow(rr_node), rr_graph.node_ylow(rr_node), - rr_graph.node_layer(rr_node)}); + rr_graph.node_layer_low(rr_node)}); //Number of classes (i.e. src/sinks) we need to draw float num_class = tile_type->class_inf.size(); @@ -569,8 +569,8 @@ RRNodeId draw_check_rr_node_hit(float click_x, float click_y) { const DeviceContext& device_ctx = g_vpr_ctx.device(); const RRGraphView& rr_graph = device_ctx.rr_graph; - for (const RRNodeId& inode : device_ctx.rr_graph.nodes()) { - int layer_num = rr_graph.node_layer(inode); + for (const RRNodeId inode : device_ctx.rr_graph.nodes()) { + int layer_num = rr_graph.node_layer_low(inode); if (!draw_state->draw_layer_display[layer_num].visible) { continue; /* Don't check RR nodes on currently invisible layers*/ } @@ -715,7 +715,7 @@ void draw_rr_costs(ezgl::renderer* g, const vtr::vector& rr_cos int transparency_factor = get_rr_node_transparency(inode); // continue if rr_node layer is not visible - int layer_num = rr_graph.node_layer(inode); + int layer_num = rr_graph.node_layer_low(inode); if (!draw_state->draw_layer_display[layer_num].visible) continue; @@ -771,7 +771,7 @@ void draw_get_rr_pin_coords(const t_rr_node& node, float* xcen, float* ycen, con i = rr_graph.node_xlow(rr_node); j = rr_graph.node_ylow(rr_node); - int layer_num = rr_graph.node_layer(rr_node); + int layer_num = rr_graph.node_layer_low(rr_node); xc = draw_coords->tile_x[i]; yc = draw_coords->tile_y[j]; @@ -823,7 +823,7 @@ int get_rr_node_transparency(RRNodeId rr_node) { const DeviceContext& device_ctx = g_vpr_ctx.device(); const RRGraphView& rr_graph = device_ctx.rr_graph; - int layer_num = rr_graph.node_layer(rr_node); + int layer_num = rr_graph.node_layer_low(rr_node); return draw_state->draw_layer_display[layer_num].alpha; } diff --git a/vpr/src/draw/draw_rr_edges.cpp b/vpr/src/draw/draw_rr_edges.cpp index a9caa433407..929aacbc9d2 100644 --- a/vpr/src/draw/draw_rr_edges.cpp +++ b/vpr/src/draw/draw_rr_edges.cpp @@ -418,7 +418,7 @@ e_side get_pin_side(RRNodeId pin_node, RRNodeId chan_node) { t_physical_tile_loc tile_loc = { rr_graph.node_xlow(pin_node), rr_graph.node_ylow(pin_node), - rr_graph.node_layer(pin_node)}; + rr_graph.node_layer_low(pin_node)}; const auto& grid_type = device_ctx.grid.get_physical_type(tile_loc); int width_offset = device_ctx.grid.get_width_offset(tile_loc); @@ -508,7 +508,7 @@ void draw_pin_to_chan_edge(RRNodeId pin_node, RRNodeId chan_node, ezgl::renderer t_physical_tile_loc tile_loc = { rr_graph.node_xlow(pin_node), rr_graph.node_ylow(pin_node), - rr_graph.node_layer(pin_node)}; + rr_graph.node_layer_low(pin_node)}; const auto& grid_type = device_ctx.grid.get_physical_type(tile_loc); const e_rr_type channel_type = rr_graph.node_type(chan_node); @@ -605,11 +605,11 @@ void draw_rr_edge(RRNodeId inode, RRNodeId prev_node, ezgl::color color, ezgl::r e_rr_type rr_type = rr_graph.node_type(inode); bool inode_inter_cluster = is_inter_cluster_node(rr_graph, inode); - int current_node_layer = rr_graph.node_layer(inode); + int current_node_layer = rr_graph.node_layer_low(inode); e_rr_type prev_type = rr_graph.node_type(prev_node); bool prev_node_inter_cluster = is_inter_cluster_node(rr_graph, prev_node); - int prev_node_layer = rr_graph.node_layer(prev_node); + int prev_node_layer = rr_graph.node_layer_low(prev_node); t_draw_layer_display edge_visibility = get_element_visibility_and_transparency(prev_node_layer, current_node_layer); diff --git a/vpr/src/draw/search_bar.cpp b/vpr/src/draw/search_bar.cpp index af194987451..e3c9586f072 100644 --- a/vpr/src/draw/search_bar.cpp +++ b/vpr/src/draw/search_bar.cpp @@ -269,7 +269,7 @@ void auto_zoom_rr_node(RRNodeId rr_node_id) { t_physical_tile_loc tile_loc = { rr_graph.node_xlow(rr_node_id), rr_graph.node_ylow(rr_node_id), - rr_graph.node_layer(rr_node_id)}; + rr_graph.node_layer_low(rr_node_id)}; t_physical_tile_type_ptr type = device_ctx.grid.get_physical_type(tile_loc); int width_offset = device_ctx.grid.get_width_offset(tile_loc); int height_offset = device_ctx.grid.get_height_offset(tile_loc); diff --git a/vpr/src/pack/sync_netlists_to_routing_flat.cpp b/vpr/src/pack/sync_netlists_to_routing_flat.cpp index e1da710d40b..7e03d3b8fd8 100644 --- a/vpr/src/pack/sync_netlists_to_routing_flat.cpp +++ b/vpr/src/pack/sync_netlists_to_routing_flat.cpp @@ -51,7 +51,7 @@ inline ClusterBlockId get_cluster_block_from_rr_node(RRNodeId inode) { t_physical_tile_loc node_phy_tile_loc(rr_graph.node_xlow(inode), rr_graph.node_ylow(inode), - rr_graph.node_layer(inode)); + rr_graph.node_layer_low(inode)); auto physical_tile = device_ctx.grid.get_physical_type(node_phy_tile_loc); int source_pin = rr_graph.node_pin_num(inode); @@ -67,7 +67,7 @@ inline ClusterBlockId get_cluster_block_from_rr_node(RRNodeId inode) { ClusterBlockId clb = place_ctx.grid_blocks().block_at_location({rr_graph.node_xlow(inode) - width_offset, rr_graph.node_ylow(inode) - height_offset, subtile, - rr_graph.node_layer(inode)}); + rr_graph.node_layer_low(inode)}); return clb; } @@ -207,7 +207,7 @@ static void sync_pb_routes_to_routing(void) { ClusterBlockId clb = get_cluster_block_from_rr_node(source_inode); auto physical_tile = device_ctx.grid.get_physical_type({rr_graph.node_xlow(source_inode), rr_graph.node_ylow(source_inode), - rr_graph.node_layer(source_inode)}); + rr_graph.node_layer_low(source_inode)}); int source_pin = rr_graph.node_pin_num(source_inode); int sink_pin = rr_graph.node_pin_num(sink_inode); @@ -329,7 +329,7 @@ static void sync_clustered_netlist_to_routing(void) { auto physical_tile = device_ctx.grid.get_physical_type({rr_graph.node_xlow(rt_node.inode), rr_graph.node_ylow(rt_node.inode), - rr_graph.node_layer(rt_node.inode)}); + rr_graph.node_layer_low(rt_node.inode)}); int pin_index = rr_graph.node_pin_num(rt_node.inode); diff --git a/vpr/src/place/net_cost_handler.cpp b/vpr/src/place/net_cost_handler.cpp index a8adccadb35..243bd0cba88 100644 --- a/vpr/src/place/net_cost_handler.cpp +++ b/vpr/src/place/net_cost_handler.cpp @@ -197,28 +197,18 @@ void NetCostHandler::alloc_and_load_for_fast_vertical_cost_update_() { * if someday we have architectures with widely varying connectivity between different layers in a stack. */ - /* - * To calculate the accumulative number of inter-die connections we first need to get the number of + /* To calculate the accumulative number of inter-die connections we first need to get the number of * inter-die connection per location. To be able to work for the cases that RR Graph is read instead * of being made from the architecture file, we calculate this number by iterating over the RR graph. Once - * tile_num_inter_die_conn is populated, we can start populating acc_tile_num_inter_die_conn_. First, - * we populate the first row and column. Then, we iterate over the rest of blocks and get the number of - * inter-die connections by adding up the number of inter-die block at that location + the accumulation - * for the block below and left to it. Then, since the accumulated number of inter-die connection to - * the block on the lower left connection of the block is added twice, that part needs to be removed. + * tile_num_inter_die_conn is populated, we can start populating acc_tile_num_inter_die_conn_. */ - for (const RRNodeId src_rr_node : rr_graph.nodes()) { - for (const t_edge_size rr_edge_idx : rr_graph.edges(src_rr_node)) { - const RRNodeId sink_rr_node = rr_graph.edge_sink_node(src_rr_node, rr_edge_idx); - if (rr_graph.node_layer(src_rr_node) != rr_graph.node_layer(sink_rr_node)) { - // We assume that the nodes driving the inter-layer connection or being driven by it - // are not stretched across multiple tiles - int src_x = rr_graph.node_xhigh(src_rr_node); - int src_y = rr_graph.node_yhigh(src_rr_node); - VTR_ASSERT(rr_graph.node_xlow(src_rr_node) == src_x && rr_graph.node_ylow(src_rr_node) == src_y); - - tile_num_inter_die_conn[src_x][src_y]++; - } + + for (const RRNodeId node : rr_graph.nodes()) { + if (rr_graph.node_type(node) == e_rr_type::CHANZ) { + int x = rr_graph.node_xlow(node); + int y = rr_graph.node_ylow(node); + VTR_ASSERT_SAFE(x == rr_graph.node_xhigh(node) && y == rr_graph.node_yhigh(node)); + tile_num_inter_die_conn[x][y]++; } } diff --git a/vpr/src/power/power.cpp b/vpr/src/power/power.cpp index 4ea38c8fcf5..1adedffd271 100644 --- a/vpr/src/power/power.cpp +++ b/vpr/src/power/power.cpp @@ -979,7 +979,7 @@ static void power_usage_routing(t_power_usage* power_usage, connectionbox_fanout = 0; switchbox_fanout = 0; for (t_edge_size iedge = 0; iedge < rr_graph.num_edges(rr_id); iedge++) { - if (rr_graph.edge_switch(rr_id, iedge) == routing_arch.wire_to_rr_ipin_switch) { + if ((RRSwitchId)rr_graph.edge_switch(rr_id, iedge) == routing_arch.wire_to_rr_ipin_switch) { connectionbox_fanout++; } else if (rr_graph.edge_switch(rr_id, iedge) == routing_arch.delayless_switch) { /* Do nothing */ @@ -1225,7 +1225,7 @@ void power_routing_init(const t_det_routing_arch& routing_arch) { case e_rr_type::CHANX: case e_rr_type::CHANY: for (t_edge_size iedge = 0; iedge < rr_graph.num_edges(rr_node_idx); iedge++) { - if (rr_graph.edge_switch(rr_node_idx, iedge) == routing_arch.wire_to_rr_ipin_switch) { + if ((RRSwitchId)rr_graph.edge_switch(rr_node_idx, iedge) == routing_arch.wire_to_rr_ipin_switch) { fanout_to_IPIN++; } else if (rr_graph.edge_switch(rr_node_idx, iedge) != routing_arch.delayless_switch) { fanout_to_seg++; diff --git a/vpr/src/route/DecompNetlistRouter.tpp b/vpr/src/route/DecompNetlistRouter.tpp index 21d800ec0b3..7198ade89f3 100644 --- a/vpr/src/route/DecompNetlistRouter.tpp +++ b/vpr/src/route/DecompNetlistRouter.tpp @@ -450,7 +450,7 @@ inline bool is_close_to_cutline(RRNodeId inode, Axis cutline_axis, int cutline_p vtr::Rect tile_bb = device_ctx.grid.get_tile_bb({rr_graph.node_xlow(inode), rr_graph.node_ylow(inode), - rr_graph.node_layer(inode)}); + rr_graph.node_layer_low(inode)}); /* Cutlines are considered to be at x + 0.5, set a thickness of +1 here by checking for equality */ if (cutline_axis == Axis::X) { @@ -467,7 +467,7 @@ inline bool is_close_to_bb(RRNodeId inode, const t_bb& bb, int thickness) { vtr::Rect tile_bb = device_ctx.grid.get_tile_bb({rr_graph.node_xlow(inode), rr_graph.node_ylow(inode), - rr_graph.node_layer(inode)}); + rr_graph.node_layer_low(inode)}); int xlow = tile_bb.xmin() - thickness; int ylow = tile_bb.ymin() - thickness; diff --git a/vpr/src/route/check_route.cpp b/vpr/src/route/check_route.cpp index b4153c40fd0..2c6613d1a99 100644 --- a/vpr/src/route/check_route.cpp +++ b/vpr/src/route/check_route.cpp @@ -304,8 +304,8 @@ static bool check_adjacent(RRNodeId from_node, RRNodeId to_node, bool is_flat) { return false; } - /* Now we know the rr graph says these two nodes are adjacent. Double * - * check that this makes sense, to verify the rr graph. */ + // Now we know the rr graph says these two nodes are adjacent. Double + // check that this makes sense, to verify the rr graph. VTR_ASSERT(reached); int num_adj = 0; @@ -313,14 +313,14 @@ static bool check_adjacent(RRNodeId from_node, RRNodeId to_node, bool is_flat) { auto from_rr = RRNodeId(from_node); auto to_rr = RRNodeId(to_node); e_rr_type from_type = rr_graph.node_type(from_rr); - int from_layer = rr_graph.node_layer(from_rr); + int from_layer = rr_graph.node_layer_low(from_rr); int from_xlow = rr_graph.node_xlow(from_rr); int from_ylow = rr_graph.node_ylow(from_rr); int from_xhigh = rr_graph.node_xhigh(from_rr); int from_yhigh = rr_graph.node_yhigh(from_rr); int from_ptc = rr_graph.node_ptc_num(from_rr); e_rr_type to_type = rr_graph.node_type(to_rr); - int to_layer = rr_graph.node_layer(to_rr); + int to_layer = rr_graph.node_layer_low(to_rr); int to_xlow = rr_graph.node_xlow(to_rr); int to_ylow = rr_graph.node_ylow(to_rr); int to_xhigh = rr_graph.node_xhigh(to_rr); diff --git a/vpr/src/route/connection_router.tpp b/vpr/src/route/connection_router.tpp index 36a80052983..b22a879706b 100644 --- a/vpr/src/route/connection_router.tpp +++ b/vpr/src/route/connection_router.tpp @@ -178,7 +178,7 @@ void ConnectionRouter::timing_driven_route_connection_from_heap(RRNodeId s if (rr_graph_->node_type(sink_node) == e_rr_type::SINK) { // We need to get a bounding box for the sink's entire tile vtr::Rect tile_bb = grid_.get_tile_bb({rr_graph_->node_xlow(sink_node), rr_graph_->node_ylow(sink_node), - rr_graph_->node_layer(sink_node)}); + rr_graph_->node_layer_low(sink_node)}); target_bb.xmin = tile_bb.xmin(); target_bb.ymin = tile_bb.ymin(); @@ -191,8 +191,8 @@ void ConnectionRouter::timing_driven_route_connection_from_heap(RRNodeId s target_bb.ymax = rr_graph_->node_yhigh(sink_node); } - target_bb.layer_min = rr_graph_->node_layer(RRNodeId(sink_node)); - target_bb.layer_max = rr_graph_->node_layer(RRNodeId(sink_node)); + target_bb.layer_min = rr_graph_->node_layer_low(RRNodeId(sink_node)); + target_bb.layer_max = rr_graph_->node_layer_high(RRNodeId(sink_node)); // Start measuring path search time std::chrono::steady_clock::time_point begin_time = std::chrono::steady_clock::now(); @@ -408,8 +408,8 @@ inline void expand_highfanout_bounding_box(t_bb& bb, const t_bb& net_bb, RRNodeI bb.ymin = std::max(net_bb.ymin, std::min(bb.ymin, rr_graph->node_ylow(inode))); bb.xmax = std::min(net_bb.xmax, std::max(bb.xmax, rr_graph->node_xhigh(inode))); bb.ymax = std::min(net_bb.ymax, std::max(bb.ymax, rr_graph->node_yhigh(inode))); - bb.layer_min = std::min(bb.layer_min, rr_graph->node_layer(inode)); - bb.layer_max = std::max(bb.layer_max, rr_graph->node_layer(inode)); + bb.layer_min = std::min(bb.layer_min, rr_graph->node_layer_low(inode)); + bb.layer_max = std::max(bb.layer_max, rr_graph->node_layer_high(inode)); } /* Expand bb by HIGH_FANOUT_BB_FAC and clip against net_bb */ @@ -446,7 +446,7 @@ t_bb ConnectionRouter::add_high_fanout_route_tree_to_heap( int target_bin_x = grid_to_bin_x(rr_graph_->node_xlow(target_node), spatial_rt_lookup); int target_bin_y = grid_to_bin_y(rr_graph_->node_ylow(target_node), spatial_rt_lookup); - auto target_layer = rr_graph_->node_layer(target_node); + short target_layer = rr_graph_->node_layer_low(target_node); int chan_nodes_added = 0; @@ -455,8 +455,8 @@ t_bb ConnectionRouter::add_high_fanout_route_tree_to_heap( highfanout_bb.xmax = rr_graph_->node_xhigh(target_node); highfanout_bb.ymin = rr_graph_->node_ylow(target_node); highfanout_bb.ymax = rr_graph_->node_yhigh(target_node); - highfanout_bb.layer_min = target_layer; - highfanout_bb.layer_max = target_layer; + highfanout_bb.layer_min = rr_graph_->node_layer_low(target_node); + highfanout_bb.layer_max = rr_graph_->node_layer_high(target_node); //Add existing routing starting from the target bin. //If the target's bin has insufficient existing routing add from the surrounding bins @@ -489,7 +489,7 @@ t_bb ConnectionRouter::add_high_fanout_route_tree_to_heap( if (!inside_bb(rr_node_to_add, net_bounding_box)) continue; - auto rt_node_layer_num = rr_graph_->node_layer(rr_node_to_add); + auto rt_node_layer_num = rr_graph_->node_layer_low(rr_node_to_add); if (rt_node_layer_num == target_layer) found_node_on_same_layer = true; diff --git a/vpr/src/route/overuse_report.cpp b/vpr/src/route/overuse_report.cpp index 63025630184..bdf470fa36b 100644 --- a/vpr/src/route/overuse_report.cpp +++ b/vpr/src/route/overuse_report.cpp @@ -17,10 +17,16 @@ */ static void generate_node_to_net_lookup(const Netlist<>& net_list, std::map>& rr_node_to_net_map); + +///@brief Print out information specific to IPIN/OPIN type rr nodes static void report_overused_ipin_opin(std::ostream& os, RRNodeId node_id, const std::map>& rr_node_to_net_map); + +///@brief Print out information specific to CHANX/CHANY type rr nodes static void report_overused_chanx_chany(std::ostream& os, RRNodeId node_id); + +///@brief Print out information specific to SOURCE/SINK type rr nodes static void report_overused_source_sink(std::ostream& os, RRNodeId node_id); static void report_congested_nets(const Netlist<>& net_list, const AtomLookup& atom_lookup, @@ -112,7 +118,7 @@ void report_overused_nodes(const Netlist<>& net_list, size_t inode = 0; for (const auto& lookup_pair : over_used_nodes_to_nets_lookup) { const RRNodeId node_id = lookup_pair.first; - const auto& congested_nets = lookup_pair.second; + const std::set& congested_nets = lookup_pair.second; os << "************************************************\n\n"; //Separation line @@ -123,12 +129,12 @@ void report_overused_nodes(const Netlist<>& net_list, os << "Capacity = " << rr_graph.node_capacity(node_id) << "\n\n"; /* Report selective info based on the rr node type */ - auto node_type = rr_graph.node_type(node_id); + e_rr_type node_type = rr_graph.node_type(node_id); os << "Node type = " << rr_graph.node_type_string(node_id) << '\n'; bool report_sinks = false; int x = rr_graph.node_xlow(node_id); int y = rr_graph.node_ylow(node_id); - int layer_num = rr_graph.node_layer(node_id); + int layer_num = rr_graph.node_layer_low(node_id); switch (node_type) { case e_rr_type::IPIN: case e_rr_type::OPIN: @@ -149,6 +155,8 @@ void report_overused_nodes(const Netlist<>& net_list, report_sinks = true; break; + // TODO: handle CHANZ nodes + default: break; } @@ -219,7 +227,6 @@ static void generate_node_to_net_lookup(const Netlist<>& net_list, } } -///@brief Print out information specific to IPIN/OPIN type rr nodes static void report_overused_ipin_opin(std::ostream& os, RRNodeId node_id, const std::map>& rr_node_to_net_map) { @@ -230,7 +237,7 @@ static void report_overused_ipin_opin(std::ostream& os, t_physical_tile_loc grid_loc; grid_loc.x = rr_graph.node_xlow(node_id); grid_loc.y = rr_graph.node_ylow(node_id); - grid_loc.layer_num = rr_graph.node_layer(node_id); + grid_loc.layer_num = rr_graph.node_layer_low(node_id); const t_physical_tile_type_ptr physical_type = device_ctx.grid.get_physical_type(grid_loc); VTR_ASSERT_MSG(grid_loc.x == rr_graph.node_xhigh(node_id) && grid_loc.y == rr_graph.node_yhigh(node_id), @@ -241,7 +248,7 @@ static void report_overused_ipin_opin(std::ostream& os, os << "On Tile Pin" << "\n"; } else { - const char* pb_type_name = get_pb_graph_node_from_pin_physical_num(physical_type, rr_graph.node_ptc_num(node_id)) ->pb_type->name; + const char* pb_type_name = get_pb_graph_node_from_pin_physical_num(physical_type, rr_graph.node_ptc_num(node_id))->pb_type->name; const t_pb_graph_pin* pb_pin = get_pb_pin_from_pin_physical_num(physical_type, rr_graph.node_ptc_num(node_id)); os << "Intra-Tile Pin - Port : " << pb_pin->port->name << " - PB Type : " << std::string(pb_type_name) << "\n"; } @@ -276,7 +283,6 @@ static void report_overused_ipin_opin(std::ostream& os, } } -///@brief Print out information specific to CHANX/CHANY type rr nodes static void report_overused_chanx_chany(std::ostream& os, RRNodeId node_id) { const auto& device_ctx = g_vpr_ctx.device(); const auto& rr_graph = device_ctx.rr_graph; @@ -290,7 +296,6 @@ static void report_overused_chanx_chany(std::ostream& os, RRNodeId node_id) { os << rr_graph.node_coordinate_to_string(node_id) << '\n'; } -///@brief Print out information specific to SOURCE/SINK type rr nodes static void report_overused_source_sink(std::ostream& os, RRNodeId node_id) { const auto& device_ctx = g_vpr_ctx.device(); const auto& rr_graph = device_ctx.rr_graph; @@ -391,11 +396,11 @@ static void log_single_overused_node_status(int overuse_index, RRNodeId node_id) const auto& route_ctx = g_vpr_ctx.routing(); int x = rr_graph.node_xlow(node_id); int y = rr_graph.node_ylow(node_id); - int layer_num = rr_graph.node_layer(node_id); - auto physical_blk = device_ctx.grid.get_physical_type({x, y, layer_num}); + int layer_num = rr_graph.node_layer_low(node_id); + t_physical_tile_type_ptr physical_blk = device_ctx.grid.get_physical_type({x, y, layer_num}); //Determines if direction or side is available for printing - auto node_type = rr_graph.node_type(node_id); + e_rr_type node_type = rr_graph.node_type(node_id); //Overuse # VTR_LOG("%6d", overuse_index); diff --git a/vpr/src/route/parallel_connection_router.cpp b/vpr/src/route/parallel_connection_router.cpp index 8fdba6acd38..2016b40f390 100644 --- a/vpr/src/route/parallel_connection_router.cpp +++ b/vpr/src/route/parallel_connection_router.cpp @@ -332,7 +332,7 @@ void ParallelConnectionRouter::timing_driven_expand_neighbour(const RTExpl // IPIN's of the target block should be contained within it's bounding box int to_xlow = this->rr_graph_->node_xlow(to_node); int to_ylow = this->rr_graph_->node_ylow(to_node); - int to_layer = this->rr_graph_->node_layer(to_node); + int to_layer = this->rr_graph_->node_layer_low(to_node); int to_xhigh = this->rr_graph_->node_xhigh(to_node); int to_yhigh = this->rr_graph_->node_yhigh(to_node); if (to_xlow < target_bb.xmin diff --git a/vpr/src/route/route_common.cpp b/vpr/src/route/route_common.cpp index e32fc4d490a..a12cd5e2187 100644 --- a/vpr/src/route/route_common.cpp +++ b/vpr/src/route/route_common.cpp @@ -456,7 +456,7 @@ static float comp_initial_acc_cost(RRNodeId node_id, if (rr_type == e_rr_type::CHANX) { int y = rr_graph.node_ylow(node_id); - int layer = rr_graph.node_layer(node_id); + int layer = rr_graph.node_layer_low(node_id); for (int x = rr_graph.node_xlow(node_id); x <= rr_graph.node_xhigh(node_id); x++) { max_util = std::max(max_util, chanx_util[layer][x][y]); } @@ -464,7 +464,7 @@ static float comp_initial_acc_cost(RRNodeId node_id, } else { VTR_ASSERT_SAFE(rr_type == e_rr_type::CHANY); int x = rr_graph.node_xlow(node_id); - int layer = rr_graph.node_layer(node_id); + int layer = rr_graph.node_layer_low(node_id); for (int y = rr_graph.node_ylow(node_id); y <= rr_graph.node_yhigh(node_id); y++) { max_util = std::max(max_util, chany_util[layer][x][y]); } @@ -777,8 +777,8 @@ t_bb load_net_route_bb(const Netlist<>& net_list, int ymin = rr_graph.node_ylow(driver_rr); int xmax = rr_graph.node_xhigh(driver_rr); int ymax = rr_graph.node_yhigh(driver_rr); - int layer_min = rr_graph.node_layer(driver_rr); - int layer_max = rr_graph.node_layer(driver_rr); + int layer_min = rr_graph.node_layer_low(driver_rr); + int layer_max = rr_graph.node_layer_high(driver_rr); auto net_sinks = net_list.net_sinks(net_id); for (size_t ipin = 1; ipin < net_sinks.size() + 1; ++ipin) { //Start at 1 since looping through sinks @@ -788,19 +788,19 @@ t_bb load_net_route_bb(const Netlist<>& net_list, VTR_ASSERT(rr_graph.node_xlow(sink_rr) <= rr_graph.node_xhigh(sink_rr)); VTR_ASSERT(rr_graph.node_ylow(sink_rr) <= rr_graph.node_yhigh(sink_rr)); - VTR_ASSERT(rr_graph.node_layer(sink_rr) >= 0); - VTR_ASSERT(rr_graph.node_layer(sink_rr) <= (int)device_ctx.grid.get_num_layers() - 1); + VTR_ASSERT(rr_graph.node_layer_low(sink_rr) >= 0); + VTR_ASSERT(rr_graph.node_layer_low(sink_rr) <= (int)device_ctx.grid.get_num_layers() - 1); vtr::Rect tile_bb = device_ctx.grid.get_tile_bb({rr_graph.node_xlow(sink_rr), rr_graph.node_ylow(sink_rr), - rr_graph.node_layer(sink_rr)}); + rr_graph.node_layer_low(sink_rr)}); xmin = std::min(xmin, tile_bb.xmin()); xmax = std::max(xmax, tile_bb.xmax()); ymin = std::min(ymin, tile_bb.ymin()); ymax = std::max(ymax, tile_bb.ymax()); - layer_min = std::min(layer_min, rr_graph.node_layer(sink_rr)); - layer_max = std::max(layer_max, rr_graph.node_layer(sink_rr)); + layer_min = std::min(layer_min, rr_graph.node_layer_low(sink_rr)); + layer_max = std::max(layer_max, rr_graph.node_layer_high(sink_rr)); } // Want the channels on all 4 sides to be usable, even if bb_factor = 0. @@ -869,7 +869,7 @@ void reserve_locally_used_opins(HeapInterface* heap, float pres_fac, float acc_f auto port_eq = get_port_equivalency_from_class_physical_num(type, iclass); VTR_ASSERT(port_eq == PortEquivalence::INSTANCE); - /* Always 0 for pads and for RECEIVER (IPIN) classes */ + // Always 0 for pads and for RECEIVER (IPIN) classes for (ipin = 0; ipin < num_local_opin; ipin++) { RRNodeId inode = route_ctx.clb_opins_used_locally[blk_id][iclass][ipin]; VTR_ASSERT(inode && size_t(inode) < rr_graph.num_nodes()); diff --git a/vpr/src/route/route_common.h b/vpr/src/route/route_common.h index 9c67467cc54..74343ff84c3 100644 --- a/vpr/src/route/route_common.h +++ b/vpr/src/route/route_common.h @@ -67,11 +67,11 @@ inline bool inside_bb(RRNodeId inode, const t_bb& bb) { if (dir == Direction::DEC) { x = rr_graph.node_xhigh(inode); y = rr_graph.node_yhigh(inode); - z = rr_graph.node_layer(inode); + z = rr_graph.node_layer_high(inode); } else { x = rr_graph.node_xlow(inode); y = rr_graph.node_ylow(inode); - z = rr_graph.node_layer(inode); + z = rr_graph.node_layer_low(inode); } return x >= bb.xmin && x <= bb.xmax && y >= bb.ymin && y <= bb.ymax && z >= bb.layer_min && z <= bb.layer_max; diff --git a/vpr/src/route/route_utilization.cpp b/vpr/src/route/route_utilization.cpp index c01d0a62c8c..194c736d79b 100644 --- a/vpr/src/route/route_utilization.cpp +++ b/vpr/src/route/route_utilization.cpp @@ -71,7 +71,7 @@ vtr::Matrix calculate_routing_usage(e_rr_type rr_type, bool is_flat, bool #ifndef NO_GRAPHICS if (!is_print) { t_draw_state* draw_state = get_draw_state_vars(); - int layer_num = rr_graph.node_layer(rr_node); + int layer_num = rr_graph.node_layer_low(rr_node); if (!draw_state->draw_layer_display[layer_num].visible) continue; // don't count usage if layer is not visible } diff --git a/vpr/src/route/route_utils.cpp b/vpr/src/route/route_utils.cpp index 0ca62ef1964..ed308079621 100644 --- a/vpr/src/route/route_utils.cpp +++ b/vpr/src/route/route_utils.cpp @@ -614,10 +614,10 @@ t_bb calc_current_bb(const RouteTree& tree) { //and xlow/ylow for xmax/ymax calculations bb.xmin = std::min(bb.xmin, rr_graph.node_xhigh(rt_node.inode)); bb.ymin = std::min(bb.ymin, rr_graph.node_yhigh(rt_node.inode)); - bb.layer_min = std::min(bb.layer_min, rr_graph.node_layer(rt_node.inode)); + bb.layer_min = std::min(bb.layer_min, rr_graph.node_layer_high(rt_node.inode)); bb.xmax = std::max(bb.xmax, rr_graph.node_xlow(rt_node.inode)); bb.ymax = std::max(bb.ymax, rr_graph.node_ylow(rt_node.inode)); - bb.layer_max = std::max(bb.layer_max, rr_graph.node_layer(rt_node.inode)); + bb.layer_max = std::max(bb.layer_max, rr_graph.node_layer_low(rt_node.inode)); } VTR_ASSERT(bb.xmin <= bb.xmax); diff --git a/vpr/src/route/router_lookahead/router_lookahead.cpp b/vpr/src/route/router_lookahead/router_lookahead.cpp index b371dc4395a..82e892d5961 100644 --- a/vpr/src/route/router_lookahead/router_lookahead.cpp +++ b/vpr/src/route/router_lookahead/router_lookahead.cpp @@ -74,7 +74,7 @@ float ClassicLookahead::get_expected_cost(RRNodeId current_node, RRNodeId target } std::pair ClassicLookahead::get_expected_delay_and_cong(RRNodeId node, RRNodeId target_node, const t_conn_cost_params& params, float R_upstream) const { - auto& device_ctx = g_vpr_ctx.device(); + const DeviceContext& device_ctx = g_vpr_ctx.device(); const auto& rr_graph = device_ctx.rr_graph; e_rr_type rr_type = rr_graph.node_type(node); @@ -82,7 +82,7 @@ std::pair ClassicLookahead::get_expected_delay_and_cong(RRNodeId n if (rr_type == e_rr_type::CHANX || rr_type == e_rr_type::CHANY) { auto [num_segs_same_dir, num_segs_ortho_dir] = get_expected_segs_to_target(node, target_node); - auto cost_index = rr_graph.node_cost_index(node); + RRIndexedDataId cost_index = rr_graph.node_cost_index(node); int ortho_cost_index = device_ctx.rr_indexed_data[cost_index].ortho_cost_index; const auto& same_data = device_ctx.rr_indexed_data[cost_index]; diff --git a/vpr/src/route/router_lookahead/router_lookahead_compressed_map.cpp b/vpr/src/route/router_lookahead/router_lookahead_compressed_map.cpp index a519d65bf8a..c332205378c 100644 --- a/vpr/src/route/router_lookahead/router_lookahead_compressed_map.cpp +++ b/vpr/src/route/router_lookahead/router_lookahead_compressed_map.cpp @@ -121,7 +121,7 @@ static void compute_router_wire_compressed_lookahead(const std::vector(grid.get_num_layers()), 2, segment_inf_vec.size(), - static_cast(grid.get_num_layers()), + grid.get_num_layers(), static_cast(num_sampling_points)}); int longest_seg_length = 0; @@ -422,8 +422,10 @@ std::pair CompressedMapLookahead::get_expected_delay_and_cong(RRNo auto& device_ctx = g_vpr_ctx.device(); auto& rr_graph = device_ctx.rr_graph; - int from_layer_num = rr_graph.node_layer(from_node); - int to_layer_num = rr_graph.node_layer(to_node); + // TODO: handle CHANZ nodes that span multiple layers + int from_layer_num = rr_graph.node_layer_low(from_node); + // to_node is a SINK, so its layer_low == layer_high + int to_layer_num = rr_graph.node_layer_low(to_node); auto [delta_x, delta_y] = util::get_xy_deltas(from_node, to_node); delta_x = abs(delta_x); delta_y = abs(delta_y); @@ -444,7 +446,7 @@ std::pair CompressedMapLookahead::get_expected_delay_and_cong(RRNo auto from_tile_index = std::distance(&device_ctx.physical_tile_types[0], from_tile_type); - auto from_ptc = rr_graph.node_ptc_num(from_node); + int from_ptc = rr_graph.node_ptc_num(from_node); std::tie(expected_delay_cost, expected_cong_cost) = util::get_cost_from_src_opin(src_opin_delays[from_layer_num][from_tile_index][from_ptc][to_layer_num], delta_x, @@ -469,7 +471,7 @@ std::pair CompressedMapLookahead::get_expected_delay_and_cong(RRNo } else if (from_type == e_rr_type::CHANX || from_type == e_rr_type::CHANY) { //When estimating costs from a wire, we directly look-up the result in the wire lookahead (f_wire_cost_map) - auto from_cost_index = rr_graph.node_cost_index(from_node); + RRIndexedDataId from_cost_index = rr_graph.node_cost_index(from_node); int from_seg_index = device_ctx.rr_indexed_data[from_cost_index].seg_index; VTR_ASSERT(from_seg_index >= 0); diff --git a/vpr/src/route/router_lookahead/router_lookahead_extended_map.cpp b/vpr/src/route/router_lookahead/router_lookahead_extended_map.cpp index 28126de5951..02d4e4cc931 100644 --- a/vpr/src/route/router_lookahead/router_lookahead_extended_map.cpp +++ b/vpr/src/route/router_lookahead/router_lookahead_extended_map.cpp @@ -73,11 +73,11 @@ std::pair ExtendedMapLookahead::get_src_opin_cost(RRNodeId from_no t_physical_tile_type_ptr tile_type = device_ctx.grid.get_physical_type({rr_graph.node_xlow(from_node), rr_graph.node_ylow(from_node), - rr_graph.node_layer(from_node)}); - auto tile_index = tile_type->index; + rr_graph.node_layer_low(from_node)}); + int tile_index = tile_type->index; - auto from_ptc = rr_graph.node_ptc_num(from_node); - int from_layer_num = rr_graph.node_layer(from_node); + int from_ptc = rr_graph.node_ptc_num(from_node); + int from_layer_num = rr_graph.node_layer_low(from_node); if (this->src_opin_delays[from_layer_num][tile_index][from_ptc].empty()) { //During lookahead profiling we were unable to find any wires which connected @@ -152,13 +152,13 @@ float ExtendedMapLookahead::get_chan_ipin_delays(RRNodeId to_node) const { e_rr_type to_type = rr_graph.node_type(to_node); VTR_ASSERT(to_type == e_rr_type::SINK || to_type == e_rr_type::IPIN); - auto to_tile_type = device_ctx.grid.get_physical_type({rr_graph.node_xlow(to_node), - rr_graph.node_ylow(to_node), - rr_graph.node_layer(to_node)}); - auto to_tile_index = to_tile_type->index; + t_physical_tile_type_ptr to_tile_type = device_ctx.grid.get_physical_type({rr_graph.node_xlow(to_node), + rr_graph.node_ylow(to_node), + rr_graph.node_layer_low(to_node)}); + int to_tile_index = to_tile_type->index; - auto to_ptc = rr_graph.node_ptc_num(to_node); - int to_layer_num = rr_graph.node_layer(to_node); + int to_ptc = rr_graph.node_ptc_num(to_node); + int to_layer_num = rr_graph.node_layer_low(to_node); float site_pin_delay = 0.f; if (this->chan_ipins_delays[to_layer_num][to_tile_index].size() != 0) { @@ -192,11 +192,10 @@ std::pair ExtendedMapLookahead::get_expected_delay_and_cong(RRNode int to_x = rr_graph.node_xlow(to_node); int to_y = rr_graph.node_ylow(to_node); - int to_layer_num = rr_graph.node_layer(to_node); + int to_layer_num = rr_graph.node_layer_low(to_node); - int dx, dy; - dx = to_x - from_x; - dy = to_y - from_y; + int dx = to_x - from_x; + int dy = to_y - from_y; e_rr_type from_type = rr_graph.node_type(from_node); if (from_type == e_rr_type::SOURCE || from_type == e_rr_type::OPIN) { diff --git a/vpr/src/route/router_lookahead/router_lookahead_map.cpp b/vpr/src/route/router_lookahead/router_lookahead_map.cpp index 6a9b7e16eb3..cef970e0d7c 100644 --- a/vpr/src/route/router_lookahead/router_lookahead_map.cpp +++ b/vpr/src/route/router_lookahead/router_lookahead_map.cpp @@ -141,6 +141,7 @@ static void set_lookahead_map_costs(unsigned from_layer_num, /* fills in missing lookahead map entries by copying the cost of the closest valid entry */ static void fill_in_missing_lookahead_entries(int segment_index, e_rr_type chan_type); + /* returns a cost entry in the f_wire_cost_map that is near the specified coordinates (and preferably towards (0,0)) */ static util::Cost_Entry get_nearby_cost_entry(int from_layer_num, int x, int y, int to_layer_num, int segment_index, int chan_index); @@ -188,7 +189,7 @@ float MapLookahead::get_expected_cost(RRNodeId current_node, RRNodeId target_nod } else if (from_rr_type == e_rr_type::IPIN) { // Change if you're allowing route-throughs return (device_ctx.rr_indexed_data[RRIndexedDataId(SINK_COST_INDEX)].base_cost); } else { // Change this if you want to investigate route-throughs - return (0.); + return 0.f; } } } @@ -206,17 +207,17 @@ float MapLookahead::get_expected_cost_flat_router(RRNodeId current_node, RRNodeI t_physical_tile_type_ptr from_physical_type = device_ctx.grid.get_physical_type({rr_graph.node_xlow(current_node), rr_graph.node_ylow(current_node), - rr_graph.node_layer(current_node)}); + rr_graph.node_layer_low(current_node)}); int from_node_ptc_num = rr_graph.node_ptc_num(current_node); t_physical_tile_type_ptr to_physical_type = device_ctx.grid.get_physical_type({rr_graph.node_xlow(target_node), rr_graph.node_ylow(target_node), - rr_graph.node_layer(target_node)}); + rr_graph.node_layer_low(target_node)}); float delay_offset_cost = 0.; float cong_offset_cost = 0.; int to_node_ptc_num = rr_graph.node_ptc_num(target_node); - int to_layer_num = rr_graph.node_layer(target_node); + int to_layer_num = rr_graph.node_layer_low(target_node); // We have not checked the multi-layer FPGA for flat routing - VTR_ASSERT(rr_graph.node_layer(current_node) == rr_graph.node_layer(target_node)); + VTR_ASSERT(rr_graph.node_layer_low(current_node) == rr_graph.node_layer_low(target_node)); if (from_rr_type == e_rr_type::CHANX || from_rr_type == e_rr_type::CHANY) { std::tie(delay_cost, cong_cost) = get_expected_delay_and_cong(current_node, target_node, params, R_upstream); @@ -258,8 +259,8 @@ float MapLookahead::get_expected_cost_flat_router(RRNodeId current_node, RRNodeI auto [delta_x, delta_y] = util::get_xy_deltas(current_node, target_node); delta_x = abs(delta_x); delta_y = abs(delta_y); - delay_cost = params.criticality * chann_distance_based_min_cost[rr_graph.node_layer(current_node)][to_layer_num][delta_x][delta_y].delay; - cong_cost = (1. - params.criticality) * chann_distance_based_min_cost[rr_graph.node_layer(current_node)][to_layer_num][delta_x][delta_y].congestion; + delay_cost = params.criticality * chann_distance_based_min_cost[rr_graph.node_layer_low(current_node)][to_layer_num][delta_x][delta_y].delay; + cong_cost = (1. - params.criticality) * chann_distance_based_min_cost[rr_graph.node_layer_low(current_node)][to_layer_num][delta_x][delta_y].congestion; delay_offset_cost = params.criticality * tile_min_cost.at(to_physical_type->index).at(to_node_ptc_num).delay; cong_offset_cost = (1. - params.criticality) * tile_min_cost.at(to_physical_type->index).at(to_node_ptc_num).congestion; @@ -289,8 +290,8 @@ float MapLookahead::get_expected_cost_flat_router(RRNodeId current_node, RRNodeI auto [delta_x, delta_y] = util::get_xy_deltas(current_node, target_node); delta_x = abs(delta_x); delta_y = abs(delta_y); - delay_cost = params.criticality * chann_distance_based_min_cost[rr_graph.node_layer(current_node)][to_layer_num][delta_x][delta_y].delay; - cong_cost = (1. - params.criticality) * chann_distance_based_min_cost[rr_graph.node_layer(current_node)][to_layer_num][delta_x][delta_y].congestion; + delay_cost = params.criticality * chann_distance_based_min_cost[rr_graph.node_layer_low(current_node)][to_layer_num][delta_x][delta_y].delay; + cong_cost = (1. - params.criticality) * chann_distance_based_min_cost[rr_graph.node_layer_low(current_node)][to_layer_num][delta_x][delta_y].congestion; delay_offset_cost = params.criticality * tile_min_cost.at(to_physical_type->index).at(to_node_ptc_num).delay; cong_offset_cost = (1. - params.criticality) * tile_min_cost.at(to_physical_type->index).at(to_node_ptc_num).congestion; @@ -309,8 +310,8 @@ std::pair MapLookahead::get_expected_delay_and_cong(RRNodeId from_ const auto& device_ctx = g_vpr_ctx.device(); const auto& rr_graph = device_ctx.rr_graph; - int from_layer_num = rr_graph.node_layer(from_node); - int to_layer_num = rr_graph.node_layer(to_node); + int from_layer_num = rr_graph.node_layer_low(from_node); + int to_layer_num = rr_graph.node_layer_low(to_node); auto [delta_x, delta_y] = util::get_xy_deltas(from_node, to_node); delta_x = abs(delta_x); delta_y = abs(delta_y); @@ -361,15 +362,28 @@ std::pair MapLookahead::get_expected_delay_and_cong(RRNodeId from_ .c_str()) .c_str()); - } else if (from_type == e_rr_type::CHANX || from_type == e_rr_type::CHANY) { - //When estimating costs from a wire, we directly look-up the result in the wire lookahead (f_wire_cost_map) + } else if (from_type == e_rr_type::CHANX || from_type == e_rr_type::CHANY || from_type == e_rr_type::CHANZ) { + // When estimating costs from a wire, we directly look-up the result in the wire lookahead (f_wire_cost_map) + + // For CHANZ nodes, if the direction is + // 1) incremental --> `chanz_node` now drives other nodes on node_layer_high(chanz_node). + // 2) decremental --> `chanz_node` now drives other nodes on node_layer_low(chanz_node). + // 3) decremental --> `chanz_node` now drives other nodes on both layers, so we choose the target layer + if (from_type == e_rr_type::CHANZ) { + Direction chanz_node_dir = rr_graph.node_direction(from_node); + if (chanz_node_dir == Direction::INC) { + from_layer_num = rr_graph.node_layer_high(from_node); + } else if (chanz_node_dir == Direction::BIDIR) { + from_layer_num = to_layer_num; + } + } - auto from_cost_index = rr_graph.node_cost_index(from_node); + RRIndexedDataId from_cost_index = rr_graph.node_cost_index(from_node); int from_seg_index = device_ctx.rr_indexed_data[from_cost_index].seg_index; VTR_ASSERT(from_seg_index >= 0); - /* now get the expected cost from our lookahead map */ + // Now get the expected cost from our lookahead map util::Cost_Entry cost_entry = get_wire_cost_entry(from_type, from_seg_index, from_layer_num, @@ -391,9 +405,9 @@ std::pair MapLookahead::get_expected_delay_and_cong(RRNodeId from_ .c_str()); expected_delay_cost = cost_entry.delay * params.criticality; expected_cong_cost = cost_entry.congestion * (1 - params.criticality); - } else if (from_type == e_rr_type::IPIN) { /* Change if you're allowing route-throughs */ + } else if (from_type == e_rr_type::IPIN) { // Change if you're allowing route-throughs return std::make_pair(0., device_ctx.rr_indexed_data[RRIndexedDataId(SINK_COST_INDEX)].base_cost); - } else { /* Change this if you want to investigate route-throughs */ + } else { // Change this if you want to investigate route-throughs return std::make_pair(0., 0.); } @@ -403,8 +417,8 @@ std::pair MapLookahead::get_expected_delay_and_cong(RRNodeId from_ void MapLookahead::compute(const std::vector& segment_inf) { vtr::ScopedStartFinishTimer timer("Computing router lookahead map"); - //First compute the delay map when starting from the various wire types - //(CHANX/CHANY)in the routing architecture + // First compute the delay map when starting from the various wire types + // (CHANX/CHANY/CHANZ) in the routing architecture compute_router_wire_lookahead(segment_inf, route_verbosity_); //Next, compute which wire types are accessible (and the cost to reach them) @@ -482,18 +496,14 @@ float MapLookahead::get_opin_distance_min_delay(int physical_tile_idx, int from_ /******** Function Definitions ********/ static util::Cost_Entry get_wire_cost_entry(e_rr_type rr_type, int seg_index, int from_layer_num, int delta_x, int delta_y, int to_layer_num) { - VTR_ASSERT_SAFE(rr_type == e_rr_type::CHANX || rr_type == e_rr_type::CHANY); + VTR_ASSERT_SAFE(rr_type == e_rr_type::CHANX || rr_type == e_rr_type::CHANY || rr_type == e_rr_type::CHANZ); VTR_ASSERT_SAFE(from_layer_num < static_cast(f_wire_cost_map.dim_size(0))); VTR_ASSERT_SAFE(to_layer_num < static_cast(f_wire_cost_map.dim_size(1))); VTR_ASSERT_SAFE(seg_index < static_cast(f_wire_cost_map.dim_size(3))); VTR_ASSERT_SAFE(delta_x < static_cast(f_wire_cost_map.dim_size(4))); VTR_ASSERT_SAFE(delta_y < static_cast(f_wire_cost_map.dim_size(5))); - int chan_index = 0; - if (rr_type == e_rr_type::CHANY) { - chan_index = 1; - } - + const int chan_index = util::chan_type_to_index(rr_type); return f_wire_cost_map[from_layer_num][to_layer_num][chan_index][seg_index][delta_x][delta_y]; } @@ -504,29 +514,37 @@ static void compute_router_wire_lookahead(const std::vector& segm const auto& device_ctx = g_vpr_ctx.device(); const auto& grid = device_ctx.grid; + const size_t num_layers = grid.get_num_layers(); + const size_t chan_type_dim_size = (num_layers == 1) ? 2 : 3; + //Re-allocate - f_wire_cost_map = t_wire_cost_map({static_cast(grid.get_num_layers()), - static_cast(grid.get_num_layers()), - 2, + f_wire_cost_map = t_wire_cost_map({num_layers, + num_layers, + chan_type_dim_size, segment_inf_vec.size(), device_ctx.grid.width(), device_ctx.grid.height()}); int longest_seg_length = 0; - for (const auto& seg_inf : segment_inf_vec) { + for (const t_segment_inf& seg_inf : segment_inf_vec) { longest_seg_length = std::max(longest_seg_length, seg_inf.length); } // Profile each wire segment type - for (size_t from_layer_num = 0; from_layer_num < grid.get_num_layers(); from_layer_num++) { + for (size_t from_layer_num = 0; from_layer_num < num_layers; from_layer_num++) { for (const t_segment_inf& segment_inf : segment_inf_vec) { std::vector chan_types; - if (segment_inf.parallel_axis == e_parallel_axis::X_AXIS) + if (segment_inf.parallel_axis == e_parallel_axis::X_AXIS) { chan_types.push_back(e_rr_type::CHANX); - else if (segment_inf.parallel_axis == e_parallel_axis::Y_AXIS) + } else if (segment_inf.parallel_axis == e_parallel_axis::Y_AXIS) { chan_types.push_back(e_rr_type::CHANY); - else //Both for BOTH_AXIS segments and special segments such as clock_networks we want to search in both directions. + } else if (segment_inf.parallel_axis == e_parallel_axis::Z_AXIS) { + chan_types.push_back(e_rr_type::CHANZ); + } else { + VTR_ASSERT(segment_inf.parallel_axis == e_parallel_axis::BOTH_AXIS); + // Both for BOTH_AXIS segments and special segments such as clock_networks we want to search in both directions. chan_types.insert(chan_types.end(), {e_rr_type::CHANX, e_rr_type::CHANY}); + } for (e_rr_type chan_type : chan_types) { util::t_routing_cost_map routing_cost_map = util::get_routing_cost_map(longest_seg_length, @@ -544,8 +562,8 @@ static void compute_router_wire_lookahead(const std::vector& segm // and store it in the lookahead cost map set_lookahead_map_costs(from_layer_num, segment_inf.seg_index, chan_type, routing_cost_map); - /* fill in missing entries in the lookahead cost map by copying the closest cost entries (cost map was computed based on - * a reference coordinate > (0,0) so some entries that represent a cross-chip distance have not been computed) */ + // Fill in missing entries in the lookahead cost map by copying the closest cost entries (cost map was computed based on + // a reference coordinate > (0,0) so some entries that represent a cross-chip distance have not been computed) fill_in_missing_lookahead_entries(segment_inf.seg_index, chan_type); } } @@ -556,7 +574,7 @@ static void set_lookahead_map_costs(unsigned from_layer_num, int segment_index, e_rr_type chan_type, util::t_routing_cost_map& routing_cost_map) { - int chan_index = (chan_type == e_rr_type::CHANX) ? 0 : 1; + const int chan_index = util::chan_type_to_index(chan_type); // set the lookahead cost map entries with a representative cost entry from routing_cost_map for (unsigned to_layer = 0; to_layer < routing_cost_map.dim_size(0); to_layer++) { @@ -570,11 +588,10 @@ static void set_lookahead_map_costs(unsigned from_layer_num, } } -/* fills in missing lookahead map entries by copying the cost of the closest valid entry */ static void fill_in_missing_lookahead_entries(int segment_index, e_rr_type chan_type) { - int chan_index = (chan_type == e_rr_type::CHANX) ? 0 : 1; + const DeviceContext& device_ctx = g_vpr_ctx.device(); - auto& device_ctx = g_vpr_ctx.device(); + const int chan_index = util::chan_type_to_index(chan_type); const int num_layers = device_ctx.grid.get_num_layers(); const int grid_width = device_ctx.grid.width(); diff --git a/vpr/src/route/router_lookahead/router_lookahead_map.h b/vpr/src/route/router_lookahead/router_lookahead_map.h index 3c93943dba3..8f79abfe13b 100644 --- a/vpr/src/route/router_lookahead/router_lookahead_map.h +++ b/vpr/src/route/router_lookahead/router_lookahead_map.h @@ -41,16 +41,27 @@ class MapLookahead : public RouterLookahead { float get_opin_distance_min_delay(int physical_tile_idx, int from_layer, int to_layer, int dx, int dy) const override; }; -/* provides delay/congestion estimates to travel specified distances - * in the x/y direction */ -// This is a 6D array storing the cost to travel from a node of type CHANX/CHANY to a point that is dx, dy further, and is on the "layer_num" layer. -// To store this information, the first index is the layer number that the node under consideration is on, the second index is the layer number of the target node, the third index represents the type of channel (X/Y) -// that the node under consideration belongs to, the forth is the segment type (specified in the architecture file under the "segmentlist" tag), the fourth is the -// target "layer_num" mentioned above, the fifth is dx, and the last one is dy. -typedef vtr::NdMatrix t_wire_cost_map; //[0..num_layers][0..num_layers][0..1][[0..num_seg_types-1][0..device_ctx.grid.width()-1][0..device_ctx.grid.height()-1] - //[0..1] entry distinguish between CHANX/CHANY start nodes respectively - // The first index is the layer number that the node under consideration is on, and the second index - // is the layer number that the target node is on. +/** + * @brief Provides delay/congestion estimates to travel specified distances + * in the x/y direction + * + * This is a 6D array storing the cost to travel from a node of type CHANX/CHANY/CHANZ + * to a point that is dx, dy further, and is on the "layer_num" layer. + * + * To store this information: + * - The first index is the layer number that the node under consideration is on. + * - The second index is the layer number of the target node. + * - The third index represents the type of channel (X/Y/Z) that the node under consideration belongs to. + * - The forth is the segment type (specified in the architecture file under the "segmentlist" tag). + * - The fifth is dx. + * - The last one is dy. + * + * @note [0..num_layers][0..num_layers][0..2][0..num_seg_types-1][0..device_ctx.grid.width()-1][0..device_ctx.grid.height()-1] + * - [0..2] entry distinguish between CHANX/CHANY/CHANZ start nodes respectively + * - The first index is the layer number that the node under consideration is on. + * - The second index is the layer number that the target node is on. + */ +typedef vtr::NdMatrix t_wire_cost_map; void read_router_lookahead(const std::string& file); void write_router_lookahead(const std::string& file); diff --git a/vpr/src/route/router_lookahead/router_lookahead_map_utils.cpp b/vpr/src/route/router_lookahead/router_lookahead_map_utils.cpp index 23f2ac3db49..f476f2bb0cf 100644 --- a/vpr/src/route/router_lookahead/router_lookahead_map_utils.cpp +++ b/vpr/src/route/router_lookahead/router_lookahead_map_utils.cpp @@ -141,7 +141,7 @@ PQ_Entry::PQ_Entry(RRNodeId set_rr_node, int /*switch_ind*/, float parent_delay, this->congestion_upstream = parent_congestion_upstream; this->R_upstream = parent_R_upstream; if (!starting_node) { - auto cost_index = rr_graph.node_cost_index(RRNodeId(set_rr_node)); + RRIndexedDataId cost_index = rr_graph.node_cost_index(RRNodeId(set_rr_node)); //this->delay += rr_graph.node_C(RRNodeId(set_rr_node)) * (g_rr_switch_inf[switch_ind].R + 0.5*rr_graph.node_R(RRNodeId(set_rr_node))) + // g_rr_switch_inf[switch_ind].Tdel; @@ -543,37 +543,60 @@ t_ipin_primitive_sink_delays compute_intra_tile_dijkstra(const RRGraphView& rr_g return pin_delays; } -/* returns index of a node from which to start routing */ -RRNodeId get_start_node(int layer, int start_x, int start_y, int target_x, int target_y, e_rr_type rr_type, int seg_index, int track_offset) { +RRNodeId get_chanxy_start_node(int layer, int start_x, int start_y, int target_x, int target_y, e_rr_type rr_type, int seg_index, int track_offset) { const auto& device_ctx = g_vpr_ctx.device(); const auto& rr_graph = device_ctx.rr_graph; const auto& node_lookup = rr_graph.node_lookup(); - RRNodeId result = RRNodeId::INVALID(); + VTR_ASSERT(rr_type == e_rr_type::CHANX || rr_type == e_rr_type::CHANY); - if (rr_type != e_rr_type::CHANX && rr_type != e_rr_type::CHANY) { - VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "Must start lookahead routing from CHANX or CHANY node\n"); - } + RRNodeId result = RRNodeId::INVALID(); - /* determine which direction the wire should go in based on the start & target coordinates */ + // Determine which direction the wire should go in based on the start & target coordinates Direction direction = Direction::INC; if ((rr_type == e_rr_type::CHANX && target_x < start_x) || (rr_type == e_rr_type::CHANY && target_y < start_y)) { direction = Direction::DEC; } - int start_lookup_x = start_x; - int start_lookup_y = start_y; - - /* find first node in channel that has specified segment index and goes in the desired direction */ - for (const RRNodeId& node_id : node_lookup.find_channel_nodes(layer, start_lookup_x, start_lookup_y, rr_type)) { + // Find first node in channel that has specified segment index and goes in the desired direction + for (const RRNodeId node_id : node_lookup.find_channel_nodes(layer, start_x, start_y, rr_type)) { VTR_ASSERT(rr_graph.node_type(node_id) == rr_type); Direction node_direction = rr_graph.node_direction(node_id); - auto node_cost_ind = rr_graph.node_cost_index(node_id); + RRIndexedDataId node_cost_ind = rr_graph.node_cost_index(node_id); int node_seg_ind = device_ctx.rr_indexed_data[node_cost_ind].seg_index; if ((node_direction == direction || node_direction == Direction::BIDIR) && node_seg_ind == seg_index) { - /* found first track that has the specified segment index and goes in the desired direction */ + // Found first track that has the specified segment index and goes in the desired direction + result = node_id; + if (track_offset == 0) { + break; + } + track_offset -= 2; + } + } + + return result; +} + +RRNodeId get_chanz_start_node(int start_x, int start_y, int seg_index, int track_offset, Direction dir) { + const auto& device_ctx = g_vpr_ctx.device(); + const auto& rr_graph = device_ctx.rr_graph; + const auto& node_lookup = rr_graph.node_lookup(); + + RRNodeId result = RRNodeId::INVALID(); + + // CHANZ nodes currently span across all layers, so the value of layer is irrelevant. + const int layer = 0; + + // Find first node in channel that has specified segment index and goes in the desired direction + for (const RRNodeId node_id : node_lookup.find_channel_nodes(layer, start_x, start_y, e_rr_type::CHANZ)) { + Direction node_direction = rr_graph.node_direction(node_id); + RRIndexedDataId node_cost_ind = rr_graph.node_cost_index(node_id); + int node_seg_ind = device_ctx.rr_indexed_data[node_cost_ind].seg_index; + + if ((node_direction == dir || node_direction == Direction::BIDIR) && node_seg_ind == seg_index) { + // Found first track that has the specified segment index and goes in the desired direction result = node_id; if (track_offset == 0) { break; @@ -692,7 +715,7 @@ std::pair get_xy_deltas(RRNodeId from_node, RRNodeId to_node) { t_routing_cost_map get_routing_cost_map(int longest_seg_length, unsigned from_layer_num, - const e_rr_type& chan_type, + const e_rr_type chan_type, const t_segment_inf& segment_inf, const std::unordered_map>& sample_locs, bool sample_all_locs, @@ -701,43 +724,32 @@ t_routing_cost_map get_routing_cost_map(int longest_seg_length, const auto& rr_graph = device_ctx.rr_graph; const auto& grid = device_ctx.grid; - //Start sampling at the lower left non-corner + // Start sampling at the lower left non-corner int ref_x = 1; int ref_y = 1; - //Sample from locations near the reference location (to capture maximum distance paths) - //Also sample from locations at least the longest wire length away from the edge (to avoid - //edge effects for shorter distances) - std::vector ref_increments = {0, - 1, - longest_seg_length, - longest_seg_length + 1}; + // Sample from locations near the reference location (to capture maximum distance paths) + // Also sample from locations at least the longest wire length away from the edge (to avoid + // edge effects for shorter distances) + std::vector ref_increments{0, 1, longest_seg_length, longest_seg_length + 1}; - //Uniquify the increments (avoid sampling the same locations repeatedly if they happen to - //overlap) + // Uniquify the increments (avoid sampling the same locations repeatedly if they happen to overlap) std::stable_sort(ref_increments.begin(), ref_increments.end()); ref_increments.erase(std::unique(ref_increments.begin(), ref_increments.end()), ref_increments.end()); - //Upper right non-corner - int target_x = device_ctx.grid.width() - 2; - int target_y = device_ctx.grid.height() - 2; + // Upper right non-corner + const int target_x = device_ctx.grid.width() - 2; + const int target_y = device_ctx.grid.height() - 2; - //if arch file specifies die_number="layer_num" doesn't require inter-cluster - //programmable routing resources, then we shouldn't profile wire segment types in - //the current layer + // If arch file specifies die_number="layer_num" doesn't have inter-cluster + // programmable routing resources, then we shouldn't profile wire segment types in + // the current layer if (!device_ctx.inter_cluster_prog_routing_resources[from_layer_num]) { return t_routing_cost_map(); } - //First try to pick good representative sample locations for each type + // First try to pick good representative sample locations for each type std::vector sample_nodes; - std::vector chan_types; - if (segment_inf.parallel_axis == e_parallel_axis::X_AXIS) - chan_types.push_back(e_rr_type::CHANX); - else if (segment_inf.parallel_axis == e_parallel_axis::Y_AXIS) - chan_types.push_back(e_rr_type::CHANY); - else //Both for BOTH_AXIS segments and special segments such as clock_networks we want to search in both directions. - chan_types.insert(chan_types.end(), {e_rr_type::CHANX, e_rr_type::CHANY}); for (int ref_inc : ref_increments) { int sample_x = ref_x + ref_inc; @@ -747,31 +759,35 @@ t_routing_cost_map get_routing_cost_map(int longest_seg_length, if (sample_y >= int(grid.height())) continue; for (int track_offset = 0; track_offset < MAX_TRACK_OFFSET; track_offset += 2) { - /* get the rr node index from which to start routing */ - RRNodeId start_node = get_start_node(from_layer_num, sample_x, sample_y, - target_x, target_y, //non-corner upper right - chan_type, segment_inf.seg_index, track_offset); + // Get the rr node index from which to start routing - if (!start_node) { - continue; + RRNodeId start_node; + if (is_chanxy(chan_type)) { + start_node = get_chanxy_start_node(from_layer_num, sample_x, sample_y, + target_x, target_y, + chan_type, segment_inf.seg_index, track_offset); + } else { + VTR_ASSERT(is_chanz(chan_type)); + Direction direction = (from_layer_num == 0) ? Direction::DEC : Direction::INC; + start_node = get_chanz_start_node(sample_x, sample_x, segment_inf.seg_index, track_offset, direction); } - // TODO: Temporary - After testing benchmarks this can be deleted - VTR_ASSERT(rr_graph.node_layer(start_node) == (int)from_layer_num); - sample_nodes.emplace_back(start_node); + if (start_node) { + sample_nodes.emplace_back(start_node); + } } } - //If we failed to find any representative sample locations, search exhaustively - // - //This is to ensure we sample 'unusual' wire types which may not exist in all channels - //(e.g. clock routing) + // If we failed to find any representative sample locations, search exhaustively + // This is to ensure we sample 'unusual' wire types which may not exist in all channels (e.g. clock routing) if (sample_nodes.empty()) { // Try an exhaustive search to find a suitable sample point for (RRNodeId rr_node : rr_graph.nodes()) { e_rr_type rr_type = rr_graph.node_type(rr_node); if (rr_type != chan_type) continue; - if (rr_graph.node_layer(rr_node) != (int)from_layer_num) continue; + if (is_chanxy(rr_type) && rr_graph.node_layer_low(rr_node) != (int)from_layer_num) continue; + if (is_chanz(rr_type) && rr_graph.node_direction(rr_node) == Direction::INC && from_layer_num != 1) continue; + if (is_chanz(rr_type) && rr_graph.node_direction(rr_node) == Direction::DEC && from_layer_num != 0) continue; RRIndexedDataId cost_index = rr_graph.node_cost_index(rr_node); VTR_ASSERT(cost_index != RRIndexedDataId(UNDEFINED)); @@ -788,10 +804,10 @@ t_routing_cost_map get_routing_cost_map(int longest_seg_length, } } - //Finally, now that we have a list of sample locations, run a Dijkstra flood from - //each sample location to profile the routing network from this type + // Finally, now that we have a list of sample locations, run a Dijkstra flood from + // each sample location to profile the routing network from this type - t_routing_cost_map routing_cost_map({(size_t)device_ctx.grid.get_num_layers(), device_ctx.grid.width(), device_ctx.grid.height()}); + t_routing_cost_map routing_cost_map({device_ctx.grid.get_num_layers(), device_ctx.grid.width(), device_ctx.grid.height()}); if (sample_nodes.empty()) { VTR_LOGV_WARN(route_verbosity > 1, @@ -800,7 +816,7 @@ t_routing_cost_map get_routing_cost_map(int longest_seg_length, segment_inf.name.c_str(), segment_inf.length); } else { - //reset cost for this segment + // reset cost for this segment routing_cost_map.fill(Expansion_Cost_Entry()); // to avoid multiple memory allocation and de-allocations in run_dijkstra() @@ -904,9 +920,10 @@ void dump_readable_router_lookahead_map(const std::string& file_name, const std: VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "Unable to open file '%s' for writing\n", file_name.c_str()); } + const int chan_type_dim_size = (num_layers == 1) ? 2 : 3; VTR_ASSERT(dim_sizes[0] == num_layers); VTR_ASSERT(dim_sizes[1] == num_layers); - VTR_ASSERT(dim_sizes[2] == 2); + VTR_ASSERT(dim_sizes[2] == chan_type_dim_size); VTR_ASSERT(dim_sizes.size() == 5 || (dim_sizes.size() == 6 && dim_sizes[4] == grid_width && dim_sizes[5] == grid_height)); ofs << "from_layer," @@ -918,9 +935,14 @@ void dump_readable_router_lookahead_map(const std::string& file_name, const std: "cong_cost," "delay_cost\n"; + std::vector chan_types{e_rr_type::CHANX, e_rr_type::CHANY}; + if (num_layers > 1) { + chan_types.push_back(e_rr_type::CHANZ); + } + for (int from_layer_num = 0; from_layer_num < num_layers; from_layer_num++) { for (int to_layer_num = 0; to_layer_num < num_layers; to_layer_num++) { - for (e_rr_type chan_type : {e_rr_type::CHANX, e_rr_type::CHANY}) { + for (e_rr_type chan_type : chan_types) { for (int seg_index = 0; seg_index < dim_sizes[3]; seg_index++) { for (int dx = 0; dx < grid_width; dx++) { for (int dy = 0; dy < grid_height; dy++) { @@ -966,7 +988,7 @@ static void dijkstra_flood_to_wires(int itile, root.node = node; int ptc = rr_graph.node_ptc_num(node); - int root_layer_num = rr_graph.node_layer(node); + int root_layer_num = rr_graph.node_layer_low(node); /* * Perform Dijkstra from the SOURCE/OPIN of interest, stopping at the first @@ -994,7 +1016,7 @@ static void dijkstra_flood_to_wires(int itile, pq.pop(); e_rr_type curr_rr_type = rr_graph.node_type(curr.node); - int curr_layer_num = rr_graph.node_layer(curr.node); + int curr_layer_num = rr_graph.node_layer_low(curr.node); if (curr_rr_type == e_rr_type::CHANX || curr_rr_type == e_rr_type::CHANY || curr_rr_type == e_rr_type::SINK) { //We stop expansion at any CHANX/CHANY/SINK int seg_index; @@ -1075,7 +1097,7 @@ static void dijkstra_flood_to_ipins(RRNodeId node, util::t_chan_ipins_delays& ch root.node = node; root.level = 0; - int root_layer = rr_graph.node_layer(node); + int root_layer = rr_graph.node_layer_low(node); /* * Perform Djikstra from the CHAN of interest, stopping at the the first @@ -1105,7 +1127,7 @@ static void dijkstra_flood_to_ipins(RRNodeId node, util::t_chan_ipins_delays& ch if (curr_rr_type == e_rr_type::IPIN) { int node_x = rr_graph.node_xlow(curr.node); int node_y = rr_graph.node_ylow(curr.node); - int node_layer = rr_graph.node_layer(curr.node); + int node_layer = rr_graph.node_layer_low(curr.node); auto tile_type = device_ctx.grid.get_physical_type({node_x, node_y, node_layer}); int itile = tile_type->index; @@ -1126,8 +1148,8 @@ static void dijkstra_flood_to_ipins(RRNodeId node, util::t_chan_ipins_delays& ch continue; } - //We allow expansion through SOURCE/OPIN/IPIN types - auto cost_index = rr_graph.node_cost_index(curr.node); + // We allow expansion through SOURCE/OPIN/IPIN types + RRIndexedDataId cost_index = rr_graph.node_cost_index(curr.node); float new_cong = device_ctx.rr_indexed_data[cost_index].base_cost; //Current nodes congestion cost for (RREdgeId edge : rr_graph.edge_range(curr.node)) { @@ -1136,7 +1158,7 @@ static void dijkstra_flood_to_ipins(RRNodeId node, util::t_chan_ipins_delays& ch RRNodeId next_node = rr_graph.rr_nodes().edge_sink_node(edge); - if (rr_graph.node_layer(next_node) != root_layer) { + if (rr_graph.node_layer_low(next_node) != root_layer) { //Don't change the layer continue; } @@ -1294,8 +1316,6 @@ static void run_intra_tile_dijkstra(const RRGraphView& rr_graph, } } -/* runs Dijkstra's algorithm from specified node until all nodes have been visited. Each time a pin is visited, the delay/congestion information - * to that pin is stored is added to an entry in the routing_cost_map */ static void run_dijkstra(RRNodeId start_node, int start_x, int start_y, @@ -1303,49 +1323,49 @@ static void run_dijkstra(RRNodeId start_node, util::t_dijkstra_data& data, const std::unordered_map>& sample_locs, bool sample_all_locs) { - auto& device_ctx = g_vpr_ctx.device(); + const DeviceContext& device_ctx = g_vpr_ctx.device(); const auto& rr_graph = device_ctx.rr_graph; - auto& node_expanded = data.node_expanded; + vtr::vector& node_expanded = data.node_expanded; node_expanded.resize(rr_graph.num_nodes()); std::fill(node_expanded.begin(), node_expanded.end(), false); - auto& node_visited_costs = data.node_visited_costs; + vtr::vector& node_visited_costs = data.node_visited_costs; node_visited_costs.resize(rr_graph.num_nodes()); std::fill(node_visited_costs.begin(), node_visited_costs.end(), -1.0); - /* a priority queue for expansion */ + // A priority queue for expansion std::priority_queue& pq = data.pq; - //Clear priority queue if non-empty + // Clear priority queue if non-empty while (!pq.empty()) { pq.pop(); } - /* first entry has no upstream delay or congestion */ + // First entry has no upstream delay or congestion pq.emplace(start_node, UNDEFINED, 0, 0, 0, true); - /* now do routing */ + // Now do routing while (!pq.empty()) { util::PQ_Entry current = pq.top(); pq.pop(); RRNodeId curr_node = current.rr_node; - /* check that we haven't already expanded from this node */ + // Check that we haven't already expanded from this node if (node_expanded[curr_node]) { continue; } //VTR_LOG("Expanding with delay=%10.3g cong=%10.3g (%s)\n", current.delay, current.congestion_upstream, describe_rr_node(rr_graph, device_ctx.grid, device_ctx.rr_indexed_data, curr_node).c_str()); - /* if this node is an ipin record its congestion/delay in the routing_cost_map */ + // If this node is an ipin record its congestion/delay in the routing_cost_map if (rr_graph.node_type(curr_node) == e_rr_type::IPIN) { VTR_ASSERT_SAFE(rr_graph.node_xlow(curr_node) == rr_graph.node_xhigh(curr_node)); VTR_ASSERT_SAFE(rr_graph.node_ylow(curr_node) == rr_graph.node_yhigh(curr_node)); int ipin_x = rr_graph.node_xlow(curr_node); int ipin_y = rr_graph.node_ylow(curr_node); - int ipin_layer = rr_graph.node_layer(curr_node); + int ipin_layer = rr_graph.node_layer_low(curr_node); if (ipin_x >= start_x && ipin_y >= start_y) { auto [delta_x, delta_y] = util::get_xy_deltas(start_node, curr_node); @@ -1376,12 +1396,11 @@ static void run_dijkstra(RRNodeId start_node, } } -/* iterates over the children of the specified node and selectively pushes them onto the priority queue */ static void expand_dijkstra_neighbours(util::PQ_Entry parent_entry, vtr::vector& node_visited_costs, vtr::vector& node_expanded, std::priority_queue& pq) { - auto& device_ctx = g_vpr_ctx.device(); + const DeviceContext& device_ctx = g_vpr_ctx.device(); const auto& rr_graph = device_ctx.rr_graph; RRNodeId parent = parent_entry.rr_node; diff --git a/vpr/src/route/router_lookahead/router_lookahead_map_utils.h b/vpr/src/route/router_lookahead/router_lookahead_map_utils.h index 2a67ed10865..325db7aa59d 100644 --- a/vpr/src/route/router_lookahead/router_lookahead_map_utils.h +++ b/vpr/src/route/router_lookahead/router_lookahead_map_utils.h @@ -319,7 +319,8 @@ t_ipin_primitive_sink_delays compute_intra_tile_dijkstra(const RRGraphView& rr_g const t_physical_tile_loc& tile_loc); /* returns index of a node from which to start routing */ -RRNodeId get_start_node(int layer, int start_x, int start_y, int target_x, int target_y, e_rr_type rr_type, int seg_index, int track_offset); +RRNodeId get_chanxy_start_node(int layer, int start_x, int start_y, int target_x, int target_y, e_rr_type rr_type, int seg_index, int track_offset); +RRNodeId get_chanz_start_node(int start_x, int start_y, int seg_index, int track_offset, Direction dir); /** * @brief Computes the absolute delta_x and delta_y offset @@ -333,7 +334,7 @@ std::pair get_xy_deltas(RRNodeId from_node, RRNodeId to_node); t_routing_cost_map get_routing_cost_map(int longest_seg_length, unsigned from_layer_num, - const e_rr_type& chan_type, + const e_rr_type chan_type, const t_segment_inf& segment_inf, const std::unordered_map>& sample_locs, bool sample_all_locs, @@ -357,4 +358,26 @@ std::pair get_cost_from_src_opin(const std::map& dim_sizes, WireCostCallBackFunction wire_cost_func); + + /// @brief Converts a routing channel type (CHANX/CHANY/CHANZ) to an index + /// to access the channel type dimension of the router lookahead table. +inline int chan_type_to_index(e_rr_type chan_type) { + int chan_index; + switch (chan_type) { + case e_rr_type::CHANX: + chan_index = 0; + break; + case e_rr_type::CHANY: + chan_index = 1; + break; + case e_rr_type::CHANZ: + chan_index = 2; + break; + default: + VTR_ASSERT(false); + } + + return chan_index; +} + } // namespace util diff --git a/vpr/src/route/router_lookahead/router_lookahead_simple.cpp b/vpr/src/route/router_lookahead/router_lookahead_simple.cpp index d12a5dee14e..85a8aadb5af 100644 --- a/vpr/src/route/router_lookahead/router_lookahead_simple.cpp +++ b/vpr/src/route/router_lookahead/router_lookahead_simple.cpp @@ -68,8 +68,9 @@ std::pair SimpleLookahead::get_expected_delay_and_cong(RRNodeId fr e_rr_type from_type = rr_graph.node_type(from_node); util::Cost_Entry cost_entry(0, 0); if (is_chanxy(from_type) || is_chanz(from_type)) { - int from_layer_num = rr_graph.node_layer(from_node); - int to_layer_num = rr_graph.node_layer(to_node); + // TODO: handle CHANZ nodes + int from_layer_num = rr_graph.node_layer_low(from_node); + int to_layer_num = rr_graph.node_layer_low(to_node); auto [delta_x, delta_y] = util::get_xy_deltas(from_node, to_node); delta_x = abs(delta_x); diff --git a/vpr/src/route/rr_graph_generation/build_scatter_gathers.cpp b/vpr/src/route/rr_graph_generation/build_scatter_gathers.cpp new file mode 100644 index 00000000000..62c64d11d61 --- /dev/null +++ b/vpr/src/route/rr_graph_generation/build_scatter_gathers.cpp @@ -0,0 +1,286 @@ + +#include "build_scatter_gathers.h" + +#include "switchblock_scatter_gather_common_utils.h" +#include "scatter_gather_types.h" +#include "rr_types.h" +#include "globals.h" +#include "vtr_assert.h" + +#include + +// +// Static Function Declrations +// + +/** + * @brief Finds the routing channels corresponding to a given scatter or gather pattern and location. + * + * @param pattern Scatter/gather (SG) pattern to be processed. + * @param loc Physical switchblock location where the SG pattern is to be applied. + * @param chan_details_x Channel details for horizontal routing channels. + * @param chan_details_y Channel details for vertical routing channels. + * @param correct_channels Output: list of valid channel locations and types. + */ +static void index_to_correct_channels(const t_wireconn_inf& pattern, + const t_physical_tile_loc& loc, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + std::vector& correct_channels); + +/** + * @brief Collects candidate wires from given channels that match specified switchpoints. + * + * @param channels List of channel locations to search for candiates. + * @param wire_switchpoints_vec Set of wire segments and valid switchpoints for matching. + * @param chan_details_x Channel details for horizontal routing channels. + * @param chan_details_y Channel details for vertical routing channels. + * @param is_dest True if searching for destination (scatter) wires, false for source (gather). + * @param wire_type_sizes_x Stores the number of wires of each wire segment type and their starting index for horizontal routing channels. + * @param wire_type_sizes_y Stores the number of wires of each wire segment type and their starting index for vertical routing channels. + * @return Vector of candidate wires that satisfy the switchpoint and direction constraints. + */ +static std::vector find_candidate_wires(const std::vector& channels, + const std::vector& wire_switchpoints_vec, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + const t_wire_type_sizes& wire_type_sizes_x, + const t_wire_type_sizes& wire_type_sizes_y, + bool is_dest); + +// +// Static Function Definitions +// + +static void index_to_correct_channels(const t_wireconn_inf& pattern, + const t_physical_tile_loc& loc, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + std::vector& correct_channels) { + correct_channels.clear(); + + for (e_side side : pattern.sides) { + t_physical_tile_loc chan_loc; + e_rr_type chan_type; + + index_into_correct_chan(loc, side, chan_details_x, chan_details_y, chan_loc, chan_type); + + if (!chan_coords_out_of_bounds(chan_loc, chan_type)) { + correct_channels.push_back({chan_loc, chan_type, side}); + } + } +} + +static std::vector find_candidate_wires(const std::vector& channels, + const std::vector& wire_switchpoints_vec, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + const t_wire_type_sizes& wire_type_sizes_x, + const t_wire_type_sizes& wire_type_sizes_y, + bool is_dest) { + + // TODO: reuse + std::vector candidates; + + for (const auto [chan_loc, chan_type, chan_side] : channels) { + int seg_coord = (chan_type == e_rr_type::CHANY) ? chan_loc.y : chan_loc.x; + + const t_wire_type_sizes& wire_type_sizes = (chan_type == e_rr_type::CHANX) ? wire_type_sizes_x : wire_type_sizes_y; + const t_chan_seg_details* chan_details = (chan_type == e_rr_type::CHANX) ? chan_details_x[chan_loc.x][chan_loc.y].data() : chan_details_y[chan_loc.x][chan_loc.y].data(); + + for (const t_wire_switchpoints& wire_switchpoints : wire_switchpoints_vec) { + auto wire_type = vtr::string_view(wire_switchpoints.segment_name); + + if (wire_type_sizes.find(wire_type) == wire_type_sizes.end()) { + // wire_type_sizes may not contain wire_type if its seg freq is 0 + continue; + } + + // Get the number of wires of given type + int num_type_wires = wire_type_sizes.at(wire_type).num_wires; + // Get the last wire belonging to this type + int first_type_wire = wire_type_sizes.at(wire_type).start; + int last_type_wire = first_type_wire + num_type_wires - 1; + + for (int valid_switchpoint : wire_switchpoints.switchpoints) { + for (int iwire = first_type_wire; iwire <= last_type_wire; iwire++) { + Direction seg_direction = chan_details[iwire].direction(); + + /* unidirectional wires going in the decreasing direction can have an outgoing edge + * only from the top or right switch block sides, and an incoming edge only if they are + * at the left or bottom sides (analogous for wires going in INC direction) */ + if (chan_side == TOP || chan_side == RIGHT) { + if (seg_direction == Direction::DEC && is_dest) { + continue; + } + if (seg_direction == Direction::INC && !is_dest) { + continue; + } + } else { + VTR_ASSERT(chan_side == LEFT || chan_side == BOTTOM); + if (seg_direction == Direction::DEC && !is_dest) { + continue; + } + if (seg_direction == Direction::INC && is_dest) { + continue; + } + } + + int wire_switchpoint = get_switchpoint_of_wire(chan_type, chan_details[iwire], seg_coord, chan_side); + + // Check if this wire belongs to one of the specified switchpoints; add it to our 'wires' vector if so + if (wire_switchpoint != valid_switchpoint) continue; + + candidates.push_back({chan_loc, chan_type, chan_side, {iwire, wire_switchpoint}}); + } + } + } + } + + return candidates; +} + +// +// Non-satatic Function Definitions +// + +std::vector alloc_and_load_scatter_gather_connections(const std::vector& scatter_gather_patterns, + const std::vector& inter_cluster_rr, + const std::vector& segment_inf, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + const t_chan_width& nodes_per_chan, + vtr::NdMatrix, 2>& interdie_3d_links) { + const DeviceGrid& grid = g_vpr_ctx.device().grid; + + std::vector gather_channels; + std::vector scatter_channels; + + vtr::FormulaParser formula_parser; + vtr::t_formula_data formula_data; + + std::vector bottleneck_links; + + interdie_3d_links.clear(); + if (grid.get_num_layers() > 1) { + interdie_3d_links.resize({grid.width(), grid.height()}); + } + + const auto [wire_type_sizes_x, wire_type_sizes_y] = count_wire_type_sizes(chan_details_x, chan_details_y, nodes_per_chan); + + for (const t_scatter_gather_pattern& sg_pattern : scatter_gather_patterns) { + VTR_ASSERT(sg_pattern.type == e_scatter_gather_type::UNIDIR); + + for (const t_sg_location& sg_loc_info : sg_pattern.sg_locations) { + + for (const t_physical_tile_loc gather_loc : grid.all_locations()) { + if (sb_not_here(grid, inter_cluster_rr, gather_loc, sg_loc_info.type)) { + continue; + } + + auto sg_link_it = std::ranges::find_if(sg_pattern.sg_links, + [&](const t_sg_link& link) noexcept { + return link.name == sg_loc_info.sg_link_name; + }); + + VTR_ASSERT(sg_link_it != sg_pattern.sg_links.end()); + const t_sg_link& sg_link = *sg_link_it; + + auto seg_it = std::ranges::find_if(segment_inf, + [&](const t_segment_inf& seg) noexcept { + return seg.name == sg_link.seg_type; + }); + + VTR_ASSERT(seg_it != segment_inf.end()); + const t_segment_inf& wire_segment = *seg_it; + + t_physical_tile_loc scatter_loc; + scatter_loc.x = gather_loc.x + sg_link.x_offset; + scatter_loc.y = gather_loc.y + sg_link.y_offset; + scatter_loc.layer_num = gather_loc.layer_num + sg_link.z_offset; + + index_to_correct_channels(sg_pattern.gather_pattern, gather_loc, chan_details_x, chan_details_y, gather_channels); + index_to_correct_channels(sg_pattern.scatter_pattern, scatter_loc, chan_details_x, chan_details_y, scatter_channels); + + if (gather_channels.empty() || scatter_channels.empty()) { + continue; + } + + auto gather_wire_candidates = find_candidate_wires(gather_channels, + sg_pattern.gather_pattern.from_switchpoint_set, + chan_details_x, chan_details_y, + wire_type_sizes_x, wire_type_sizes_y, + /*is_dest=*/false); + + auto scatter_wire_candidates = find_candidate_wires(scatter_channels, + sg_pattern.scatter_pattern.to_switchpoint_set, + chan_details_x, chan_details_y, + wire_type_sizes_x, wire_type_sizes_y, + /*is_dest=*/true); + + int bottleneck_fanin = evaluate_num_conns_formula(formula_parser, + formula_data, + sg_pattern.gather_pattern.num_conns_formula, + gather_wire_candidates.size(), + scatter_wire_candidates.size()); + + int bottleneck_fanout = evaluate_num_conns_formula(formula_parser, + formula_data, + sg_pattern.scatter_pattern.num_conns_formula, + gather_wire_candidates.size(), + scatter_wire_candidates.size()); + + bottleneck_fanin = std::min(bottleneck_fanin, gather_wire_candidates.size()); + bottleneck_fanout = std::min(bottleneck_fanout, scatter_wire_candidates.size()); + + if (bottleneck_fanin == 0 || bottleneck_fanout == 0) { + continue; + } + + const bool is_3d_link = (sg_link.z_offset != 0); + if (is_3d_link) { + interdie_3d_links[gather_loc.x][gather_loc.y].reserve(interdie_3d_links[gather_loc.x][gather_loc.y].size() + sg_loc_info.num); + } else { + bottleneck_links.reserve(bottleneck_links.size() + sg_loc_info.num); + } + + for (int i_bottleneck = 0, i_s = 0, i_g = 0; i_bottleneck < sg_loc_info.num; i_bottleneck++) { + + t_bottleneck_link bottleneck_link; + bottleneck_link.gather_loc = gather_loc; + bottleneck_link.scatter_loc = scatter_loc; + bottleneck_link.gather_fanin_connections.reserve(bottleneck_fanin); + bottleneck_link.scatter_fanout_connections.reserve(bottleneck_fanout); + + for (int i = 0; i < bottleneck_fanin; i++) { + bottleneck_link.gather_fanin_connections.push_back(gather_wire_candidates[i_g]); + i_g = (i_g + 1) % bottleneck_fanin; + } + + for (int i = 0; i < bottleneck_fanout; i++) { + bottleneck_link.scatter_fanout_connections.push_back(scatter_wire_candidates[i_s]); + i_s = (i_s + 1) % bottleneck_fanout; + } + + if (is_3d_link) { + if (sg_link.z_offset < 0 && wire_segment.arch_wire_switch_dec != ARCH_FPGA_UNDEFINED_VAL) { + bottleneck_link.arch_wire_switch = wire_segment.arch_wire_switch_dec; + } else { + bottleneck_link.arch_wire_switch = wire_segment.arch_wire_switch; + } + interdie_3d_links[gather_loc.x][gather_loc.y].push_back(std::move(bottleneck_link)); + } else { + if ((sg_link.x_offset < 0 || sg_link.y_offset < 0) && wire_segment.arch_wire_switch_dec != ARCH_FPGA_UNDEFINED_VAL) { + bottleneck_link.arch_wire_switch = wire_segment.arch_wire_switch_dec; + } else { + bottleneck_link.arch_wire_switch = wire_segment.arch_wire_switch; + } + bottleneck_links.push_back(std::move(bottleneck_link)); + } + } + } + } + } + + return bottleneck_links; +} diff --git a/vpr/src/route/rr_graph_generation/build_scatter_gathers.h b/vpr/src/route/rr_graph_generation/build_scatter_gathers.h new file mode 100644 index 00000000000..df5a569abb3 --- /dev/null +++ b/vpr/src/route/rr_graph_generation/build_scatter_gathers.h @@ -0,0 +1,55 @@ +#pragma once + +#include "scatter_gather_types.h" +#include "rr_types.h" +#include "rr_graph_type.h" +#include "switchblock_scatter_gather_common_utils.h" + +#include + +/// Identifies a specific channel location in the device grid. +struct t_chan_loc { + t_physical_tile_loc location; ///< Physical grid location of the channel + e_rr_type chan_type; ///< Type of routing channel (e.g., CHANX, CHANY) + e_side side; ///< Side of the reference switch block the channel lies on +}; + +/// Represents a wire candidate for scatter/gather connections. +struct t_sg_candidate { + t_chan_loc chan_loc; ///< Channel location (coordinates, type, side) where the wire lies. + t_wire_switchpoint wire_switchpoint; ///< Wire index and its valid switchpoint +}; + +/// Represents a scatter/gather bottleneck connection between two locations. +struct t_bottleneck_link { + t_physical_tile_loc gather_loc; ///< Source switchblock location. + t_physical_tile_loc scatter_loc; ///< Destination switchblock location. + int arch_wire_switch; ///< The switch (mux) used to drive the bottleneck wire. + std::vector gather_fanin_connections; ///< Wires driving the bottleneck link at `gather_loc` + std::vector scatter_fanout_connections; ///< Wires driven by the bottleneck link at `scatter_loc` +}; + +/** + * @brief Builds scatter/gather bottleneck connections across the device grid. + * + * For each scatter/gather pattern, this routine finds candidate gather and scatter + * wires, evaluates connection limits from user-specified formulas, and creates + * bottleneck links between the corresponding locations. Both intra-die and inter-die + * (3D) connections are handled. + * + * @param scatter_gather_patterns List of scatter/gather connection patterns. + * @param inter_cluster_rr Flags indicating whether each layer has inter-cluster routing resources. + * @param segment_inf Wire segment type information. + * @param chan_details_x Channel details for horizontal routing channels. + * @param chan_details_y Channel details for vertical routing channels. + * @param nodes_per_chan Channel width data. + * @param interdie_3d_links Output: matrix storing inter-die (3D) bottleneck links. + * @return Vector of intra-die bottleneck links. + */ +std::vector alloc_and_load_scatter_gather_connections(const std::vector& scatter_gather_patterns, + const std::vector& inter_cluster_rr, + const std::vector& segment_inf, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + const t_chan_width& nodes_per_chan, + vtr::NdMatrix, 2>& interdie_3d_links); diff --git a/vpr/src/route/rr_graph_generation/build_switchblocks.cpp b/vpr/src/route/rr_graph_generation/build_switchblocks.cpp index 86e8126ab4c..01d1f6ab9b6 100644 --- a/vpr/src/route/rr_graph_generation/build_switchblocks.cpp +++ b/vpr/src/route/rr_graph_generation/build_switchblocks.cpp @@ -136,82 +136,32 @@ #include "vpr_types.h" #include "build_switchblocks.h" + +#include "globals.h" #include "physical_types.h" #include "parse_switchblocks.h" #include "vtr_expr_eval.h" #include "rr_types.h" - -using vtr::FormulaParser; -using vtr::t_formula_data; - -/************ Classes ************/ -/** Contains info about a wire segment type */ -class WireInfo { - public: - int length; ///< the length of this type of wire segment in tiles - int num_wires; ///< total number of wires in a channel segment (basically W) - int start; ///< the wire index at which this type starts in the channel segment (0..W-1) - - void set(int len, int wires, int st) { - length = len; - num_wires = wires; - start = st; - } - - WireInfo() { - this->set(0, 0, 0); - } - - WireInfo(int len, int wires, int st) { - this->set(len, wires, st); - } -}; - -struct t_wire_switchpoint { - int wire; ///< Wire index within the channel - int switchpoint; ///< Switchpoint of the wire -}; +#include "switchblock_scatter_gather_common_utils.h" struct t_wireconn_scratchpad { - FormulaParser formula_parser; - t_formula_data formula_data; + vtr::FormulaParser formula_parser; + vtr::t_formula_data formula_data; std::vector potential_src_wires; std::vector potential_dest_wires; std::vector scratch_wires; }; -/************ Typedefs ************/ -/* Used to get info about a given wire type based on the name */ -typedef vtr::flat_map t_wire_type_sizes; - /************ Function Declarations ************/ -/** - * @brief Counts and summarizes wire types in a routing channel. - * - * Iterates through the given array of segment details for a routing channel, - * grouping segments by wire type (as identified by `type_name()`). - * For each unique wire type, it records: - * - the wire segment length, - * - the number of wires of that type, - * - the start index of the first wire of that type in the array. - * - * @param channel Pointer to an array of `t_chan_seg_details` representing the wires in a channel. - * @param nodes_per_chan The total number of wire segments (i.e., size of the `channel` array). - * @return A map (`t_wire_type_sizes`) from wire type name to `WireInfo` containing size and indexing info for each type. - */ -static t_wire_type_sizes count_wire_type_sizes(const t_chan_seg_details* channel, int nodes_per_chan); /* Compute the wire(s) that the wire at (x, y, from_side, to_side, from_wire) should connect to. * sb_conns is updated with the result */ -static void compute_wire_connections(int x_coord, - int y_coord, - int layer_coord, - enum e_side from_side, - enum e_side to_side, +static void compute_wire_connections(const t_physical_tile_loc& sb_loc, + e_side from_side, + e_side to_side, const t_chan_details& chan_details_x, const t_chan_details& chan_details_y, const t_switchblock_inf& sb, - const DeviceGrid& grid, const t_wire_type_sizes& wire_type_sizes_x, const t_wire_type_sizes& wire_type_sizes_y, e_directionality directionality, @@ -220,17 +170,12 @@ static void compute_wire_connections(int x_coord, t_wireconn_scratchpad* scratchpad); /* ... sb_conn represents the 'coordinates' of the desired switch block connections */ -static void compute_wireconn_connections(const DeviceGrid& grid, - e_directionality directionality, +static void compute_wireconn_connections(e_directionality directionality, const t_chan_details& from_chan_details, const t_chan_details& to_chan_details, SwitchblockLookupKey sb_conn, - int from_x, - int from_y, - int from_layer, - int to_x, - int to_y, - int to_layer, + const t_physical_tile_loc& from_loc, + const t_physical_tile_loc& to_loc, e_rr_type from_chan_type, e_rr_type to_chan_type, const t_wire_type_sizes& wire_type_sizes_from, @@ -241,13 +186,9 @@ static void compute_wireconn_connections(const DeviceGrid& grid, vtr::RngContainer& rng, t_wireconn_scratchpad* scratchpad); -static int evaluate_num_conns_formula(t_wireconn_scratchpad* scratchpad, const std::string& num_conns_formula, int from_wire_count, int to_wire_count); - /** * * @brief calculates the wire indices belonging to the types in types in 'wire_type_sizes' and switchpoints in 'points' at the given channel segment - * - * @param grid device grid * @param chan_details channel segment details (length, start and end points, ...) * @param chan_type channel type (CHANX/CHANY) * @param x the wire x-coordinate @@ -256,12 +197,11 @@ static int evaluate_num_conns_formula(t_wireconn_scratchpad* scratchpad, const s * @param wire_switchpoints_vec valid switch points at the given channel segment * @param wire_type_sizes valid wire types * @param is_dest whether wires are source or destination within a switch block connection - * @param order switchpoint order (fixed, shuffled) specified in the architecture file - * @param rand_state used to randomly shuffle switchpoint if required (shuffled order) + * @param switchpoint_order switchpoint order (fixed, shuffled) specified in the architecture file + * @param rng used to randomly shuffle switchpoint if required (shuffled order) * @param output_wires collected wire indices that matches the specified types and switchpoints */ -static void get_switchpoint_wires(const DeviceGrid& grid, - const t_chan_seg_details* chan_details, +static void get_switchpoint_wires(const t_chan_seg_details* chan_details, e_rr_type chan_type, int x, int y, @@ -269,149 +209,11 @@ static void get_switchpoint_wires(const DeviceGrid& grid, const std::vector& wire_switchpoints_vec, const t_wire_type_sizes& wire_type_sizes, bool is_dest, - SwitchPointOrder switchpoint_order, + e_switch_point_order switchpoint_order, vtr::RngContainer& rng, std::vector* output_wires, std::vector* scratch_wires); -/** - * @brief finds the correct channel (x or y), and the coordinates to index into it based on the - * specified tile coordinates (x,y,layer) and the switch block side. - * - * @param tile_x x-coordinate of the tile - * @param tile_y y-coordinate of the tile - * @param tile_layer layer-coordinate of the tile - * @param src_side switch block source side - * @param dest_side switch block destination side - * @param chan_details_x x-channel segment details (length, start and end points, ...) - * @param chan_details_y x-channel segment details (length, start and end points, ...) - * @param chan_x x-coordinate of the channel - * @param chan_y y-coordinate of the channel - * @param chan_layer layer_coordinate of the channel - * @param chan_type chan type that the function index into - * - * @return returns the type of channel that we are indexing into (ie, CHANX or CHANY) and channel coordinates and type - */ -static const t_chan_details& index_into_correct_chan(int tile_x, - int tile_y, - int tile_layer, - enum e_side src_side, - enum e_side dest_side, - const t_chan_details& chan_details_x, - const t_chan_details& chan_details_y, - int& chan_x, - int& chan_y, - int& chan_layer, - e_rr_type& chan_type); - -/** - * @brief check whether a specific track location is valid within the device grid - * - * @param grid device grid - * @param x_coord x-coordinate of the location - * @param y_coord y-coordinate of the location - * @param layer_coord layer-coordinate of the location - * @param chan_type track channel type (CHANX or CHANY), required since device perimeter does not have certain channels - * - * @return true if the track location is outside the device grid, false otherwise. - */ -static bool coords_out_of_bounds(const DeviceGrid& grid, int x_coord, int y_coord, int layer_coord, e_rr_type chan_type); - -/* returns the subsegment number of the specified wire at seg_coord*/ -static int get_wire_subsegment_num(const DeviceGrid& grid, e_rr_type chan_type, const t_chan_seg_details& wire_details, int seg_coord); - -int get_wire_segment_length(const DeviceGrid& grid, e_rr_type chan_type, const t_chan_seg_details& wire_details); - -/* Returns the switchpoint of the wire specified by wire_details at a segment coordinate - * of seg_coord, and connection to the sb_side of the switchblock */ -static int get_switchpoint_of_wire(const DeviceGrid& grid, - e_rr_type chan_type, - const t_chan_seg_details& wire_details, - int seg_coord, - e_side sb_side); - -/** - * @brief check whether a switch block exists in a specified coordinate within the device grid - * - * @param grid device grid - * @param inter_cluster_rr used to check whether inter-cluster programmable routing resources exist in the current layer - * @param x x-coordinate of the location - * @param y y-coordinate of the location - * @param layer layer-coordinate of the location - * @param sb switchblock information specified in the architecture file - * - * @return true if a switch block exists at the specified location, false otherwise. - */ -static bool sb_not_here(const DeviceGrid& grid, - const std::vector& inter_cluster_rr, - int x, - int y, - int layer, - const t_switchblock_inf& sb); - -/** - * @brief check whether specified coordinate is located at the device grid corner and a switch block exists there - * - * @param grid device grid - * @param inter_cluster_rr used to check whether inter-cluster programmable routing resources exist in the current layer - * @param x x-coordinate of the location - * @param y y-coordinate of the location - * @param layer layer-coordinate of the location - * - * @return true if the specified coordinate represents a corner location within the device grid and a switch block exists there, false otherwise. - */ -static bool is_corner_sb(const DeviceGrid& grid, const std::vector& inter_cluster_rr, int x, int y, int layer); - -/** - * @brief check whether specified coordinate is located at one of the perimeter device grid locations and a switch block exists there - * - * @param grid device grid - * @param inter_cluster_rr used to check whether inter-cluster programmable routing resources exist in the current layer - * @param x x-coordinate of the location - * @param y y-coordinate of the location - * @param layer layer-coordinate of the location - * - * @return true if the specified coordinate represents a perimeter location within the device grid and a switch block exists there, false otherwise. - */ -static bool is_perimeter_sb(const DeviceGrid& grid, const std::vector& inter_cluster_rr, int x, int y, int layer); - -/** - * @brief check whether specified coordinate is located at core of the device grid (not perimeter) and a switch block exists there - * - * @param grid device grid - * @param inter_cluster_rr used to check whether inter-cluster programmable routing resources exist in the current layer - * @param x x-coordinate of the location - * @param y y-coordinate of the location - * @param layer layer-coordinate of the location - * - * @return true if the specified coordinate represents a core location within the device grid and a switch block exists there, false otherwise. - */ -static bool is_core_sb(const DeviceGrid& grid, const std::vector& inter_cluster_rr, int x, int y, int layer); - -/** - * @brief check whether specified coordinate is located in the architecture-specified regions that the switchblock should be applied to - * - * @param grid device grid - * @param inter_cluster_rr used to check whether inter-cluster programmable routing resources exist in the current layer - * @param x x-coordinate of the location - * @param y y-coordinate of the location - * @param sb switchblock information specified in the architecture file - * - * @return true if the specified coordinate falls into the architecture-specified location for this switchblock, false otherwise. - */ -static bool match_sb_xy(const DeviceGrid& grid, const std::vector& inter_cluster_rr, int x, int y, int layer, const t_switchblock_inf& sb); - -/** - * @brief check whether specified layer has inter-cluster programmable routing resources or not. - * - * @param grid device grid - * @param inter_cluster_rr inter-cluster programmable routing resources availability within different layers in multi-die FPGAs - * @param layer a valid layer index within the device grid, must be between [0..num_layer-1] - * - * @return true if the specified layer contain inter-cluster programmable routing resources, false otherwise. - */ -static bool is_prog_routing_avail(const DeviceGrid& grid, const std::vector& inter_cluster_rr, int layer); - /* adjusts a negative destination wire index calculated from a permutation formula */ static int adjust_formula_result(int dest_wire, int src_W, int dest_W, int connection_ind); @@ -430,18 +232,7 @@ t_sb_connection_map* alloc_and_load_switchblock_permutations(const t_chan_detail t_sb_connection_map* sb_conns = new t_sb_connection_map; - /* We assume that x & y channels have the same ratios of wire types. i.e., looking at a single - * channel is representative of all channels in the FPGA -- as of 3/9/2013 this is true in VPR */ - - /* Count the number of wires in each wire type in the specified channel. Note that this is representative of - * the wire count for every channel in direction due to the assumption stated above. - * This will not hold if we - * 1) support different horizontal and vertical segment distributions - * 2) support non-uniform channel distributions. - */ - t_wire_type_sizes wire_type_sizes_y = count_wire_type_sizes(chan_details_y[0][0].data(), nodes_per_chan.y_max); - t_wire_type_sizes wire_type_sizes_x = count_wire_type_sizes(chan_details_x[0][0].data(), nodes_per_chan.x_max); - t_wire_type_sizes wire_type_sizes = count_wire_type_sizes(chan_details_x[0][0].data(), nodes_per_chan.max); + const auto [wire_type_sizes_x, wire_type_sizes_y] = count_wire_type_sizes(chan_details_x, chan_details_y, nodes_per_chan); /******** slow switch block computation method; computes switchblocks at each coordinate ********/ // Iterate over all the switchblocks specified in the architecture @@ -452,24 +243,20 @@ t_sb_connection_map* alloc_and_load_switchblock_permutations(const t_chan_detail VPR_FATAL_ERROR(VPR_ERROR_ARCH, "alloc_and_load_switchblock_connections: Switchblock %s does not match directionality of architecture\n", sb.name.c_str()); } - // Iterate over the x,y, layer coordinates spanning the FPGA, filling in all the switch blocks that exist - for (size_t layer_coord = 0; layer_coord < grid.get_num_layers(); layer_coord++) { - for (size_t x_coord = 0; x_coord < grid.width(); x_coord++) { - for (size_t y_coord = 0; y_coord <= grid.height(); y_coord++) { - if (sb_not_here(grid, inter_cluster_rr, x_coord, y_coord, layer_coord, sb)) { - continue; - } + // Iterate over all locations in the grid, filling in all the switch blocks that exist + for (const t_physical_tile_loc sb_loc : grid.all_locations()) { + if (sb_not_here(grid, inter_cluster_rr, sb_loc, sb.location, sb.specified_loc)) { + continue; + } - // now we iterate over all the potential side1->side2 connections - for (e_side from_side : TOTAL_3D_SIDES) { - for (e_side to_side : TOTAL_3D_SIDES) { - // Fill appropriate entry of the sb_conns map with vector specifying the wires the current wire will connect to - compute_wire_connections(x_coord, y_coord, layer_coord, from_side, to_side, - chan_details_x, chan_details_y, sb, grid, - wire_type_sizes_x, wire_type_sizes_y, directionality, sb_conns, - rng, &scratchpad); - } - } + // now we iterate over all the potential side1->side2 connections + for (e_side from_side : TOTAL_2D_SIDES) { + for (e_side to_side : TOTAL_2D_SIDES) { + // Fill appropriate entry of the sb_conns map with vector specifying the wires the current wire will connect to + compute_wire_connections(sb_loc, from_side, to_side, + chan_details_x, chan_details_y, sb, + wire_type_sizes_x, wire_type_sizes_y, directionality, sb_conns, + rng, &scratchpad); } } } @@ -491,194 +278,7 @@ void free_switchblock_permutations(t_sb_connection_map* sb_conns) { vtr::malloc_trim(0); } -static bool sb_not_here(const DeviceGrid& grid, - const std::vector& inter_cluster_rr, - int x, - int y, - int layer, - const t_switchblock_inf& sb) { - bool sb_not_here = true; - - switch (sb.location) { - case e_sb_location::E_EVERYWHERE: - sb_not_here = false; - break; - case e_sb_location::E_PERIMETER: - if (is_perimeter_sb(grid, inter_cluster_rr, x, y, layer)) { - sb_not_here = false; - } - break; - case e_sb_location::E_CORNER: - if (is_corner_sb(grid, inter_cluster_rr, x, y, layer)) { - sb_not_here = false; - } - break; - case e_sb_location::E_CORE: - if (is_core_sb(grid, inter_cluster_rr, x, y, layer)) { - sb_not_here = false; - } - break; - case e_sb_location::E_FRINGE: - if (is_perimeter_sb(grid, inter_cluster_rr, x, y, layer) && !is_corner_sb(grid, inter_cluster_rr, x, y, layer)) { - sb_not_here = false; - } - break; - case e_sb_location::E_XY_SPECIFIED: - if (match_sb_xy(grid, inter_cluster_rr, x, y, layer, sb)) { - sb_not_here = false; - } - - break; - default: - VPR_FATAL_ERROR(VPR_ERROR_ARCH, "sb_not_here: unrecognized location enum: %d\n", sb.location); - break; - } - return sb_not_here; -} - -static bool is_corner_sb(const DeviceGrid& grid, const std::vector& inter_cluster_rr, int x, int y, int layer) { - if (!is_prog_routing_avail(grid, inter_cluster_rr, layer)) { - return false; - } - bool is_corner = false; - if ((x == 0 && y == 0) || (x == 0 && y == int(grid.height()) - 2) || //-2 for no perim channels - (x == int(grid.width()) - 2 && y == 0) || //-2 for no perim channels - (x == int(grid.width()) - 2 && y == int(grid.height()) - 2)) { //-2 for no perim channels - is_corner = true; - } - return is_corner; -} - -static bool is_perimeter_sb(const DeviceGrid& grid, const std::vector& inter_cluster_rr, int x, int y, int layer) { - if (!is_prog_routing_avail(grid, inter_cluster_rr, layer)) { - return false; - } - bool is_perimeter = false; - if (x == 0 || x == int(grid.width()) - 2 || y == 0 || y == int(grid.height()) - 2) { - is_perimeter = true; - } - return is_perimeter; -} - -static bool is_core_sb(const DeviceGrid& grid, const std::vector& inter_cluster_rr, int x, int y, int layer) { - if (!is_prog_routing_avail(grid, inter_cluster_rr, layer)) { - return false; - } - bool is_core = !is_perimeter_sb(grid, inter_cluster_rr, x, y, layer); - return is_core; -} - -static bool is_prog_routing_avail(const DeviceGrid& grid, const std::vector& inter_cluster_rr, int layer) { - bool is_prog_avail = true; - //make sure layer number is legal - VTR_ASSERT(layer >= 0 && layer < (int)grid.get_num_layers()); - //check if the current layer has programmable routing resources before trying to build a custom switch blocks - if (!inter_cluster_rr.at(layer)) { - is_prog_avail = false; - } - return is_prog_avail; -} - -static bool match_sb_xy(const DeviceGrid& grid, const std::vector& inter_cluster_rr, int x, int y, int layer, const t_switchblock_inf& sb) { - if (!is_prog_routing_avail(grid, inter_cluster_rr, layer)) { - return false; - } - //if one of sb_x and sb_y is defined, we either know the exact location (x,y) or the exact x location (will apply it to all rows) - //or the exact y location (will apply it to all columns) - if (sb.x != -1 || sb.y != -1) { - if (x == sb.x && y == sb.y) { - return true; - } - - if (x == sb.x && sb.y == -1) { - return true; - } - - if (sb.x == -1 && y == sb.y) { - return true; - } - } - - //if both sb_x and sb_y is not defined, we have a region that we should apply this SB pattern to, we just need to check - //whether the location passed into this function falls within this region or not - //calculate the appropriate region based on the repeatx/repeaty and current location. - //This is to determine whether the given location is part of the current SB specified region with regular expression or not - //After region calculation, the current SB will apply to this location if: - // 1) the given (x,y) location falls into the calculated region - // *AND* - // 2) incrx/incry are respected within the region, this means all locations within the calculated region do - // not necessarily crosspond to the current SB. If incrx/incry is equal to 1, then all locations within the - // calculated region are valid. - - //calculate the region - int x_reg_step = (sb.reg_x.repeat != 0) ? (x - sb.reg_x.start) / sb.reg_x.repeat : sb.reg_x.start; - int y_reg_step = (sb.reg_y.repeat != 0) ? (y - sb.reg_y.start) / sb.reg_y.repeat : sb.reg_y.start; - - //step must be non-negative - x_reg_step = std::max(0, x_reg_step); - y_reg_step = std::max(0, y_reg_step); - - int reg_startx = sb.reg_x.start + (x_reg_step * sb.reg_x.repeat); - int reg_endx = sb.reg_x.end + (x_reg_step * sb.reg_x.repeat); - reg_endx = std::min(reg_endx, int(grid.width() - 1)); - - int reg_starty = sb.reg_y.start + (y_reg_step * sb.reg_y.repeat); - int reg_endy = sb.reg_y.end + (y_reg_step * sb.reg_y.repeat); - reg_endy = std::min(reg_endy, int(grid.height() - 1)); - - //check x coordinate - if (x >= reg_startx && x <= reg_endx) { //should fall into the region - //we also should respect the incrx - //if incrx is not equal to 1, all locations within this region are *NOT* valid - if ((x + reg_startx) % sb.reg_x.incr == 0) { - //valid x coordinate, check for y value - if (y >= reg_starty && y <= reg_endy) { - //check for incry, similar as incrx - if ((y + reg_starty) % sb.reg_y.incr == 0) { - //both x and y are valid - return true; - } - } - } - } - - //if reach here, we don't have sb in this location - return false; -} - -static t_wire_type_sizes count_wire_type_sizes(const t_chan_seg_details* channel, int nodes_per_chan) { - int num_wires = 0; - WireInfo wire_info; - - vtr::string_view wire_type = channel[0].type_name(); - int length = channel[0].length(); - int start = 0; - - t_wire_type_sizes wire_type_sizes; - - for (int iwire = 0; iwire < nodes_per_chan; iwire++) { - vtr::string_view new_type = channel[iwire].type_name(); - int new_length = channel[iwire].length(); - int new_start = iwire; - if (new_type != wire_type) { - wire_info.set(length, num_wires, start); - wire_type_sizes[wire_type] = wire_info; - wire_type = new_type; - length = new_length; - start = new_start; - num_wires = 0; - } - num_wires++; - } - - wire_info.set(length, num_wires, start); - wire_type_sizes[wire_type] = wire_info; - - return wire_type_sizes; -} - -static void get_switchpoint_wires(const DeviceGrid& grid, - const t_chan_seg_details* chan_details, +static void get_switchpoint_wires(const t_chan_seg_details* chan_details, e_rr_type chan_type, int x, int y, @@ -686,7 +286,7 @@ static void get_switchpoint_wires(const DeviceGrid& grid, const std::vector& wire_switchpoints_vec, const t_wire_type_sizes& wire_type_sizes, bool is_dest, - SwitchPointOrder switchpoint_order, + e_switch_point_order switchpoint_order, vtr::RngContainer& rng, std::vector* output_wires, std::vector* scratch_wires) { @@ -701,7 +301,6 @@ static void get_switchpoint_wires(const DeviceGrid& grid, collected_wire_switchpoints.clear(); auto wire_type = vtr::string_view(wire_switchpoints.segment_name); - const std::vector& points = wire_switchpoints.switchpoints; if (wire_type_sizes.find(wire_type) == wire_type_sizes.end()) { // wire_type_sizes may not contain wire_type if its seg freq is 0 @@ -714,14 +313,12 @@ static void get_switchpoint_wires(const DeviceGrid& grid, int first_type_wire = wire_type_sizes.at(wire_type).start; int last_type_wire = first_type_wire + num_type_wires - 1; - /* Walk through each wire segment of specified type and check whether it matches one - * of the specified switchpoints. - * - * Note that we walk through the points in order, this ensures that returned switchpoints - * match the order specified in the architecture, which we assume is a priority order specified - * by the architect. - */ - for (int valid_switchpoint : points) { + // Walk through each wire segment of specified type and check whether it matches one + // of the specified switchpoints. + // Note that we walk through the points in order, this ensures that returned switchpoints + // match the order specified in the architecture, which we assume is a priority order specified + // by the architect. + for (int valid_switchpoint : wire_switchpoints.switchpoints) { for (int iwire = first_type_wire; iwire <= last_type_wire; iwire++) { Direction seg_direction = chan_details[iwire].direction(); @@ -745,7 +342,7 @@ static void get_switchpoint_wires(const DeviceGrid& grid, } } - int wire_switchpoint = get_switchpoint_of_wire(grid, chan_type, chan_details[iwire], seg_coord, side); + int wire_switchpoint = get_switchpoint_of_wire(chan_type, chan_details[iwire], seg_coord, side); // Check if this wire belongs to one of the specified switchpoints; add it to our 'wires' vector if so if (wire_switchpoint != valid_switchpoint) continue; @@ -758,39 +355,34 @@ static void get_switchpoint_wires(const DeviceGrid& grid, collected_wire_switchpoints.begin(), collected_wire_switchpoints.end()); } - if (switchpoint_order == SwitchPointOrder::SHUFFLED) { - // We new re-order the switchpoints to try to make adjacent switchpoints have different values + if (switchpoint_order == e_switch_point_order::SHUFFLED) { + // We now re-order the switchpoints to try to make adjacent switchpoints have different values vtr::shuffle(all_collected_wire_switchpoints.begin(), all_collected_wire_switchpoints.end(), rng); } else { - VTR_ASSERT(switchpoint_order == SwitchPointOrder::FIXED); + VTR_ASSERT(switchpoint_order == e_switch_point_order::FIXED); // Already ordered so same switchpoints are adjacent by above collection loop } } -static void compute_wire_connections(int x_coord, - int y_coord, - int layer_coord, - enum e_side from_side, - enum e_side to_side, +static void compute_wire_connections(const t_physical_tile_loc& sb_loc, + e_side from_side, + e_side to_side, const t_chan_details& chan_details_x, const t_chan_details& chan_details_y, const t_switchblock_inf& sb, - const DeviceGrid& grid, const t_wire_type_sizes& wire_type_sizes_x, const t_wire_type_sizes& wire_type_sizes_y, e_directionality directionality, t_sb_connection_map* sb_conns, vtr::RngContainer& rng, t_wireconn_scratchpad* scratchpad) { - int from_x, from_y, from_layer; // index into source channel - int to_x, to_y, to_layer; // index into destination channel e_rr_type from_chan_type, to_chan_type; // the type of channel - i.e. CHANX or CHANY - from_x = from_y = to_x = to_y = from_layer = to_layer = UNDEFINED; + t_physical_tile_loc from_loc, to_loc; // For indexing into this switchblock's permutation funcs SBSideConnection side_conn(from_side, to_side); // For indexing into FPGA's switchblock map - SwitchblockLookupKey sb_conn(x_coord, y_coord, layer_coord, from_side, to_side); + SwitchblockLookupKey sb_conn(sb_loc, from_side, to_side); // Can't connect a switchblock side to itself if (from_side == to_side) { @@ -807,16 +399,15 @@ static void compute_wire_connections(int x_coord, * destination channels. also return the channel type (ie chanx/chany/both) into which we are * indexing */ // Details for source channel - const t_chan_details& from_chan_details = index_into_correct_chan(x_coord, y_coord, layer_coord, from_side, to_side, chan_details_x, chan_details_y, - from_x, from_y, from_layer, from_chan_type); + const t_chan_details& from_chan_details = index_into_correct_chan(sb_loc, from_side, chan_details_x, chan_details_y, + from_loc, from_chan_type); // Details for destination channel - const t_chan_details& to_chan_details = index_into_correct_chan(x_coord, y_coord, layer_coord, to_side, from_side, chan_details_x, chan_details_y, - to_x, to_y, to_layer, to_chan_type); + const t_chan_details& to_chan_details = index_into_correct_chan(sb_loc, to_side, chan_details_x, chan_details_y, + to_loc, to_chan_type); - // make sure from_x/y and to_x/y aren't out of bounds - if (coords_out_of_bounds(grid, to_x, to_y, to_layer, to_chan_type) - || coords_out_of_bounds(grid, from_x, from_y, from_layer, from_chan_type)) { + // make sure from_loc and to_loc aren't out of bounds + if (chan_coords_out_of_bounds(to_loc, to_chan_type) || chan_coords_out_of_bounds(from_loc, from_chan_type)) { return; } @@ -829,8 +420,8 @@ static void compute_wire_connections(int x_coord, const t_wireconn_inf& wireconn = sb.wireconns[iconn]; // compute the destination wire segments to which the source wire segment should connect based on the current wireconn - compute_wireconn_connections(grid, directionality, from_chan_details, to_chan_details, - sb_conn, from_x, from_y, from_layer, to_x, to_y, to_layer, from_chan_type, to_chan_type, wire_type_sizes_from, + compute_wireconn_connections(directionality, from_chan_details, to_chan_details, + sb_conn, from_loc, to_loc, from_chan_type, to_chan_type, wire_type_sizes_from, wire_type_sizes_to, sb, wireconn, sb_conns, rng, scratchpad); } } @@ -839,17 +430,12 @@ static void compute_wire_connections(int x_coord, * channel segment with coordinate from_x/from_y) should connect to based on the specified 'wireconn'. * wireconn defines the source and destination sets of wire segments (based on wire segment type & switchpoint * as defined at the top of this file), and the indices of wires to connect to are relative to these sets */ -static void compute_wireconn_connections(const DeviceGrid& grid, - e_directionality directionality, +static void compute_wireconn_connections(e_directionality directionality, const t_chan_details& from_chan_details, const t_chan_details& to_chan_details, SwitchblockLookupKey sb_conn, - int from_x, - int from_y, - int from_layer, - int to_x, - int to_y, - int to_layer, + const t_physical_tile_loc& from_loc, + const t_physical_tile_loc& to_loc, e_rr_type from_chan_type, e_rr_type to_chan_type, const t_wire_type_sizes& wire_type_sizes_from, @@ -861,18 +447,13 @@ static void compute_wireconn_connections(const DeviceGrid& grid, t_wireconn_scratchpad* scratchpad) { constexpr bool verbose = false; - // Choose the from_side to be the same as to_side if the connection is travelling across dice in multi-die FPGAs - e_side from_side = (sb_conn.from_side != ABOVE && sb_conn.from_side != UNDER) ? sb_conn.from_side : sb_conn.to_side; - // Choose the to_side to be the same as from_side if the connection is travelling across dice in multi-die FPGAs - e_side to_side = (sb_conn.to_side != ABOVE && sb_conn.to_side != UNDER) ? sb_conn.to_side : sb_conn.from_side; - - /* vectors that will contain indices of the wires belonging to the source/dest wire types/points */ - get_switchpoint_wires(grid, from_chan_details[from_x][from_y].data(), from_chan_type, from_x, from_y, from_side, + // vectors that will contain indices of the wires belonging to the source/dest wire types/points + get_switchpoint_wires(from_chan_details[from_loc.x][from_loc.y].data(), from_chan_type, from_loc.x, from_loc.y, sb_conn.from_side, wireconn.from_switchpoint_set, wire_type_sizes_from, /*is_dest=*/false, wireconn.from_switchpoint_order, rng, &scratchpad->potential_src_wires, &scratchpad->scratch_wires); - get_switchpoint_wires(grid, to_chan_details[to_x][to_y].data(), to_chan_type, to_x, to_y, to_side, + get_switchpoint_wires(to_chan_details[to_loc.x][to_loc.y].data(), to_chan_type, to_loc.x, to_loc.y, sb_conn.to_side, wireconn.to_switchpoint_set, wire_type_sizes_to, /*is_dest=*/true, wireconn.to_switchpoint_order, rng, &scratchpad->potential_dest_wires, &scratchpad->scratch_wires); @@ -931,7 +512,11 @@ static void compute_wireconn_connections(const DeviceGrid& grid, // * interleave (to ensure good diversity) // Determine how many connections to make - int num_conns = evaluate_num_conns_formula(scratchpad, wireconn.num_conns_formula, potential_src_wires.size(), potential_dest_wires.size()); + int num_conns = evaluate_num_conns_formula(scratchpad->formula_parser, + scratchpad->formula_data, + wireconn.num_conns_formula, + potential_src_wires.size(), + potential_dest_wires.size()); VTR_ASSERT_MSG(num_conns >= 0, "Number of switchblock connections to create must be non-negative"); VTR_LOGV(verbose, " num_conns: %zu\n", num_conns); @@ -942,20 +527,20 @@ static void compute_wireconn_connections(const DeviceGrid& grid, int src_wire_ind = iconn % potential_src_wires.size(); //Index in src set int from_wire = potential_src_wires[src_wire_ind].wire; //Index in channel - Direction from_wire_direction = from_chan_details[from_x][from_y][from_wire].direction(); + Direction from_wire_direction = from_chan_details[from_loc.x][from_loc.y][from_wire].direction(); if (from_wire_direction == Direction::INC) { - /* if this is a unidirectional wire headed in the increasing direction (relative to coordinate system) - * then switch block source side should be BOTTOM or LEFT */ + // If this is a unidirectional wire headed in the increasing direction (relative to coordinate system) + // then switch block source side should be BOTTOM or LEFT if (sb_conn.from_side == TOP || sb_conn.from_side == RIGHT) { continue; } - VTR_ASSERT(sb_conn.from_side == BOTTOM || sb_conn.from_side == LEFT || sb_conn.from_side == ABOVE || sb_conn.from_side == UNDER); + VTR_ASSERT(sb_conn.from_side == BOTTOM || sb_conn.from_side == LEFT); } else if (from_wire_direction == Direction::DEC) { - /* a wire heading in the decreasing direction can only connect from the TOP or RIGHT sides of a switch block */ + // A wire heading in the decreasing direction can only connect from the TOP or RIGHT sides of a switch block if (sb_conn.from_side == BOTTOM || sb_conn.from_side == LEFT) { continue; } - VTR_ASSERT(sb_conn.from_side == TOP || sb_conn.from_side == RIGHT || sb_conn.from_side == ABOVE || sb_conn.from_side == UNDER); + VTR_ASSERT(sb_conn.from_side == TOP || sb_conn.from_side == RIGHT); } else { VTR_ASSERT(from_wire_direction == Direction::BIDIR); } @@ -969,7 +554,7 @@ static void compute_wireconn_connections(const DeviceGrid& grid, const std::vector& permutations_ref = iter->second; for (const std::string& perm : permutations_ref) { /* Convert the symbolic permutation formula to a number */ - t_formula_data& formula_data = scratchpad->formula_data; + vtr::t_formula_data& formula_data = scratchpad->formula_data; formula_data.clear(); formula_data.set_var_value("W", dest_W); formula_data.set_var_value("t", src_wire_ind); @@ -982,24 +567,18 @@ static void compute_wireconn_connections(const DeviceGrid& grid, int to_wire = potential_dest_wires[dest_wire_ind].wire; //Index in channel - /* create the struct containing information about the target wire segment which will be added to the - * sb connections map */ + // Initialize information about the target wire segment which will be added to the sb connections map t_switchblock_edge sb_edge; sb_edge.from_wire = from_wire; sb_edge.to_wire = to_wire; - sb_edge.from_wire_layer = from_layer; - sb_edge.to_wire_layer = to_layer; // if the switch override has been set, use that, Otherwise use default if (wireconn.switch_override_indx != DEFAULT_SWITCH) { sb_edge.switch_ind = wireconn.switch_override_indx; - } else if (from_layer == to_layer) { - sb_edge.switch_ind = to_chan_details[to_x][to_y][to_wire].arch_wire_switch(); - sb_edge.switch_ind_between_layers = -1; //the connection does not cross any layers + } else if (from_loc.layer_num == to_loc.layer_num) { + sb_edge.switch_ind = to_chan_details[to_loc.x][to_loc.y][to_wire].arch_wire_switch(); } else { - VTR_ASSERT(from_layer != to_layer); - sb_edge.switch_ind = to_chan_details[to_x][to_y][to_wire].arch_wire_switch(); - sb_edge.switch_ind_between_layers = to_chan_details[to_x][to_y][to_wire].arch_inter_die_switch(); + VTR_ASSERT(false); } VTR_LOGV(verbose, " make_conn: %d -> %d switch=%d\n", sb_edge.from_wire, sb_edge.to_wire, sb_edge.switch_ind); @@ -1021,242 +600,14 @@ static void compute_wireconn_connections(const DeviceGrid& grid, } } -static int evaluate_num_conns_formula(t_wireconn_scratchpad* scratchpad, const std::string& num_conns_formula, int from_wire_count, int to_wire_count) { - t_formula_data& vars = scratchpad->formula_data; - vars.clear(); - - vars.set_var_value("from", from_wire_count); - vars.set_var_value("to", to_wire_count); - - return scratchpad->formula_parser.parse_formula(num_conns_formula, vars); -} - -static const t_chan_details& index_into_correct_chan(int tile_x, - int tile_y, - int tile_layer, - enum e_side src_side, - enum e_side dest_side, - const t_chan_details& chan_details_x, - const t_chan_details& chan_details_y, - int& chan_x, - int& chan_y, - int& chan_layer, - e_rr_type& chan_type) { - chan_type = e_rr_type::CHANX; - /* here we use the VPR convention that a tile 'owns' the channels directly to the right - * and above it */ - switch (src_side) { - case TOP: - /* this is y-channel belonging to tile above in the same layer */ - chan_x = tile_x; - chan_y = tile_y + 1; - chan_layer = tile_layer; - chan_type = e_rr_type::CHANY; - return chan_details_y; - break; - case RIGHT: - /* this is x-channel belonging to tile to the right in the same layer */ - chan_x = tile_x + 1; - chan_y = tile_y; - chan_layer = tile_layer; - chan_type = e_rr_type::CHANX; - return chan_details_x; - break; - case BOTTOM: - /* this is y-channel on the right of the tile in the same layer */ - chan_x = tile_x; - chan_y = tile_y; - chan_type = e_rr_type::CHANY; - chan_layer = tile_layer; - return chan_details_y; - break; - case LEFT: - /* this is x-channel on top of the tile in the same layer*/ - chan_x = tile_x; - chan_y = tile_y; - chan_type = e_rr_type::CHANX; - chan_layer = tile_layer; - return chan_details_x; - break; - case ABOVE: - /* this is x-channel and y-channel on the same tile location in layer above the current layer */ - chan_x = tile_x; - chan_y = tile_y; - chan_layer = tile_layer + 1; - chan_type = (dest_side == RIGHT || dest_side == LEFT) ? e_rr_type::CHANX : e_rr_type::CHANY; - return (dest_side == RIGHT || dest_side == LEFT) ? chan_details_x : chan_details_y; - break; - case UNDER: - /* this is x-channel and y-channel on the same tile location in layer under the current layer */ - chan_x = tile_x; - chan_y = tile_y; - chan_layer = tile_layer - 1; - chan_type = (dest_side == RIGHT || dest_side == LEFT) ? e_rr_type::CHANX : e_rr_type::CHANY; - return (dest_side == RIGHT || dest_side == LEFT) ? chan_details_x : chan_details_y; - break; - default: - VPR_FATAL_ERROR(VPR_ERROR_ARCH, "index_into_correct_chan: unknown side specified: %d\n", src_side); - break; - } - VTR_ASSERT(false); - return chan_details_x; //Unreachable -} - -static bool coords_out_of_bounds(const DeviceGrid& grid, int x_coord, int y_coord, int layer_coord, e_rr_type chan_type) { - bool result = true; - - /* the layer that channel is located at must be legal regardless of chan_type*/ - if (layer_coord < 0 || layer_coord > (int)grid.get_num_layers()) { - return result; - } - - if (e_rr_type::CHANX == chan_type) { - /* there is no x-channel at x=0 */ - if (x_coord <= 0 || x_coord >= int(grid.width()) - 1 || y_coord < 0 || y_coord >= int(grid.height()) - 1) { - result = true; - } else { - result = false; - } - } else if (e_rr_type::CHANY == chan_type) { - /* there is no y-channel at y=0 */ - if (x_coord < 0 || x_coord >= int(grid.width()) - 1 || y_coord <= 0 || y_coord >= int(grid.height()) - 1) { - result = true; - } else { - result = false; - } - - } else { - VPR_FATAL_ERROR(VPR_ERROR_ARCH, "coords_out_of_bounds(): illegal channel type %d\n", chan_type); - } - return result; -} - -static int get_wire_subsegment_num(const DeviceGrid& grid, e_rr_type chan_type, const t_chan_seg_details& wire_details, int seg_coord) { - /* We get wire subsegment number by comparing the wire's seg_coord to the seg_start of the wire. - * The offset between seg_start (or seg_end) and seg_coord is the subsegment number - * - * Cases: - * seg starts at bottom but does not extend all the way to the top -- look at seg_end - * seg starts > bottom and does not extend all the way to top -- look at seg_start - * seg starts > bottom but terminates all the way at the top -- look at seg_start - * seg starts at bottom and extends all the way to the top -- look at seg end - */ - - int subsegment_num; - int seg_start = wire_details.seg_start(); - int seg_end = wire_details.seg_end(); - Direction direction = wire_details.direction(); - int wire_length = get_wire_segment_length(grid, chan_type, wire_details); - int min_seg; - - /* determine the minimum and maximum values that the 'seg' coordinate - * of a wire can take */ - min_seg = 1; - - if (seg_start != min_seg) { - subsegment_num = seg_coord - seg_start; - } else { - subsegment_num = (wire_length - 1) - (seg_end - seg_coord); - } - - /* if this wire is going in the decreasing direction, reverse the subsegment num */ - VTR_ASSERT(seg_end >= seg_start); - if (direction == Direction::DEC) { - subsegment_num = wire_length - 1 - subsegment_num; - } - - return subsegment_num; -} - -/* returns wire segment length based on either: - * 1) the wire length specified in the segment details variable for this wire (if this wire segment doesn't span entire FPGA) - * 2) the seg_start and seg_end coordinates in the segment details for this wire (if this wire segment spans entire FPGA, as might happen for very long wires) - * - * Computing the wire segment length in this way help to classify short vs long wire segments according to switchpoint. */ -int get_wire_segment_length(const DeviceGrid& grid, e_rr_type chan_type, const t_chan_seg_details& wire_details) { - int wire_length; - - int min_seg = 1; - int max_seg = grid.width() - 2; //-2 for no perim channels - if (chan_type == e_rr_type::CHANY) { - max_seg = grid.height() - 2; //-2 for no perim channels - } - - int seg_start = wire_details.seg_start(); - int seg_end = wire_details.seg_end(); - - if (seg_start == min_seg && seg_end == max_seg) { - wire_length = seg_end - seg_start + 1; - } else { - wire_length = wire_details.length(); - } - - return wire_length; -} - -static int get_switchpoint_of_wire(const DeviceGrid& grid, - e_rr_type chan_type, - const t_chan_seg_details& wire_details, - int seg_coord, - e_side sb_side) { - /* this function calculates the switchpoint of a given wire by first calculating - * the subsegment number of the specified wire. For instance, for a wire with L=4: - * - * switchpoint: 0-------1-------2-------3-------0 - * subsegment_num: 0 1 2 3 - * - * So knowing the wire's subsegment_num and which switchblock side it connects to is - * enough to calculate the switchpoint - * - */ - - /* get the minimum and maximum segment coordinate which a wire in this channel type can take */ - int min_seg = 1; - int max_seg = grid.width() - 2; //-2 for no perim channels - if (chan_type == e_rr_type::CHANY) { - max_seg = grid.height() - 2; //-2 for no perim channels - } - - /* check whether the current seg_coord/sb_side coordinate specifies a perimeter switch block side at which all wire segments terminate/start. - * in this case only segments with switchpoints = 0 can exist */ - bool perimeter_connection = false; - if ((seg_coord == min_seg && (sb_side == RIGHT || sb_side == TOP)) || (seg_coord == max_seg && (sb_side == LEFT || sb_side == BOTTOM))) { - perimeter_connection = true; - } - - int switchpoint; - if (perimeter_connection) { - switchpoint = 0; - } else { - int wire_length = get_wire_segment_length(grid, chan_type, wire_details); - int subsegment_num = get_wire_subsegment_num(grid, chan_type, wire_details, seg_coord); - - Direction direction = wire_details.direction(); - if (LEFT == sb_side || BOTTOM == sb_side) { - switchpoint = (subsegment_num + 1) % wire_length; - if (direction == Direction::DEC) { - switchpoint = subsegment_num; - } - } else { - VTR_ASSERT(RIGHT == sb_side || TOP == sb_side); - switchpoint = subsegment_num; - if (direction == Direction::DEC) { - switchpoint = (subsegment_num + 1) % wire_length; - } - } - } - - return switchpoint; -} - -/* adjusts the destination wire calculated from a permutation formula to account for negative indicies, +/* adjusts the destination wire calculated from a permutation formula to account for negative indices, * source wire set offset, and modulo by destination wire set size * */ static int adjust_formula_result(int dest_wire, int src_W, int dest_W, int connection_ind) { int result = dest_wire; if (dest_wire < 0) { - //Adjust for negative indicies + //Adjust for negative indices int mult = (-1 * dest_wire) / dest_W + 1; result = dest_wire + mult * dest_W; } @@ -1266,7 +617,7 @@ static int adjust_formula_result(int dest_wire, int src_W, int dest_W, int conne // The permutation formula produce a 1-to-1 mapping from src track to dest track (i.e. each source // track is mapped to precisely one destination track). This is problematic if we are processing // a wireconn which goes through the source set multiple times (e.g. dest set larger than src set while - // processing a WireConnType::TO), since the permutation formula will only generate src_W track indicies + // processing a WireConnType::TO), since the permutation formula will only generate src_W track indices // (leaving some of the destination tracks unconnected). To ensure we get different destination tracks on // subsequent passes through the same source set, we offset the raw track by a multiple of src_W. Note the // use of integer division; src_mult will equal 0 on the first pass, 1 on the second etc. diff --git a/vpr/src/route/rr_graph_generation/build_switchblocks.h b/vpr/src/route/rr_graph_generation/build_switchblocks.h index a7e15ba3399..c4a9d5cc37b 100644 --- a/vpr/src/route/rr_graph_generation/build_switchblocks.h +++ b/vpr/src/route/rr_graph_generation/build_switchblocks.h @@ -34,6 +34,10 @@ class SwitchblockLookupKey { this->set_coords(set_x, set_y, set_layer, set_from, set_to); } + SwitchblockLookupKey(const t_physical_tile_loc& set_loc, e_side set_from, e_side set_to) { + this->set_coords(set_loc.x, set_loc.y, set_loc.layer_num, set_from, set_to); + } + /// @brief Constructor for initializing member variables with default layer number (0), used for single die FPGA SwitchblockLookupKey(int set_x, int set_y, e_side set_from, e_side set_to) { this->set_coords(set_x, set_y, 0, set_from, set_to); @@ -73,9 +77,7 @@ struct t_hash_Switchblock_Lookup { } }; -/** - * @brief Contains the required information to build an RR graph edge for a switch block connection - */ +/// @brief Contains the required information to build an RR graph edge for a switch block connection. struct t_switchblock_edge { /// Source wire ptc_num index in a channel short from_wire; @@ -83,17 +85,8 @@ struct t_switchblock_edge { /// Destination wire ptc_num index in a channel short to_wire; - /// RR graph switch index that connects the source wire to the destination wire that connect two tracks in same layer + /// RR graph switch index that connects the source wire to the destination wire that connect two tracks short switch_ind; - - /// RR graph switch index that connects two tracks in different layers - short switch_ind_between_layers; - - /// The layer index that the source wire is located at - short from_wire_layer; - - /// The layer index that the destination wire is located at - short to_wire_layer; }; /** @@ -120,7 +113,7 @@ typedef std::unordered_map * @param switchblocks switch block information extracted from the architecture file * @param nodes_per_chan number of track in each channel (x,y) * @param directionality specifies the switch block edges direction (unidirectional or bidirectional) - * @param rand_state initialize the random number generator (RNG) + * @param rng the random number generator (RNG) * * @return creates a map between switch blocks (key) and their corresponding edges (value). */ @@ -130,7 +123,7 @@ t_sb_connection_map* alloc_and_load_switchblock_permutations(const t_chan_detail const std::vector& inter_cluster_rr, const std::vector& switchblocks, const t_chan_width& nodes_per_chan, - enum e_directionality directionality, + e_directionality directionality, vtr::RngContainer& rng); /** diff --git a/vpr/src/route/rr_graph_generation/clock_connection_builders.cpp b/vpr/src/route/rr_graph_generation/clock_connection_builders.cpp index 188e1384e0c..f7d987a2ff8 100644 --- a/vpr/src/route/rr_graph_generation/clock_connection_builders.cpp +++ b/vpr/src/route/rr_graph_generation/clock_connection_builders.cpp @@ -110,7 +110,8 @@ RRNodeId RoutingToClockConnection::create_virtual_clock_network_sink_node(int la rr_graph_builder.set_node_name(node_index, arch->default_clock_network_name); rr_graph_builder.set_node_class_num(node_index, ptc); rr_graph_builder.set_node_coordinates(node_index, x, y, x, y); - rr_graph_builder.set_node_layer(node_index, layer); + rr_graph_builder.set_node_layer_low(node_index, layer); + rr_graph_builder.set_node_layer_high(node_index, layer); rr_graph_builder.set_node_capacity(node_index, 1); rr_graph_builder.set_node_cost_index(node_index, RRIndexedDataId(SINK_COST_INDEX)); diff --git a/vpr/src/route/rr_graph_generation/clock_network_builders.cpp b/vpr/src/route/rr_graph_generation/clock_network_builders.cpp index 14d2b57bc20..c8e7dc71bda 100644 --- a/vpr/src/route/rr_graph_generation/clock_network_builders.cpp +++ b/vpr/src/route/rr_graph_generation/clock_network_builders.cpp @@ -342,7 +342,8 @@ int ClockRib::create_chanx_wire(int layer, rr_graph_builder.set_node_type(chanx_node, e_rr_type::CHANX); rr_graph_builder.set_node_coordinates(chanx_node, x_start, y, x_end, y); - rr_graph_builder.set_node_layer(chanx_node, layer); + rr_graph_builder.set_node_layer_low(chanx_node, layer); + rr_graph_builder.set_node_layer_high(chanx_node, layer); rr_graph_builder.set_node_capacity(chanx_node, 1); rr_graph_builder.set_node_track_num(chanx_node, ptc_num); rr_graph_builder.set_node_rc_index(chanx_node, NodeRCIndex(find_create_rr_rc_data( @@ -683,7 +684,8 @@ int ClockSpine::create_chany_wire(int layer, rr_graph_builder.set_node_type(chany_node, e_rr_type::CHANY); rr_graph_builder.set_node_coordinates(chany_node, x, y_start, x, y_end); - rr_graph_builder.set_node_layer(chany_node, layer); + rr_graph_builder.set_node_layer_low(chany_node, layer); + rr_graph_builder.set_node_layer_high(chany_node, layer); rr_graph_builder.set_node_capacity(chany_node, 1); rr_graph_builder.set_node_track_num(chany_node, ptc_num); rr_graph_builder.set_node_rc_index(chany_node, NodeRCIndex(find_create_rr_rc_data( diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index 4d5b701aba4..cdf038804a5 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -4,6 +4,7 @@ #include #include #include "alloc_and_load_rr_indexed_data.h" +#include "build_scatter_gathers.h" #include "get_parallel_segs.h" #include "physical_types.h" #include "physical_types_util.h" @@ -184,33 +185,32 @@ static int get_opin_direct_connections(RRGraphBuilder& rr_graph_builder, static std::function alloc_and_load_rr_graph(RRGraphBuilder& rr_graph_builder, t_rr_graph_storage& L_rr_node, const RRGraphView& rr_graph, - const int num_seg_types, - const int num_seg_types_x, + const size_t num_seg_types, + const size_t num_seg_types_x, + const size_t num_seg_types_y, const t_unified_to_parallel_seg_index& seg_index_map, const t_chan_details& chan_details_x, const t_chan_details& chan_details_y, const t_track_to_pin_lookup& track_to_pin_lookup_x, const t_track_to_pin_lookup& track_to_pin_lookup_y, const t_pin_to_track_lookup& opin_to_track_map, + const vtr::NdMatrix, 2>& interdie_3d_links, const vtr::NdMatrix, 3>& switch_block_conn, t_sb_connection_map* sb_conn_map, const DeviceGrid& grid, const int Fs, t_sblock_pattern& sblock_pattern, const std::vector>& Fc_out, - vtr::NdMatrix& Fc_xofs, - vtr::NdMatrix& Fc_yofs, const t_chan_width& chan_width, const int wire_to_ipin_switch, const int wire_to_pin_between_dice_switch, - const int custom_3d_sb_fanin_fanout, const int delayless_switch, - const enum e_directionality directionality, + const e_directionality directionality, bool* Fc_clipped, const std::vector& directs, const std::vector& clb_to_clb_directs, bool is_global_graph, - const enum e_clock_modeling clock_modeling, + const e_clock_modeling clock_modeling, bool is_flat, const int route_verbosity); @@ -460,7 +460,6 @@ static void build_rr_chan(RRGraphBuilder& rr_graph_builder, const t_track_to_pin_lookup& track_to_pin_lookup, t_sb_connection_map* sb_conn_map, const vtr::NdMatrix, 3>& switch_block_conn, - vtr::NdMatrix& num_of_3d_conns_custom_SB, const int cost_index_offset, const t_chan_width& nodes_per_chan, const DeviceGrid& grid, @@ -470,30 +469,30 @@ static void build_rr_chan(RRGraphBuilder& rr_graph_builder, const t_chan_details& chan_details_x, const t_chan_details& chan_details_y, t_rr_edge_info_set& rr_edges_to_create, - t_rr_edge_info_set& des_3d_rr_edges_to_create, const int wire_to_ipin_switch, const int wire_to_pin_between_dice_switch, - const int custom_3d_sb_fanin_fanout, - const int delayless_switch, - const enum e_directionality directionality); + const e_directionality directionality); /** * @brief builds the extra length-0 CHANX nodes to handle 3D custom switchblocks edges in the RR graph. * @param rr_graph_builder RRGraphBuilder data structure which allows data modification on a routing resource graph - * @param layer switch block layer-coordinate * @param x_coord switch block x_coordinate * @param y_coord switch block y-coordinate * @param const_index_offset index to the correct node type for RR node cost initialization - * @param nodes_per_chan number of tracks per channel (x, y) - * @param chan_details_x channel-x details (length, start and end points, ...) */ -static void build_inter_die_custom_sb_rr_chan(RRGraphBuilder& rr_graph_builder, - const int layer, - const int x_coord, - const int y_coord, - const int const_index_offset, - const t_chan_width& nodes_per_chan, - const t_chan_details& chan_details_x); +static void build_inter_die_3d_rr_chan(RRGraphBuilder& rr_graph_builder, + const int x_coord, + const int y_coord, + const std::vector& interdie_3d_links, + const int const_index_offset); + +static void add_inter_die_3d_edges(RRGraphBuilder& rr_graph_builder, + int x_coord, + int y_coord, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + const std::vector& interdie_3d_links, + t_rr_edge_info_set& interdie_3d_rr_edges_to_create); void uniquify_edges(t_rr_edge_info_set& rr_edges_to_create); @@ -600,14 +599,14 @@ static void build_rr_graph(e_graph_type graph_type, const int global_route_switch, const int wire_to_arch_ipin_switch, const int wire_to_pin_between_dice_switch, - const int custom_3d_sb_fanin_fanout, const int delayless_switch, const float R_minW_nmos, const float R_minW_pmos, const e_base_cost_type base_cost_type, const e_clock_modeling clock_modeling, const std::vector& directs, - int* wire_to_rr_ipin_switch, + const std::vector& scatter_gather_patterns, + RRSwitchId* wire_to_rr_ipin_switch, bool is_flat, int* Warnings, const int route_verbosity); @@ -704,13 +703,13 @@ void create_rr_graph(e_graph_type graph_type, det_routing_arch.global_route_switch, det_routing_arch.wire_to_arch_ipin_switch, det_routing_arch.wire_to_arch_ipin_switch_between_dice, - router_opts.custom_3d_sb_fanin_fanout, det_routing_arch.delayless_switch, det_routing_arch.R_minW_nmos, det_routing_arch.R_minW_pmos, router_opts.base_cost_type, router_opts.clock_modeling, directs, + device_ctx.arch->scatter_gather_patterns, &det_routing_arch.wire_to_rr_ipin_switch, is_flat, Warnings, @@ -911,7 +910,7 @@ std::set get_layers_of_physical_types(const t_physical_tile_type_ptr type) } std::set get_layers_pin_is_connected_to(const t_physical_tile_type_ptr type, int from_layer, int pin_index) { - const auto& device_ctx = g_vpr_ctx.device(); + const DeviceContext& device_ctx = g_vpr_ctx.device(); std::set layer_pin_index_is_connected_to; for (int layer = 0; layer < (int)device_ctx.grid.get_num_layers(); layer++) { if (is_pin_conencted_to_layer(type, pin_index, from_layer, layer, device_ctx.grid.get_num_layers())) { @@ -943,14 +942,14 @@ static void build_rr_graph(e_graph_type graph_type, const int global_route_switch, const int wire_to_arch_ipin_switch, const int wire_to_pin_between_dice_switch, - const int custom_3d_sb_fanin_fanout, const int delayless_switch, const float R_minW_nmos, const float R_minW_pmos, const e_base_cost_type base_cost_type, const e_clock_modeling clock_modeling, const std::vector& directs, - int* wire_to_rr_ipin_switch, + const std::vector& scatter_gather_patterns, + RRSwitchId* wire_to_rr_ipin_switch, bool is_flat, int* Warnings, const int route_verbosity) { @@ -990,6 +989,7 @@ static void build_rr_graph(e_graph_type graph_type, t_unified_to_parallel_seg_index segment_index_map; std::vector segment_inf_x = get_parallel_segs(segment_inf, segment_index_map, e_parallel_axis::X_AXIS); std::vector segment_inf_y = get_parallel_segs(segment_inf, segment_index_map, e_parallel_axis::Y_AXIS); + std::vector segment_inf_z = get_parallel_segs(segment_inf, segment_index_map, e_parallel_axis::Z_AXIS); std::vector seg_details_x; std::vector seg_details_y; @@ -1157,18 +1157,6 @@ static void build_rr_graph(e_graph_type graph_type, } device_ctx.rr_graph_builder.resize_nodes(num_rr_nodes); - // These are data structures used by the unidir opin mapping. They are used - // to spread connections evenly for each segment type among the available - // wire start points - vtr::NdMatrix Fc_xofs({grid.height() - 1, - grid.width() - 1, - segment_inf_x.size()}, - 0); //[0..grid.height()-2][0..grid.width()-2][0..num_seg_types_x-1] - vtr::NdMatrix Fc_yofs({grid.width() - 1, - grid.height() - 1, - segment_inf_y.size()}, - 0); //[0..grid.width()-2][0..grid.height()-2][0..num_seg_types_y-1] - // START SB LOOKUP // Alloc and load the switch block lookup vtr::NdMatrix, 3> switch_block_conn; @@ -1184,9 +1172,9 @@ static void build_rr_graph(e_graph_type graph_type, const std::vector& inter_cluster_prog_rr = device_ctx.inter_cluster_prog_routing_resources; if (is_global_graph) { - switch_block_conn = alloc_and_load_switch_block_conn(&nodes_per_chan, SUBSET, 3); + switch_block_conn = alloc_and_load_switch_block_conn(&nodes_per_chan, e_switch_block_type::SUBSET, /*Fs=*/3); } else { - if (sb_type == CUSTOM) { + if (sb_type == e_switch_block_type::CUSTOM) { sb_conn_map = alloc_and_load_switchblock_permutations(chan_details_x, chan_details_y, grid, inter_cluster_prog_rr, switchblocks, nodes_per_chan, directionality, @@ -1216,17 +1204,21 @@ static void build_rr_graph(e_graph_type graph_type, } } } - // END SB LOOKUP - // Check whether RR graph need to allocate new nodes for 3D custom switch blocks. - // To avoid wasting memory, the data structures are only allocated if a custom switch block - // is described in the architecture file, and we have more than one die in device grid. - if (grid.get_num_layers() > 1 && sb_type == CUSTOM) { - // Keep how many nodes each switchblock requires for each x,y location - vtr::NdMatrix extra_nodes_per_switchblock = get_number_track_to_track_inter_die_conn(sb_conn_map, custom_3d_sb_fanin_fanout, device_ctx.rr_graph_builder); + vtr::NdMatrix, 2> interdie_3d_links; + const std::vector bottleneck_links = alloc_and_load_scatter_gather_connections(scatter_gather_patterns, + inter_cluster_prog_rr, + segment_inf, + chan_details_x, chan_details_y, + nodes_per_chan, + interdie_3d_links); + + // Check whether RR graph need to allocate new nodes for 3D connections. + // To avoid wasting memory, the data structures are only allocated if we have more than one die in device grid. + if (grid.get_num_layers() > 1) { // Allocate new nodes in each switchblocks - alloc_and_load_inter_die_rr_node_indices(device_ctx.rr_graph_builder, grid, extra_nodes_per_switchblock, &num_rr_nodes); + alloc_and_load_inter_die_rr_node_indices(device_ctx.rr_graph_builder, interdie_3d_links, &num_rr_nodes); device_ctx.rr_graph_builder.resize_nodes(num_rr_nodes); } @@ -1311,17 +1303,17 @@ static void build_rr_graph(e_graph_type graph_type, auto update_chan_width = alloc_and_load_rr_graph( device_ctx.rr_graph_builder, device_ctx.rr_graph_builder.rr_nodes(), device_ctx.rr_graph, segment_inf.size(), - segment_inf_x.size(), + segment_inf_x.size(), segment_inf_y.size(), segment_index_map, chan_details_x, chan_details_y, track_to_pin_lookup_x, track_to_pin_lookup_y, opin_to_track_map, + interdie_3d_links, switch_block_conn, sb_conn_map, grid, Fs, unidir_sb_pattern, - Fc_out, Fc_xofs, Fc_yofs, + Fc_out, nodes_per_chan, wire_to_arch_ipin_switch, wire_to_pin_between_dice_switch, - custom_3d_sb_fanin_fanout, delayless_switch, directionality, &Fc_clipped, @@ -1374,10 +1366,10 @@ static void build_rr_graph(e_graph_type graph_type, // edge subsets. Must be done after RR switches have been allocated device_ctx.rr_graph_builder.partition_edges(); - //Save the channel widths for the newly constructed graph + // Save the channel widths for the newly constructed graph device_ctx.chan_width = nodes_per_chan; - rr_graph_externals(segment_inf, segment_inf_x, segment_inf_y, *wire_to_rr_ipin_switch, base_cost_type); + rr_graph_externals(segment_inf, segment_inf_x, segment_inf_y, segment_inf_z, *wire_to_rr_ipin_switch, base_cost_type); const VibDeviceGrid vib_grid; check_rr_graph(device_ctx.rr_graph, @@ -1510,14 +1502,14 @@ void build_tile_rr_graph(RRGraphBuilder& rr_graph_builder, delayless_switch); std::vector> switch_fanin_remap; - int dummy_int; + RRSwitchId dummy_sw_id; alloc_and_load_rr_switch_inf(rr_graph_builder, switch_fanin_remap, sw_map, det_routing_arch.R_minW_nmos, det_routing_arch.R_minW_pmos, det_routing_arch.wire_to_arch_ipin_switch, - &dummy_int); + &dummy_sw_id); rr_graph_builder.partition_edges(); } @@ -1544,7 +1536,7 @@ void alloc_and_load_rr_switch_inf(RRGraphBuilder& rr_graph_builder, const float R_minW_nmos, const float R_minW_pmos, const int wire_to_arch_ipin_switch, - int* wire_to_rr_ipin_switch) { + RRSwitchId* wire_to_rr_ipin_switch) { // we will potentially be creating a couple of versions of each arch switch where // each version corresponds to a different fan-in. We will need to fill device_ctx.rr_switch_inf // with this expanded list of switches. @@ -1578,7 +1570,7 @@ void alloc_and_load_rr_switch_inf(RRGraphBuilder& rr_graph_builder, // return a representative switch if (arch_switch_fanins[wire_to_arch_ipin_switch].count(UNDEFINED)) { // only have one ipin cblock switch. OK. - (*wire_to_rr_ipin_switch) = arch_switch_fanins[wire_to_arch_ipin_switch][UNDEFINED]; + (*wire_to_rr_ipin_switch) = (RRSwitchId)arch_switch_fanins[wire_to_arch_ipin_switch][UNDEFINED]; } else if (arch_switch_fanins[wire_to_arch_ipin_switch].size() != 0) { VPR_FATAL_ERROR(VPR_ERROR_ARCH, "Not currently allowing an ipin cblock switch to have multiple fan-ins"); @@ -1588,7 +1580,7 @@ void alloc_and_load_rr_switch_inf(RRGraphBuilder& rr_graph_builder, // //Instead of throwing an error we issue a warning. This means that check_rr_graph() etc. will run to give more information //and allow graphics to be brought up for users to debug their architectures. - (*wire_to_rr_ipin_switch) = UNDEFINED; + (*wire_to_rr_ipin_switch) = RRSwitchId::INVALID(); VTR_LOG_WARN("No switch found for the ipin cblock in RR graph. Check if there is an error in arch file, or if no connection blocks are being built in RR graph\n"); } } @@ -1729,18 +1721,19 @@ static void remap_rr_node_switch_indices(RRGraphBuilder& rr_graph_builder, void rr_graph_externals(const std::vector& segment_inf, const std::vector& segment_inf_x, const std::vector& segment_inf_y, - int wire_to_rr_ipin_switch, - enum e_base_cost_type base_cost_type) { - auto& device_ctx = g_vpr_ctx.device(); + const std::vector& segment_inf_z, + RRSwitchId wire_to_rr_ipin_switch, + e_base_cost_type base_cost_type) { + const DeviceContext& device_ctx = g_vpr_ctx.device(); const auto& rr_graph = device_ctx.rr_graph; const auto& grid = device_ctx.grid; auto& mutable_device_ctx = g_vpr_ctx.mutable_device(); - auto& rr_indexed_data = mutable_device_ctx.rr_indexed_data; + vtr::vector& rr_indexed_data = mutable_device_ctx.rr_indexed_data; bool echo_enabled = getEchoEnabled() && isEchoFileEnabled(E_ECHO_RR_GRAPH_INDEXED_DATA); const char* echo_file_name = getEchoFileName(E_ECHO_RR_GRAPH_INDEXED_DATA); - add_rr_graph_C_from_switches(rr_graph.rr_switch_inf(RRSwitchId(wire_to_rr_ipin_switch)).Cin); - alloc_and_load_rr_indexed_data(rr_graph, grid, segment_inf, segment_inf_x, - segment_inf_y, rr_indexed_data, wire_to_rr_ipin_switch, base_cost_type, echo_enabled, echo_file_name); + add_rr_graph_C_from_switches(rr_graph.rr_switch_inf(wire_to_rr_ipin_switch).Cin); + alloc_and_load_rr_indexed_data(rr_graph, grid, segment_inf, segment_inf_x, segment_inf_y, segment_inf_z, + rr_indexed_data, wire_to_rr_ipin_switch, base_cost_type, echo_enabled, echo_file_name); //load_rr_index_segments(segment_inf.size()); } @@ -1826,7 +1819,7 @@ std::vector> alloc_and_load_actual_fc(const std::vector& sets_per_seg_type, const t_chan_width* nodes_per_chan, const e_fc_type fc_type, - const enum e_directionality directionality, + const e_directionality directionality, bool* Fc_clipped, bool is_flat) { // Initialize Fc of all blocks to zero @@ -1938,33 +1931,32 @@ std::vector> alloc_and_load_actual_fc(const std::vector alloc_and_load_rr_graph(RRGraphBuilder& rr_graph_builder, t_rr_graph_storage& L_rr_node, const RRGraphView& rr_graph, - const int num_seg_types, - const int num_seg_types_x, + const size_t num_seg_types, + const size_t num_seg_types_x, + const size_t num_seg_types_y, const t_unified_to_parallel_seg_index& seg_index_map, const t_chan_details& chan_details_x, const t_chan_details& chan_details_y, const t_track_to_pin_lookup& track_to_pin_lookup_x, const t_track_to_pin_lookup& track_to_pin_lookup_y, const t_pin_to_track_lookup& opin_to_track_map, + const vtr::NdMatrix, 2>& interdie_3d_links, const vtr::NdMatrix, 3>& switch_block_conn, t_sb_connection_map* sb_conn_map, const DeviceGrid& grid, const int Fs, t_sblock_pattern& sblock_pattern, const std::vector>& Fc_out, - vtr::NdMatrix& Fc_xofs, - vtr::NdMatrix& Fc_yofs, const t_chan_width& chan_width, const int wire_to_ipin_switch, const int wire_to_pin_between_dice_switch, - const int custom_3d_sb_fanin_fanout, const int delayless_switch, - const enum e_directionality directionality, + const e_directionality directionality, bool* Fc_clipped, const std::vector& directs, const std::vector& clb_to_clb_directs, bool is_global_graph, - const enum e_clock_modeling clock_modeling, + const e_clock_modeling clock_modeling, bool /*is_flat*/, const int route_verbosity) { // We take special care when creating RR graph edges (there are typically many more @@ -2026,6 +2018,14 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder VTR_LOGV(route_verbosity > 1, "SOURCE->OPIN and IPIN->SINK edge count:%d\n", num_edges); num_edges = 0; + + // These are data structures used by the unidir opin mapping. They are used + // to spread connections evenly for each segment type among the available + // wire start points + // [0..grid.height()-2][0..grid.width()-2][0..num_seg_types_x/y-1] + vtr::NdMatrix Fc_xofs({grid.height() - 1, grid.width() - 1, num_seg_types_x}, 0); + vtr::NdMatrix Fc_yofs({grid.width() - 1, grid.height() - 1, num_seg_types_y}, 0); + // Build opins int rr_edges_before_directs = 0; for (size_t layer = 0; layer < grid.get_num_layers(); layer++) { @@ -2068,16 +2068,19 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder // Build channels VTR_ASSERT(Fs % 3 == 0); - // In case of multi-die FPGA and a custom 3D SB, we keep track of how many 3D connections have been already made for each x,y location - vtr::NdMatrix num_of_3d_conns_custom_SB; - if (grid.get_num_layers() > 1 && sb_conn_map != nullptr) { - num_of_3d_conns_custom_SB.resize({grid.width(), grid.height()}, 0); - } - - t_rr_edge_info_set des_3d_rr_edges_to_create; + t_rr_edge_info_set interdie_3d_rr_edges_to_create; for (size_t i = 0; i < grid.width() - 1; ++i) { for (size_t j = 0; j < grid.height() - 1; ++j) { + + // In multi-die FPGAs with track-to-track connections between layers, we need to load CHANZ nodes + // These extra nodes can be driven from many tracks in the source layer and can drive multiple tracks in the destination layer, + // since these die-crossing connections have more delays. + if (grid.get_num_layers() > 1) { + build_inter_die_3d_rr_chan(rr_graph_builder, i, j, interdie_3d_links[i][j], + CHANX_COST_INDEX_START + num_seg_types_x + num_seg_types_y); + } + for (int layer = 0; layer < (int)grid.get_num_layers(); ++layer) { const auto& device_ctx = g_vpr_ctx.device(); // Skip the current die if architecture file specifies that it doesn't require inter-cluster programmable resource routing @@ -2085,31 +2088,19 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder continue; } - // In multi-die FPGAs with track-to-track connections between layers, we need to load newly added length-0 CHANX nodes - // These extra nodes can be driven from many tracks in the source layer and can drive multiple tracks in the destination layer, - // since these die-crossing connections have more delays. - if (grid.get_num_layers() > 1 && sb_conn_map != nullptr) { - //custom switch block defined in the architecture - VTR_ASSERT(sblock_pattern.empty() && switch_block_conn.empty()); - build_inter_die_custom_sb_rr_chan(rr_graph_builder, layer, i, j, CHANX_COST_INDEX_START, chan_width, - chan_details_x); - } - if (i > 0) { int tracks_per_chan = ((is_global_graph) ? 1 : chan_width.x_list[j]); build_rr_chan(rr_graph_builder, layer, i, j, e_rr_type::CHANX, track_to_pin_lookup_x, sb_conn_map, switch_block_conn, - num_of_3d_conns_custom_SB, CHANX_COST_INDEX_START, + CHANX_COST_INDEX_START, chan_width, grid, tracks_per_chan, sblock_pattern, Fs / 3, chan_details_x, chan_details_y, - rr_edges_to_create, des_3d_rr_edges_to_create, + rr_edges_to_create, wire_to_ipin_switch, wire_to_pin_between_dice_switch, - custom_3d_sb_fanin_fanout, - delayless_switch, directionality); - //Create the actual CHAN->CHAN edges + // Create the actual CHAN->CHAN edges uniquify_edges(rr_edges_to_create); alloc_and_load_edges(rr_graph_builder, rr_edges_to_create); num_edges += rr_edges_to_create.size(); @@ -2120,14 +2111,12 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder int tracks_per_chan = ((is_global_graph) ? 1 : chan_width.y_list[i]); build_rr_chan(rr_graph_builder, layer, i, j, e_rr_type::CHANY, track_to_pin_lookup_y, sb_conn_map, switch_block_conn, - num_of_3d_conns_custom_SB, CHANX_COST_INDEX_START + num_seg_types_x, + CHANX_COST_INDEX_START + num_seg_types_x, chan_width, grid, tracks_per_chan, sblock_pattern, Fs / 3, chan_details_x, chan_details_y, - rr_edges_to_create, des_3d_rr_edges_to_create, + rr_edges_to_create, wire_to_ipin_switch, wire_to_pin_between_dice_switch, - custom_3d_sb_fanin_fanout, - delayless_switch, directionality); //Create the actual CHAN->CHAN edges @@ -2138,14 +2127,17 @@ static std::function alloc_and_load_rr_graph(RRGraphBuilder rr_edges_to_create.clear(); } } - } - } - if (grid.get_num_layers() > 1 && sb_conn_map != nullptr) { - uniquify_edges(des_3d_rr_edges_to_create); - alloc_and_load_edges(rr_graph_builder, des_3d_rr_edges_to_create); - num_edges += des_3d_rr_edges_to_create.size(); - des_3d_rr_edges_to_create.clear(); + if (grid.get_num_layers() > 1) { + add_inter_die_3d_edges(rr_graph_builder, i, j, + chan_details_x, chan_details_y, + interdie_3d_links[i][j], interdie_3d_rr_edges_to_create); + uniquify_edges(interdie_3d_rr_edges_to_create); + alloc_and_load_edges(rr_graph_builder, interdie_3d_rr_edges_to_create); + num_edges += interdie_3d_rr_edges_to_create.size(); + interdie_3d_rr_edges_to_create.clear(); + } + } } VTR_LOGV(route_verbosity > 1, "CHAN->CHAN type edge count:%d\n", num_edges); @@ -2305,7 +2297,8 @@ static void add_classes_rr_graph(RRGraphBuilder& rr_graph_builder, VTR_ASSERT(root_loc.x <= std::numeric_limits::max() && root_loc.y <= std::numeric_limits::max()); rr_graph_builder.set_node_coordinates(class_inode, (short)root_loc.x, (short)root_loc.y, (short)(root_loc.x + physical_type->width - 1), (short)(root_loc.y + physical_type->height - 1)); VTR_ASSERT(root_loc.layer_num <= std::numeric_limits::max()); - rr_graph_builder.set_node_layer(class_inode, root_loc.layer_num); + rr_graph_builder.set_node_layer_low(class_inode, root_loc.layer_num); + rr_graph_builder.set_node_layer_high(class_inode, root_loc.layer_num); float R = 0.; float C = 0.; rr_graph_builder.set_node_rc_index(class_inode, NodeRCIndex(find_create_rr_rc_data(R, C, mutable_device_ctx.rr_rc_data))); @@ -2362,7 +2355,8 @@ static void add_pins_rr_graph(RRGraphBuilder& rr_graph_builder, root_loc.y + y_offset, root_loc.x + x_offset, root_loc.y + y_offset); - rr_graph_builder.set_node_layer(node_id, root_loc.layer_num); + rr_graph_builder.set_node_layer_low(node_id, root_loc.layer_num); + rr_graph_builder.set_node_layer_high(node_id, root_loc.layer_num); rr_graph_builder.add_node_side(node_id, pin_side); } } @@ -2930,7 +2924,6 @@ static void build_rr_chan(RRGraphBuilder& rr_graph_builder, const t_track_to_pin_lookup& track_to_pin_lookup, t_sb_connection_map* sb_conn_map, const vtr::NdMatrix, 3>& switch_block_conn, - vtr::NdMatrix& num_of_3d_conns_custom_SB, const int cost_index_offset, const t_chan_width& nodes_per_chan, const DeviceGrid& grid, @@ -2940,12 +2933,9 @@ static void build_rr_chan(RRGraphBuilder& rr_graph_builder, const t_chan_details& chan_details_x, const t_chan_details& chan_details_y, t_rr_edge_info_set& rr_edges_to_create, - t_rr_edge_info_set& des_3d_rr_edges_to_create, const int wire_to_ipin_switch, const int wire_to_pin_between_dice_switch, - const int custom_3d_sb_fanin_fanout, - const int delayless_switch, - const enum e_directionality directionality) { + const e_directionality directionality) { // this function builds both x and y-directed channel segments, so set up our coordinates based on channel type const auto& device_ctx = g_vpr_ctx.device(); @@ -3024,9 +3014,9 @@ static void build_rr_chan(RRGraphBuilder& rr_graph_builder, if (to_seg_details->length() > 0) { get_track_to_tracks(rr_graph_builder, layer, chan_coord, start, track, chan_type, chan_coord, opposite_chan_type, seg_dimension, max_opposite_chan_width, grid, - Fs_per_side, sblock_pattern, num_of_3d_conns_custom_SB, node, rr_edges_to_create, - des_3d_rr_edges_to_create, from_seg_details, to_seg_details, opposite_chan_details, - directionality, custom_3d_sb_fanin_fanout, delayless_switch, + Fs_per_side, sblock_pattern, node, rr_edges_to_create, + from_seg_details, to_seg_details, opposite_chan_details, + directionality, switch_block_conn, sb_conn_map); } } @@ -3045,9 +3035,9 @@ static void build_rr_chan(RRGraphBuilder& rr_graph_builder, if (to_seg_details->length() > 0) { get_track_to_tracks(rr_graph_builder, layer, chan_coord, start, track, chan_type, chan_coord + 1, opposite_chan_type, seg_dimension, max_opposite_chan_width, grid, - Fs_per_side, sblock_pattern, num_of_3d_conns_custom_SB, node, rr_edges_to_create, - des_3d_rr_edges_to_create, from_seg_details, to_seg_details, opposite_chan_details, - directionality, custom_3d_sb_fanin_fanout, delayless_switch, switch_block_conn, sb_conn_map); + Fs_per_side, sblock_pattern, node, rr_edges_to_create, + from_seg_details, to_seg_details, opposite_chan_details, + directionality, switch_block_conn, sb_conn_map); } } @@ -3076,9 +3066,9 @@ static void build_rr_chan(RRGraphBuilder& rr_graph_builder, if (to_seg_details->length() > 0) { get_track_to_tracks(rr_graph_builder, layer, chan_coord, start, track, chan_type, target_seg, chan_type, seg_dimension, max_chan_width, grid, - Fs_per_side, sblock_pattern, num_of_3d_conns_custom_SB, node, rr_edges_to_create, - des_3d_rr_edges_to_create, from_seg_details, to_seg_details, from_chan_details, - directionality, custom_3d_sb_fanin_fanout, delayless_switch, + Fs_per_side, sblock_pattern, node, rr_edges_to_create, + from_seg_details, to_seg_details, from_chan_details, + directionality, switch_block_conn, sb_conn_map); } } @@ -3098,7 +3088,8 @@ static void build_rr_chan(RRGraphBuilder& rr_graph_builder, rr_graph_builder.set_node_coordinates(node, x_coord, start, x_coord, end); } - rr_graph_builder.set_node_layer(node, layer); + rr_graph_builder.set_node_layer_low(node, layer); + rr_graph_builder.set_node_layer_high(node, layer); int length = end - start + 1; float R = length * seg_details[track].Rmetal(); @@ -3111,15 +3102,51 @@ static void build_rr_chan(RRGraphBuilder& rr_graph_builder, } } -static void build_inter_die_custom_sb_rr_chan(RRGraphBuilder& rr_graph_builder, - const int layer, - const int x_coord, - const int y_coord, - const int const_index_offset, - const t_chan_width& nodes_per_chan, - const t_chan_details& chan_details_x) { +static void add_inter_die_3d_edges(RRGraphBuilder& rr_graph_builder, + int x_coord, + int y_coord, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + const std::vector& interdie_3d_links, + t_rr_edge_info_set& interdie_3d_rr_edges_to_create) { + + const RRSpatialLookup& node_lookup = rr_graph_builder.node_lookup(); + const int num_tracks = interdie_3d_links.size(); + + for (int track = 0; track < num_tracks; track++) { + const t_bottleneck_link& link = interdie_3d_links[track]; + VTR_ASSERT_SAFE(x_coord == link.gather_loc.x && y_coord == link.gather_loc.y); + VTR_ASSERT_SAFE(x_coord == link.scatter_loc.x && y_coord == link.scatter_loc.y); + + RRNodeId chanz_node = node_lookup.find_node(0, x_coord, y_coord, e_rr_type::CHANZ, track); + + for (const t_sg_candidate& gather_wire : link.gather_fanin_connections) { + const t_physical_tile_loc& chan_loc = gather_wire.chan_loc.location; + e_rr_type chan_type = gather_wire.chan_loc.chan_type; + RRNodeId gather_node = node_lookup.find_node(chan_loc.layer_num, chan_loc.x, chan_loc.y, chan_type, gather_wire.wire_switchpoint.wire); + + interdie_3d_rr_edges_to_create.emplace_back(gather_node, chanz_node, link.arch_wire_switch, false); + } + + for (const t_sg_candidate& scatter_wire : link.scatter_fanout_connections) { + const t_physical_tile_loc& chan_loc = scatter_wire.chan_loc.location; + e_rr_type chan_type = scatter_wire.chan_loc.chan_type; + const t_chan_details& chan_details = (chan_type == e_rr_type::CHANX) ? chan_details_x : chan_details_y; + RRNodeId scatter_node = node_lookup.find_node(chan_loc.layer_num, chan_loc.x, chan_loc.y, chan_type, scatter_wire.wire_switchpoint.wire); + + int switch_index = chan_details[chan_loc.x][chan_loc.y][scatter_wire.wire_switchpoint.wire].arch_wire_switch(); + interdie_3d_rr_edges_to_create.emplace_back(chanz_node, scatter_node, switch_index, false); + } + } +} + +static void build_inter_die_3d_rr_chan(RRGraphBuilder& rr_graph_builder, + const int x_coord, + const int y_coord, + const std::vector& interdie_3d_links, + const int const_index_offset) { auto& mutable_device_ctx = g_vpr_ctx.mutable_device(); - const t_chan_seg_details* seg_details = chan_details_x[x_coord][y_coord].data(); + const size_t num_layers = g_vpr_ctx.device().grid.get_num_layers(); // 3D connections within the switch blocks use some CHANZ nodes to allow a single 3D connection to be driven // by multiple tracks in the source layer, and drives multiple tracks in the destination layer. @@ -3132,22 +3159,28 @@ static void build_inter_die_custom_sb_rr_chan(RRGraphBuilder& rr_graph_builder, // 3) xhigh=xlow, yhigh=ylow // 4) directionality: NONE (neither incremental nor decremental in 2D space) - const int start_track = nodes_per_chan.max; - // Go through allocated nodes until no nodes are found within the RRGraph builder for (int track_num = 0; /*no condition*/; track_num++) { // Try to find a node with the current track_num - RRNodeId node = rr_graph_builder.node_lookup().find_node(layer, x_coord, y_coord, e_rr_type::CHANZ, track_num); + + RRNodeId node = rr_graph_builder.node_lookup().find_node(0, x_coord, y_coord, e_rr_type::CHANZ, track_num); + for (size_t layer = 1; layer < num_layers; layer++) { + VTR_ASSERT(node == rr_graph_builder.node_lookup().find_node(layer, x_coord, y_coord, e_rr_type::CHANZ, track_num)); + } // If the track can't be found, it means we have already processed all tracks if (!node.is_valid()) { + VTR_ASSERT(interdie_3d_links.size() == (size_t)track_num); break; } - rr_graph_builder.set_node_layer(node, layer); + // TODO: layer numbers should be extracted from link info + rr_graph_builder.set_node_layer_low(node, 0); + rr_graph_builder.set_node_layer_high(node, 1); + rr_graph_builder.set_node_coordinates(node, x_coord, y_coord, x_coord, y_coord); // TODO: the index doesn't make any sense. We need to an RRIndexedDataId for CHANZ nodes - rr_graph_builder.set_node_cost_index(node, RRIndexedDataId(const_index_offset + seg_details[start_track - 1].index())); + rr_graph_builder.set_node_cost_index(node, RRIndexedDataId(const_index_offset)); rr_graph_builder.set_node_capacity(node, 1); // GLOBAL routing handled elsewhere float R = 0; float C = 0; @@ -3155,7 +3188,12 @@ static void build_inter_die_custom_sb_rr_chan(RRGraphBuilder& rr_graph_builder, rr_graph_builder.set_node_type(node, e_rr_type::CHANZ); rr_graph_builder.set_node_track_num(node, track_num); - rr_graph_builder.set_node_direction(node, Direction::NONE); + if (interdie_3d_links[track_num].scatter_loc.layer_num > interdie_3d_links[track_num].gather_loc.layer_num) { + rr_graph_builder.set_node_direction(node, Direction::INC); + } else { + VTR_ASSERT_SAFE(interdie_3d_links[track_num].scatter_loc.layer_num < interdie_3d_links[track_num].gather_loc.layer_num); + rr_graph_builder.set_node_direction(node, Direction::DEC); + } } } @@ -3971,10 +4009,7 @@ static void build_unidir_rr_opins(RRGraphBuilder& rr_graph_builder, const std::vector& clb_to_clb_directs, const int num_seg_types, int& rr_edge_count) { - /* - * This routine adds the edges from opins to channels at the specified - * grid location (i,j) and grid tile side - */ + // This routine adds the edges from opins to channels at the specified grid location (i,j) and grid tile side *Fc_clipped = false; t_physical_tile_type_ptr type = grid.get_physical_type({i, j, layer}); @@ -4020,7 +4055,7 @@ static void build_unidir_rr_opins(RRGraphBuilder& rr_graph_builder, e_parallel_axis wanted_axis = chan_type == e_rr_type::CHANX ? e_parallel_axis::X_AXIS : e_parallel_axis::Y_AXIS; int seg_index = get_parallel_seg_index(iseg, seg_index_map, wanted_axis); - /*The segment at index iseg doesn't have the proper adjacency so skip building Fc_out conenctions for it*/ + // The segment at index iseg doesn't have the proper adjacency so skip building Fc_out connections for it. if (seg_index < 0) continue; diff --git a/vpr/src/route/rr_graph_generation/rr_graph.h b/vpr/src/route/rr_graph_generation/rr_graph.h index ba61e028998..452e058ddb8 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.h +++ b/vpr/src/route/rr_graph_generation/rr_graph.h @@ -51,13 +51,14 @@ void alloc_and_load_rr_switch_inf(RRGraphBuilder& rr_graph_builder, const float R_minW_nmos, const float R_minW_pmos, const int wire_to_arch_ipin_switch, - int* wire_to_rr_ipin_switch); + RRSwitchId* wire_to_rr_ipin_switch); void rr_graph_externals(const std::vector& segment_inf, const std::vector& segment_inf_x, const std::vector& segment_inf_y, - int wire_to_rr_ipin_switch, - enum e_base_cost_type base_cost_type); + const std::vector& segment_inf_z, + RRSwitchId wire_to_rr_ipin_switch, + e_base_cost_type base_cost_type); std::vector> alloc_and_load_actual_fc(const std::vector& types, const int max_pins, @@ -65,7 +66,7 @@ std::vector> alloc_and_load_actual_fc(const std::vector& sets_per_seg_type, const t_chan_width* nodes_per_chan, const e_fc_type fc_type, - const enum e_directionality directionality, + const e_directionality directionality, bool* Fc_clipped, bool is_flat); diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.cpp b/vpr/src/route/rr_graph_generation/rr_graph2.cpp index bcc4dd1e5a0..22d3bd4140f 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph2.cpp @@ -88,15 +88,11 @@ static void get_switchblocks_edges(RRGraphBuilder& rr_graph_builder, const int to_y, const e_rr_type to_chan_type, const int switch_override, - const int custom_3d_sb_fanin_fanout, - const int delayless_switch, const t_sb_connection_map& sb_conn_map, - vtr::NdMatrix& num_of_3d_conns_custom_SB, t_rr_edge_info_set& rr_edges_to_create, - t_rr_edge_info_set& des_3d_rr_edges_to_create, int& edge_count); -/* +/** * @brief Figures out the edges that should connect the given wire segment to the given channel segment, adds these edges to 'rr_edge_to_create' * * @param rr_graph_builder RRGraphBuilder data structure which allows data modification on a routing resource graph @@ -124,49 +120,9 @@ static int get_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, const e_side from_side, const e_side to_side, const int swtich_override, - const int custom_3d_sb_fanin_fanout, - const int delayless_switch, const t_sb_connection_map& sb_conn_map, - vtr::NdMatrix& num_of_3d_conns_custom_SB, RRNodeId from_rr_node, - t_rr_edge_info_set& rr_edges_to_create, - t_rr_edge_info_set& des_3d_rr_edges_to_create); - -/** - * @brief checks if a specific switch block edge is crossing any layer to create 3D custom switch blocks - * - * @param src_side switch block edge source side - * @param dest_side switch block edge destination side - * - * @return true if the connection going to another layer, false otherwise. - */ -static bool is_sb_conn_layer_crossing(e_side src_side, e_side dest_side); - -/** - * @brief finds corresponding RR nodes for a 3D SB edge and fill 3D custom switch block information (offset to correct extra CHANX nodes, source tracks, ..) - * - * @param rr_graph_builder RRGraphBuilder data structure which allows data modification on a routing resource graph - * @param x x-coordinate of both src and dest wires - * @param y y-coordinate of both src and dest wires - * @param from_wire from wire index within channel width - * @param from_wire_layer from wire layer-coordinate - * @param from_wire_type from wire type (CHANX/CHANY) - * @param to_wire to wire index within channel width - * @param to_wire_layer to wire layer-coordinate - * @param to_wire_type to wire type (CHANX/CHANY) - * @param curr_switchblocks_offset number of extra nodes that has already been added to the current switch block - * - * @ returns whether both source track RR node and destination RR node exist - */ -static bool check_3d_SB_RRnodes(RRGraphBuilder& rr_graph_builder, - int x, - int y, - int from_wire, - int from_wire_layer, - e_rr_type from_wire_type, - int to_wire, - int to_wire_layer, - e_rr_type to_wire_type); + t_rr_edge_info_set& rr_edges_to_create); static int vpr_to_phy_track(const int itrack, const int chan_num, @@ -287,7 +243,7 @@ std::vector alloc_and_load_seg_details(int* max_chan_width, const int max_len, const std::vector& segment_inf, const bool use_full_seg_groups, - const enum e_directionality directionality) { + const e_directionality directionality) { /* Allocates and loads the seg_details data structure. Max_len gives the * * maximum length of a segment (dimension of array). The code below tries * * to: * @@ -815,14 +771,12 @@ int get_unidir_opin_connections(RRGraphBuilder& rr_graph_builder, } bool is_cblock(const int chan, const int seg, const int track, const t_chan_seg_details* seg_details) { - int length, ofs, start_seg; + int length = seg_details[track].length(); - length = seg_details[track].length(); + // Make sure they gave us correct start + int start_seg = get_seg_start(seg_details, track, chan, seg); - /* Make sure they gave us correct start */ - start_seg = get_seg_start(seg_details, track, chan, seg); - - ofs = seg - start_seg; + int ofs = seg - start_seg; VTR_ASSERT(ofs >= 0); VTR_ASSERT(ofs < length); @@ -1036,84 +990,6 @@ void dump_track_to_pin_map(t_track_to_pin_lookup& track_to_pin_map, } } -static bool is_sb_conn_layer_crossing(e_side src_side, e_side dest_side) { - if (src_side < NUM_2D_SIDES && dest_side < NUM_2D_SIDES) { - return false; - } - - if (src_side == dest_side) { - return false; - } - - return true; -} - -static bool check_3d_SB_RRnodes(RRGraphBuilder& rr_graph_builder, - int x, - int y, - int from_wire, - int from_wire_layer, - e_rr_type from_wire_type, - int to_wire, - int to_wire_layer, - e_rr_type to_wire_type) { - RRNodeId from_inode = rr_graph_builder.node_lookup().find_node(from_wire_layer, x, y, from_wire_type, from_wire); - RRNodeId to_inode = rr_graph_builder.node_lookup().find_node(to_wire_layer, x, y, to_wire_type, to_wire); - - if (from_inode && to_inode) { - return true; - } - - return false; -} - -vtr::NdMatrix get_number_track_to_track_inter_die_conn(t_sb_connection_map* sb_conn_map, - const int custom_3d_sb_fanin_fanout, - RRGraphBuilder& rr_graph_builder) { - const auto& grid_ctx = g_vpr_ctx.device().grid; - vtr::NdMatrix extra_nodes_per_switchblocks{{grid_ctx.width(), grid_ctx.height()}, 0}; - - for (size_t y = 0; y < grid_ctx.height(); y++) { - for (size_t x = 0; x < grid_ctx.width(); x++) { - for (int layer = 0; layer < (int)grid_ctx.get_num_layers(); layer++) { - - int num_of_3d_conn = 0; - for (e_side from_side : TOTAL_3D_SIDES) { - for (e_side to_side : TOTAL_3D_SIDES) { - if (!is_sb_conn_layer_crossing(from_side, to_side)) { // this connection is not crossing any layer - continue; - } - - SwitchblockLookupKey sb_coord(x, y, layer, from_side, to_side); - if (sb_conn_map->count(sb_coord) > 0) { - std::vector& conn_vector = (*sb_conn_map)[sb_coord]; - for (const t_switchblock_edge& iconn : conn_vector) { - // check if both from_node and to_node exists in the rr-graph - // CHANY -> CHANX connection - if (check_3d_SB_RRnodes(rr_graph_builder, x, y, iconn.from_wire, - iconn.from_wire_layer, e_rr_type::CHANY, - iconn.to_wire, iconn.to_wire_layer, - e_rr_type::CHANX)) { - num_of_3d_conn++; - } - // CHANX -> CHANY connection - if (check_3d_SB_RRnodes(rr_graph_builder, x, y, iconn.from_wire, - iconn.from_wire_layer, e_rr_type::CHANX, - iconn.to_wire, iconn.to_wire_layer, - e_rr_type::CHANY)) { - num_of_3d_conn++; - } - } - } - } - } - extra_nodes_per_switchblocks[x][y] += ((num_of_3d_conn + custom_3d_sb_fanin_fanout - 1) / custom_3d_sb_fanin_fanout); - } - } - } - return extra_nodes_per_switchblocks; -} - int get_track_to_pins(RRGraphBuilder& rr_graph_builder, int layer, int seg, @@ -1124,11 +1000,11 @@ int get_track_to_pins(RRGraphBuilder& rr_graph_builder, t_rr_edge_info_set& rr_edges_to_create, const t_track_to_pin_lookup& track_to_pin_lookup, const t_chan_seg_details* seg_details, - enum e_rr_type chan_type, + e_rr_type chan_type, int chan_length, int wire_to_ipin_switch, int wire_to_pin_between_dice_switch, - enum e_directionality directionality) { + e_directionality directionality) { /* * Adds the fan-out edges from wire segment at (chan, seg, track) to adjacent * blocks along the wire's length @@ -1229,22 +1105,18 @@ int get_track_to_tracks(RRGraphBuilder& rr_graph_builder, const DeviceGrid& grid, const int Fs_per_side, t_sblock_pattern& sblock_pattern, - vtr::NdMatrix& num_of_3d_conns_custom_SB, RRNodeId from_rr_node, t_rr_edge_info_set& rr_edges_to_create, - t_rr_edge_info_set& des_3d_rr_edges_to_create, const t_chan_seg_details* from_seg_details, const t_chan_seg_details* to_seg_details, const t_chan_details& to_chan_details, - const enum e_directionality directionality, - const int custom_3d_sb_fanin_fanout, - const int delayless_switch, + const e_directionality directionality, const vtr::NdMatrix, 3>& switch_block_conn, const t_sb_connection_map* sb_conn_map) { int to_chan, to_sb; std::vector conn_tracks; bool from_is_sblock, is_behind, Fs_clipped; - enum e_side to_side; + e_side to_side; /* check whether a custom switch block will be used */ bool custom_switch_block = false; @@ -1369,8 +1241,8 @@ int get_track_to_tracks(RRGraphBuilder& rr_graph_builder, if (Direction::DEC == from_seg_details[from_track].direction() || BI_DIRECTIONAL == directionality) { num_conn += get_track_to_chan_seg(rr_graph_builder, layer, from_track, to_chan, to_seg, to_type, from_side_a, to_side, - switch_override, custom_3d_sb_fanin_fanout, delayless_switch, - *sb_conn_map, num_of_3d_conns_custom_SB, from_rr_node, rr_edges_to_create, des_3d_rr_edges_to_create); + switch_override, + *sb_conn_map, from_rr_node, rr_edges_to_create); } } else { if (BI_DIRECTIONAL == directionality) { @@ -1407,8 +1279,8 @@ int get_track_to_tracks(RRGraphBuilder& rr_graph_builder, if (Direction::INC == from_seg_details[from_track].direction() || BI_DIRECTIONAL == directionality) { num_conn += get_track_to_chan_seg(rr_graph_builder, layer, from_track, to_chan, to_seg, to_type, from_side_b, to_side, - switch_override, custom_3d_sb_fanin_fanout, delayless_switch, - *sb_conn_map, num_of_3d_conns_custom_SB, from_rr_node, rr_edges_to_create, des_3d_rr_edges_to_create); + switch_override, + *sb_conn_map, from_rr_node, rr_edges_to_create); } } else { if (BI_DIRECTIONAL == directionality) { @@ -1519,12 +1391,8 @@ static void get_switchblocks_edges(RRGraphBuilder& rr_graph_builder, const int to_y, const e_rr_type to_chan_type, const int switch_override, - const int custom_3d_sb_fanin_fanout, - const int delayless_switch, const t_sb_connection_map& sb_conn_map, - vtr::NdMatrix& num_of_3d_conns_custom_SB, t_rr_edge_info_set& rr_edges_to_create, - t_rr_edge_info_set& des_3d_rr_edges_to_create, int& edge_count) { const auto& device_ctx = g_vpr_ctx.device(); @@ -1540,84 +1408,27 @@ static void get_switchblocks_edges(RRGraphBuilder& rr_graph_builder, if (sb_edge.from_wire != from_wire) continue; int to_wire = sb_edge.to_wire; - int to_layer = sb_edge.to_wire_layer; // Get the index of the switch connecting the two wires int src_switch = sb_edge.switch_ind; - // Get the index of the switch connecting the two wires in two layers - int src_switch_betwen_layers = sb_edge.switch_ind_between_layers; - - if (to_layer == layer) { // track-to-track connection within the same layer - RRNodeId to_node = rr_graph_builder.node_lookup().find_node(to_layer, to_x, to_y, to_chan_type, to_wire); - - if (!to_node) { - continue; - } - - // Apply any switch overrides - if (should_apply_switch_override(switch_override)) { - src_switch = switch_override; - } - - rr_edges_to_create.emplace_back(from_rr_node, to_node, src_switch, false); - ++edge_count; - - if (device_ctx.arch_switch_inf[src_switch].directionality() == BI_DIRECTIONAL) { - // Add reverse edge since bidirectional - rr_edges_to_create.emplace_back(to_node, from_rr_node, src_switch, false); - ++edge_count; - } - } else { // track-to_track connection crossing layer - VTR_ASSERT(to_layer != layer); - // Check if current connection is valid, since switch block pattern is very general, - // we might see invalid layer in connection, so we just skip those - if ((layer < 0 || layer >= (int)device_ctx.grid.get_num_layers()) - || (to_layer < 0 || to_layer >= (int)device_ctx.grid.get_num_layers())) { - continue; - } - if (tile_x != to_x || tile_y != to_y) { - continue; - } + RRNodeId to_node = rr_graph_builder.node_lookup().find_node(layer, to_x, to_y, to_chan_type, to_wire); - // In order to connect two tracks in different layers, we need to follow these three steps: - // 1) connect "from_tracks" to CHANZ node in the same switch block - // 2) connect CHANZ node located in from_layer to another CHANZ node located in to_layer - // 3) connect CHANZ node located in to_layer to "to_track" - // +-------------+ +-------------+ +--------------+ +--------------+ - // | from_wire | -----> | CHANZ node | ------> | CHANZ node | ------> | to_wire | - // | (src_layer) | | (src_layer) | | (dest_layer) | | (dest_layer) | - // +-------------+ +-------------+ +--------------+ +--------------+ - - const int chanz_track_num = num_of_3d_conns_custom_SB[tile_x][tile_y] / custom_3d_sb_fanin_fanout; - RRNodeId src_chanz_node = rr_graph_builder.node_lookup().find_node(layer, tile_x, tile_y, e_rr_type::CHANZ, chanz_track_num); - RRNodeId sink_chanz_node = rr_graph_builder.node_lookup().find_node(to_layer, tile_x, tile_y, e_rr_type::CHANZ, chanz_track_num); - RRNodeId sink_track_node = rr_graph_builder.node_lookup().find_node(to_layer, to_x, to_y, to_chan_type, to_wire); - - if (!src_chanz_node || !sink_chanz_node || !sink_track_node) { - continue; - } + if (!to_node) { + continue; + } - // Apply any switch overrides - if (should_apply_switch_override(switch_override)) { - src_switch = switch_override; - } + // Apply any switch overrides + if (should_apply_switch_override(switch_override)) { + src_switch = switch_override; + } - // Add edge between source node at from layer to intermediate node - rr_edges_to_create.emplace_back(from_rr_node, src_chanz_node, delayless_switch, false); - ++edge_count; + rr_edges_to_create.emplace_back(from_rr_node, to_node, src_switch, false); + ++edge_count; - // Add edge between intermediate node to destination node at to layer - // might add the same edge more than once, but redundant edges will be removed before updating the RR graph - des_3d_rr_edges_to_create.emplace_back(sink_chanz_node, sink_track_node, src_switch_betwen_layers, false); + if (device_ctx.arch_switch_inf[src_switch].directionality() == BI_DIRECTIONAL) { + // Add reverse edge since bidirectional + rr_edges_to_create.emplace_back(to_node, from_rr_node, src_switch, false); ++edge_count; - - // We only add the following edge between intermediate nodes once for the first 3D connection for each pair of intermediate nodes - if (num_of_3d_conns_custom_SB[tile_x][tile_y] % custom_3d_sb_fanin_fanout == 0) { - rr_edges_to_create.emplace_back(src_chanz_node, sink_chanz_node, delayless_switch, false); - ++edge_count; - } - - num_of_3d_conns_custom_SB[tile_x][tile_y]++; } } } @@ -1632,13 +1443,9 @@ static int get_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, const e_side from_side, const e_side to_side, const int switch_override, - const int custom_3d_sb_fanin_fanout, - const int delayless_switch, const t_sb_connection_map& sb_conn_map, - vtr::NdMatrix& num_of_3d_conns_custom_SB, RRNodeId from_rr_node, - t_rr_edge_info_set& rr_edges_to_create, - t_rr_edge_info_set& des_3d_rr_edges_to_create) { + t_rr_edge_info_set& rr_edges_to_create) { int edge_count = 0; int to_x, to_y; int tile_x, tile_y; @@ -1671,36 +1478,10 @@ static int get_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, to_y, to_chan_type, switch_override, - custom_3d_sb_fanin_fanout, - delayless_switch, sb_conn_map, - num_of_3d_conns_custom_SB, rr_edges_to_create, - des_3d_rr_edges_to_create, edge_count); - // Check sb_conn_map for connections between two layers - for (e_side to_another_die_side : {ABOVE, UNDER}) { - get_switchblocks_edges(rr_graph_builder, - tile_x, - tile_y, - layer, - from_side, - from_wire, - from_rr_node, - to_another_die_side, - to_x, - to_y, - to_chan_type, - switch_override, - custom_3d_sb_fanin_fanout, - delayless_switch, - sb_conn_map, - num_of_3d_conns_custom_SB, - rr_edges_to_create, - des_3d_rr_edges_to_create, - edge_count); - } return edge_count; } diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.h b/vpr/src/route/rr_graph_generation/rr_graph2.h index 87c3024f352..45bebc65f4d 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.h +++ b/vpr/src/route/rr_graph_generation/rr_graph2.h @@ -11,23 +11,11 @@ /******************* Subroutines exported by rr_graph2.c *********************/ -/** - * @brief Goes through 3D custom switch blocks and counts how many connections are crossing dice for each switch block. - * - * @param sb_conn_map switch block permutation map - * @param rr_graph_builder RRGraphBuilder data structure which allows data modification on a routing resource graph - * - * @return number of die-crossing connection for each unique (x, y) location within the grid ([0..grid.width-1][0..grid.height-1]) - */ -vtr::NdMatrix get_number_track_to_track_inter_die_conn(t_sb_connection_map* sb_conn_map, - const int custom_3d_sb_fanin_fanout, - RRGraphBuilder& rr_graph_builder); - std::vector alloc_and_load_seg_details(int* max_chan_width, const int max_len, const std::vector& segment_inf, const bool use_full_seg_groups, - const enum e_directionality directionality); + const e_directionality directionality); void alloc_and_load_chan_details(const DeviceGrid& grid, const t_chan_width& nodes_per_chan, @@ -113,11 +101,11 @@ int get_track_to_pins(RRGraphBuilder& rr_graph_builder, t_rr_edge_info_set& rr_edges_to_create, const t_track_to_pin_lookup& track_to_pin_lookup, const t_chan_seg_details* seg_details, - enum e_rr_type chan_type, + e_rr_type chan_type, int chan_length, int wire_to_ipin_switch, int wire_to_pin_between_dice_switch, - enum e_directionality directionality); + e_directionality directionality); int get_track_to_tracks(RRGraphBuilder& rr_graph_builder, const int layer, @@ -132,16 +120,12 @@ int get_track_to_tracks(RRGraphBuilder& rr_graph_builder, const DeviceGrid& grid, const int Fs_per_side, t_sblock_pattern& sblock_pattern, - vtr::NdMatrix& num_of_3d_conns_custom_SB, RRNodeId from_rr_node, t_rr_edge_info_set& rr_edges_to_create, - t_rr_edge_info_set& des_3d_rr_edges_to_create, const t_chan_seg_details* from_seg_details, const t_chan_seg_details* to_seg_details, const t_chan_details& to_chan_details, - const enum e_directionality directionality, - const int custom_3d_sb_fanin_fanout, - const int delayless_switch, + const e_directionality directionality, const vtr::NdMatrix, 3>& switch_block_conn, const t_sb_connection_map* sb_conn_map); diff --git a/vpr/src/route/rr_graph_generation/rr_graph_area.cpp b/vpr/src/route/rr_graph_generation/rr_graph_area.cpp index 6c8f6b1b9c9..c0952b620cd 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_area.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph_area.cpp @@ -24,17 +24,17 @@ static const e_trans_area_eq trans_area_eq = AREA_IMPROVED_NMOS_ONLY; /************************ Subroutines local to this module *******************/ -static void count_bidir_routing_transistors(int num_switch, int wire_to_ipin_switch, float R_minW_nmos, float R_minW_pmos, const float trans_sram_bit); +static void count_bidir_routing_transistors(int num_switch, RRSwitchId wire_to_ipin_switch, float R_minW_nmos, float R_minW_pmos, const float trans_sram_bit); static void count_unidir_routing_transistors(std::vector& segment_inf, - int wire_to_ipin_switch, + RRSwitchId wire_to_ipin_switch, float R_minW_nmos, float R_minW_pmos, const float trans_sram_bit, bool is_flat); static float get_cblock_trans(vtr::vector& num_inputs_to_cblock, - int wire_to_ipin_switch, + RRSwitchId wire_to_ipin_switch, int max_inputs_to_cblock, float trans_sram_bit); @@ -54,7 +54,7 @@ static float trans_per_R(float Rtrans, float R_minW_trans); void count_routing_transistors(enum e_directionality directionality, int num_switch, - int wire_to_ipin_switch, + RRSwitchId wire_to_ipin_switch, std::vector& segment_inf, float R_minW_nmos, float R_minW_pmos, @@ -87,7 +87,7 @@ void count_routing_transistors(enum e_directionality directionality, } } -void count_bidir_routing_transistors(int num_switch, int wire_to_ipin_switch, float R_minW_nmos, float R_minW_pmos, const float trans_sram_bit) { +static void count_bidir_routing_transistors(int num_switch, RRSwitchId wire_to_ipin_switch, float R_minW_nmos, float R_minW_pmos, const float trans_sram_bit) { /* Tri-state buffers are designed as a buffer followed by a pass transistor. * * I make Rbuffer = Rpass_transitor = 1/2 Rtri-state_buffer. * * I make the pull-up and pull-down sides of the buffer the same strength -- * @@ -300,12 +300,12 @@ void count_bidir_routing_transistors(int num_switch, int wire_to_ipin_switch, fl VTR_LOG("\n"); } -void count_unidir_routing_transistors(std::vector& /*segment_inf*/, - int wire_to_ipin_switch, - float R_minW_nmos, - float R_minW_pmos, - const float trans_sram_bit, - bool is_flat) { +static void count_unidir_routing_transistors(std::vector& /*segment_inf*/, + RRSwitchId wire_to_ipin_switch, + float R_minW_nmos, + float R_minW_pmos, + const float trans_sram_bit, + bool is_flat) { auto& device_ctx = g_vpr_ctx.device(); const auto& rr_graph = device_ctx.rr_graph; @@ -484,7 +484,7 @@ void count_unidir_routing_transistors(std::vector& /*segment_inf* } static float get_cblock_trans(vtr::vector& num_inputs_to_cblock, - int wire_to_ipin_switch, + RRSwitchId wire_to_ipin_switch, int max_inputs_to_cblock, float trans_sram_bit) { /* Computes the transistors in the input connection block multiplexers and * @@ -508,8 +508,8 @@ static float get_cblock_trans(vtr::vector& num_inputs_to_cblock, for (int i = 1; i <= max_inputs_to_cblock; i++) { trans_per_cblock[i] = trans_per_mux(i, trans_sram_bit, - rr_graph.rr_switch_inf(RRSwitchId(wire_to_ipin_switch)).mux_trans_size); - trans_per_cblock[i] += rr_graph.rr_switch_inf(RRSwitchId(wire_to_ipin_switch)).buf_size; + rr_graph.rr_switch_inf(wire_to_ipin_switch).mux_trans_size); + trans_per_cblock[i] += rr_graph.rr_switch_inf(wire_to_ipin_switch).buf_size; } trans_count = 0.; diff --git a/vpr/src/route/rr_graph_generation/rr_graph_area.h b/vpr/src/route/rr_graph_generation/rr_graph_area.h index cac5c81794e..014ef247172 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_area.h +++ b/vpr/src/route/rr_graph_generation/rr_graph_area.h @@ -5,7 +5,7 @@ void count_routing_transistors(enum e_directionality directionality, int num_switch, - int wire_to_ipin_switch, + RRSwitchId wire_to_ipin_switch, std::vector& segment_inf, float R_minW_nmos, float R_minW_pmos, diff --git a/vpr/src/route/rr_graph_generation/rr_graph_sbox.cpp b/vpr/src/route/rr_graph_generation/rr_graph_sbox.cpp index 3ddb41e0eda..37a729a0368 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_sbox.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph_sbox.cpp @@ -94,13 +94,13 @@ int get_simple_switch_block_track(const enum e_side from_side, int to_track = -1; // Can check to see if it's not set later. - if (switch_block_type == SUBSET) { /* NB: Global routing uses SUBSET too */ + if (switch_block_type == e_switch_block_type::SUBSET) { /* NB: Global routing uses SUBSET too */ to_track = from_track; } /* See S. Wilton Phd thesis, U of T, 1996 p. 103 for details on following. */ - else if (switch_block_type == WILTON) { + else if (switch_block_type == e_switch_block_type::WILTON) { if (from_side == LEFT) { if (to_side == RIGHT) { /* CHANX to CHANX */ to_track = from_track; @@ -147,7 +147,7 @@ int get_simple_switch_block_track(const enum e_side from_side, } } /* End switch_block_type == WILTON case. */ - else if (switch_block_type == UNIVERSAL) { + else if (switch_block_type == e_switch_block_type::UNIVERSAL) { if (from_side == LEFT) { if (to_side == RIGHT) { /* CHANX to CHANX */ to_track = from_track; @@ -191,7 +191,7 @@ int get_simple_switch_block_track(const enum e_side from_side, /* End switch_block_type == UNIVERSAL case. */ /* UDSD Modification by WMF Begin */ - if (switch_block_type == FULL) { /* Just a placeholder. No meaning in reality */ + if (switch_block_type == e_switch_block_type::FULL) { /* Just a placeholder. No meaning in reality */ to_track = from_track; } /* UDSD Modification by WMF End */ diff --git a/vpr/src/route/rr_graph_generation/rr_node_indices.cpp b/vpr/src/route/rr_graph_generation/rr_node_indices.cpp index 5820d237ebc..68c7adbbf0a 100644 --- a/vpr/src/route/rr_graph_generation/rr_node_indices.cpp +++ b/vpr/src/route/rr_graph_generation/rr_node_indices.cpp @@ -1,6 +1,7 @@ #include "rr_node_indices.h" +#include "build_scatter_gathers.h" #include "describe_rr_node.h" #include "globals.h" #include "physical_types.h" @@ -323,8 +324,7 @@ void alloc_and_load_rr_node_indices(RRGraphBuilder& rr_graph_builder, } void alloc_and_load_inter_die_rr_node_indices(RRGraphBuilder& rr_graph_builder, - const DeviceGrid& grid, - const vtr::NdMatrix& extra_nodes_per_switchblock, + const vtr::NdMatrix, 2>& interdie_3d_links, int* index) { // In case of multi-die FPGAs, we add extra nodes of type CHANZ to // support inter-die communication coming from switch blocks (connection between two tracks in different layers) @@ -332,35 +332,32 @@ void alloc_and_load_inter_die_rr_node_indices(RRGraphBuilder& rr_graph_builder, // 1) type = CHANZ // 2) xhigh == xlow, yhigh == ylow // 3) ptc = [0:number_of_connection-1] - // 4) direction = NONE - const auto& device_ctx = g_vpr_ctx.device(); - - for (size_t layer = 0; layer < grid.get_num_layers(); layer++) { - // Skip the current die if architecture file specifies that it doesn't have global resource routing - if (!device_ctx.inter_cluster_prog_routing_resources.at(layer)) { - continue; - } + const DeviceContext& device_ctx = g_vpr_ctx.device(); + const DeviceGrid& grid = device_ctx.grid; - for (size_t y = 0; y < grid.height() - 1; ++y) { - for (size_t x = 1; x < grid.width() - 1; ++x) { - // how many track-to-track connection go from current layer to other layers - int conn_count = extra_nodes_per_switchblock[x][y]; + for (size_t x = 0; x < grid.width(); x++) { + for (size_t y = 0; y < grid.height(); y++) { + const int num_chanz_nodes = interdie_3d_links[x][y].size(); - // skip if no connection is required - if (conn_count == 0) { - continue; - } + // reserve extra nodes for inter-die track-to-track connection + for (size_t layer = 0; layer < grid.get_num_layers(); layer++) { + rr_graph_builder.node_lookup().reserve_nodes(layer, x, y, e_rr_type::CHANZ, num_chanz_nodes); + } - // reserve extra nodes for inter-die track-to-track connection - rr_graph_builder.node_lookup().reserve_nodes(layer, x, y, e_rr_type::CHANZ, conn_count); - for (int rr_node_offset = 0; rr_node_offset < conn_count; rr_node_offset++) { - RRNodeId inode = rr_graph_builder.node_lookup().find_node(layer, x, y, e_rr_type::CHANZ, rr_node_offset); + for (int track_num = 0; track_num < num_chanz_nodes; track_num++) { + bool incremnet_index = false; + for (size_t layer = 0; layer < grid.get_num_layers(); layer++) { + RRNodeId inode = rr_graph_builder.node_lookup().find_node(layer, x, y, e_rr_type::CHANZ, track_num); if (!inode) { inode = RRNodeId(*index); - ++(*index); - rr_graph_builder.node_lookup().add_node(inode, layer, x, y, e_rr_type::CHANZ, rr_node_offset); + rr_graph_builder.node_lookup().add_node(inode, layer, x, y, e_rr_type::CHANZ, track_num); + incremnet_index = true; } } + + if (incremnet_index) { + ++(*index); + } } } } @@ -466,7 +463,7 @@ bool verify_rr_node_indices(const DeviceGrid& grid, describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); } - if (rr_graph.node_layer(inode) != l) { + if (l < rr_graph.node_layer_low(inode) && l > rr_graph.node_layer_high(inode)) { VPR_ERROR(VPR_ERROR_ROUTE, "RR node layer does not match between rr_nodes and rr_node_indices (%s/%s): %s", rr_node_typename[rr_graph.node_type(inode)], rr_node_typename[rr_type], diff --git a/vpr/src/route/rr_graph_generation/rr_node_indices.h b/vpr/src/route/rr_graph_generation/rr_node_indices.h index 91ddab2fcc9..ef2b34ef1be 100644 --- a/vpr/src/route/rr_graph_generation/rr_node_indices.h +++ b/vpr/src/route/rr_graph_generation/rr_node_indices.h @@ -8,6 +8,8 @@ #include "rr_graph_utils.h" #include "clustered_netlist_fwd.h" +struct t_bottleneck_link; + /** * @brief Allocates and populates data structures for efficient rr_node index lookups. * @@ -32,15 +34,11 @@ void alloc_and_load_rr_node_indices(RRGraphBuilder& rr_graph_builder, * @brief Allocates extra nodes within the RR graph to support 3D custom switch blocks for multi-die FPGAs * * @param rr_graph_builder RRGraphBuilder data structure which allows data modification on a routing resource graph - * @param nodes_per_chan number of tracks per channel (x, y) - * @param grid The device grid representing the physical layout of tiles in the FPGA fabric. - * @param extra_nodes_per_switchblock keeps how many extra length-0 CHANX node is required for each unique (x,y) location within the grid. - * Number of these extra nodes are exactly the same for all layers. Hence, we only keep it for one layer. ([0..grid.width-1][0..grid.height-1) + * @param interdie_3d_links Specifies the 3-d inter-die wires that are to be added at each switch-block location. * @param index Pointer to the global RR node index counter; incremented as new RR nodes are assigned. */ void alloc_and_load_inter_die_rr_node_indices(RRGraphBuilder& rr_graph_builder, - const DeviceGrid& grid, - const vtr::NdMatrix& extra_nodes_per_switchblock, + const vtr::NdMatrix, 2>& interdie_3d_links, int* index); /** diff --git a/vpr/src/route/rr_graph_generation/switchblock_scatter_gather_common_utils.cpp b/vpr/src/route/rr_graph_generation/switchblock_scatter_gather_common_utils.cpp new file mode 100644 index 00000000000..3a244d9baf6 --- /dev/null +++ b/vpr/src/route/rr_graph_generation/switchblock_scatter_gather_common_utils.cpp @@ -0,0 +1,472 @@ + +#include "switchblock_scatter_gather_common_utils.h" + +#include "globals.h" +#include "vpr_error.h" +#include "rr_node_types.h" +#include "rr_types.h" +#include "vtr_expr_eval.h" + +// +// Static Function Declarations +// + +/** + * Returns wire segment length based on either: + * 1) the wire length specified in the segment details variable for this wire (if this wire segment doesn't span entire FPGA) + * 2) the seg_start and seg_end coordinates in the segment details for this wire (if this wire segment spans entire FPGA, as might happen for very long wires) + * + * Computing the wire segment length in this way help to classify short vs long wire segments according to switchpoint. + */ +static int get_wire_segment_length(e_rr_type chan_type, + const t_chan_seg_details& wire_details); + +/** + * @brief Returns the subsegment number of the specified wire at seg_coord + */ +static int get_wire_subsegment_num(e_rr_type chan_type, + const t_chan_seg_details& wire_details, + int seg_coord); + +/** + * @brief Counts and summarizes wire types in a routing channel. + * + * Iterates through the given array of segment details for a routing channel, + * grouping segments by wire type (as identified by `type_name()`). + * For each unique wire type, it records: + * - the wire segment length, + * - the number of wires of that type, + * - the start index of the first wire of that type in the array. + * + * @param channel Pointer to an array of `t_chan_seg_details` representing the wires in a channel. + * @param nodes_per_chan The total number of wire segments (i.e., size of the `channel` array). + * @return A map (`t_wire_type_sizes`) from wire type name to `WireInfo` containing size and indexing info for each type. + */ +static t_wire_type_sizes count_chan_wire_type_sizes(const t_chan_seg_details* channel, int nodes_per_chan); + +/** + * @brief Check whether specified coordinate is located at the device grid corner and a switch block exists there + * @return true if the specified coordinate represents a corner location within the device grid and a switch block exists there, false otherwise. + */ +static bool is_corner_sb(const DeviceGrid& grid, const t_physical_tile_loc& loc); + +/** + * @brief check whether specified coordinate is located at one of the perimeter device grid locations and a switch block exists there * + * @return true if the specified coordinate represents a perimeter location within the device grid and a switch block exists there, false otherwise. + */ +static bool is_perimeter_sb(const DeviceGrid& grid, const t_physical_tile_loc& loc); + +/** + * @brief check whether specified coordinate is located at core of the device grid (not perimeter) and a switch block exists there + * @return true if the specified coordinate represents a core location within the device grid and a switch block exists there, false otherwise. + */ +static bool is_core_sb(const DeviceGrid& grid, const t_physical_tile_loc& loc); + +/** + * @brief check whether specified coordinate is located in the architecture-specified regions that the switchblock should be applied to + * @return true if the specified coordinate falls into the architecture-specified location for this switchblock, false otherwise. + */ +static bool match_sb_xy(const DeviceGrid& grid, const t_physical_tile_loc& loc, const t_specified_loc& sb); + +static bool is_corner_sb(const DeviceGrid& grid, const t_physical_tile_loc& loc) { + bool is_corner = false; + if ((loc.x == 0 && loc.y == 0) || (loc.x == 0 && loc.y == int(grid.height()) - 2) || //-2 for no perim channels + (loc.x == int(grid.width()) - 2 && loc.y == 0) || //-2 for no perim channels + (loc.x == int(grid.width()) - 2 && loc.y == int(grid.height()) - 2)) { //-2 for no perim channels + is_corner = true; + } + return is_corner; +} + +static bool is_perimeter_sb(const DeviceGrid& grid, const t_physical_tile_loc& loc) { + bool is_perimeter = false; + if (loc.x == 0 || loc.x == int(grid.width()) - 2 || loc.y == 0 || loc.y == int(grid.height()) - 2) { + is_perimeter = true; + } + return is_perimeter; +} + +static bool is_core_sb(const DeviceGrid& grid, const t_physical_tile_loc& loc) { + bool is_core = !is_perimeter_sb(grid, loc); + return is_core; +} + +// +// Static Function Definitions +// + +static bool match_sb_xy(const DeviceGrid& grid, + const t_physical_tile_loc& loc, + const t_specified_loc& specified_loc) { + // if one of sb_x and sb_y is defined, we either know the exact location (x,y) or the exact x location (will apply it to all rows) + // or the exact y location (will apply it to all columns) + if (specified_loc.x != -1 || specified_loc.y != -1) { + if (loc.x == specified_loc.x && loc.y == specified_loc.y) { + return true; + } + + if (loc.x == specified_loc.x && specified_loc.y == -1) { + return true; + } + + if (specified_loc.x == -1 && loc.y == specified_loc.y) { + return true; + } + } + + // if both sb_x and sb_y is not defined, we have a region that we should apply this SB pattern to, we just need to check + // whether the location passed into this function falls within this region or not + // calculate the appropriate region based on the repeatx/repeaty and current location. + // This is to determine whether the given location is part of the current SB specified region with regular expression or not + // After region calculation, the current SB will apply to this location if: + // 1) the given (x,y) location falls into the calculated region + // *AND* + // 2) incrx/incry are respected within the region, this means all locations within the calculated region do + // not necessarily crosspond to the current SB. If incrx/incry is equal to 1, then all locations within the + // calculated region are valid. + + // calculate the region + int x_reg_step = (specified_loc.reg_x.repeat != 0) ? (loc.x - specified_loc.reg_x.start) / specified_loc.reg_x.repeat : specified_loc.reg_x.start; + int y_reg_step = (specified_loc.reg_y.repeat != 0) ? (loc.y - specified_loc.reg_y.start) / specified_loc.reg_y.repeat : specified_loc.reg_y.start; + + // step must be non-negative + x_reg_step = std::max(0, x_reg_step); + y_reg_step = std::max(0, y_reg_step); + + int reg_startx = specified_loc.reg_x.start + (x_reg_step * specified_loc.reg_x.repeat); + int reg_endx = specified_loc.reg_x.end + (x_reg_step * specified_loc.reg_x.repeat); + reg_endx = std::min(reg_endx, int(grid.width() - 1)); + + int reg_starty = specified_loc.reg_y.start + (y_reg_step * specified_loc.reg_y.repeat); + int reg_endy = specified_loc.reg_y.end + (y_reg_step * specified_loc.reg_y.repeat); + reg_endy = std::min(reg_endy, int(grid.height() - 1)); + + // check x coordinate + if (loc.x >= reg_startx && loc.x <= reg_endx) { //should fall into the region + // we also should respect the incrx + // if incrx is not equal to 1, all locations within this region are *NOT* valid + if ((loc.x + reg_startx) % specified_loc.reg_x.incr == 0) { + // valid x coordinate, check for y value + if (loc.y >= reg_starty && loc.y <= reg_endy) { + // check for incry, similar as incrx + if ((loc.y + reg_starty) % specified_loc.reg_y.incr == 0) { + // both x and y are valid + return true; + } + } + } + } + + // if reach here, we don't have sb in this location + return false; +} + +static t_wire_type_sizes count_chan_wire_type_sizes(const t_chan_seg_details* channel, int nodes_per_chan) { + int num_wires = 0; + t_wire_info wire_info; + + vtr::string_view wire_type = channel[0].type_name(); + int length = channel[0].length(); + int start = 0; + + t_wire_type_sizes wire_type_sizes; + + for (int iwire = 0; iwire < nodes_per_chan; iwire++) { + vtr::string_view new_type = channel[iwire].type_name(); + int new_length = channel[iwire].length(); + int new_start = iwire; + if (new_type != wire_type) { + wire_info.set(length, num_wires, start); + wire_type_sizes[wire_type] = wire_info; + wire_type = new_type; + length = new_length; + start = new_start; + num_wires = 0; + } + num_wires++; + } + + wire_info.set(length, num_wires, start); + wire_type_sizes[wire_type] = wire_info; + + return wire_type_sizes; +} + +static int get_wire_subsegment_num(e_rr_type chan_type, + const t_chan_seg_details& wire_details, + int seg_coord) { + // We get wire subsegment number by comparing the wire's seg_coord to the seg_start of the wire. + // The offset between seg_start (or seg_end) and seg_coord is the subsegment number + // Cases: + // seg starts at bottom but does not extend all the way to the top -- look at seg_end + // seg starts > bottom and does not extend all the way to top -- look at seg_start + // seg starts > bottom but terminates all the way at the top -- look at seg_start + // seg starts at bottom and extends all the way to the top -- look at seg end + + int seg_start = wire_details.seg_start(); + int seg_end = wire_details.seg_end(); + Direction direction = wire_details.direction(); + int wire_length = get_wire_segment_length(chan_type, wire_details); + + // Determine the minimum and maximum values that the 'seg' coordinate of a wire can take + int min_seg = 1; + + int subsegment_num; + if (seg_start != min_seg) { + subsegment_num = seg_coord - seg_start; + } else { + subsegment_num = (wire_length - 1) - (seg_end - seg_coord); + } + + // If this wire is going in the decreasing direction, reverse the subsegment num. + VTR_ASSERT(seg_end >= seg_start); + if (direction == Direction::DEC) { + subsegment_num = wire_length - 1 - subsegment_num; + } + + return subsegment_num; +} + +static int get_wire_segment_length(e_rr_type chan_type, + const t_chan_seg_details& wire_details) { + const DeviceGrid& grid = g_vpr_ctx.device().grid; + + int min_seg = 1; + int max_seg = grid.width() - 2; //-2 for no perim channels + if (chan_type == e_rr_type::CHANY) { + max_seg = grid.height() - 2; //-2 for no perim channels + } + + int seg_start = wire_details.seg_start(); + int seg_end = wire_details.seg_end(); + + int wire_length; + if (seg_start == min_seg && seg_end == max_seg) { + wire_length = seg_end - seg_start + 1; + } else { + wire_length = wire_details.length(); + } + + return wire_length; +} + +// +// Non-static Function Definitions +// + +bool sb_not_here(const DeviceGrid& grid, + const std::vector& inter_cluster_rr, + const t_physical_tile_loc& loc, + e_sb_location sb_location, + const t_specified_loc& specified_loc /*=t_specified_loc()*/) { + if (!inter_cluster_rr[loc.layer_num]) { + return true; + } + + bool sb_not_here = true; + switch (sb_location) { + case e_sb_location::E_EVERYWHERE: + sb_not_here = false; + break; + + case e_sb_location::E_PERIMETER: + if (is_perimeter_sb(grid, loc)) { + sb_not_here = false; + } + break; + + case e_sb_location::E_CORNER: + if (is_corner_sb(grid, loc)) { + sb_not_here = false; + } + break; + + case e_sb_location::E_CORE: + if (is_core_sb(grid, loc)) { + sb_not_here = false; + } + break; + + case e_sb_location::E_FRINGE: + if (is_perimeter_sb(grid, loc) && !is_corner_sb(grid, loc)) { + sb_not_here = false; + } + break; + + case e_sb_location::E_XY_SPECIFIED: + if (match_sb_xy(grid, loc, specified_loc)) { + sb_not_here = false; + } + break; + + default: + VPR_FATAL_ERROR(VPR_ERROR_ARCH, "sb_not_here: unrecognized location enum: %d\n", sb_location); + break; + } + + return sb_not_here; +} + +const t_chan_details& index_into_correct_chan(const t_physical_tile_loc& sb_loc, + e_side src_side, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + t_physical_tile_loc& chan_loc, + e_rr_type& chan_type) { + chan_type = e_rr_type::CHANX; + // here we use the VPR convention that a tile 'owns' the channels directly to the right and above it + switch (src_side) { + case TOP: + // this is y-channel belonging to tile above in the same layer + chan_loc.x = sb_loc.x; + chan_loc.y = sb_loc.y + 1; + chan_loc.layer_num = sb_loc.layer_num; + chan_type = e_rr_type::CHANY; + return chan_details_y; + break; + case RIGHT: + // this is x-channel belonging to tile to the right in the same layer + chan_loc.x = sb_loc.x + 1; + chan_loc.y = sb_loc.y; + chan_loc.layer_num = sb_loc.layer_num; + chan_type = e_rr_type::CHANX; + return chan_details_x; + break; + case BOTTOM: + // this is y-channel on the right of the tile in the same layer + chan_loc.x = sb_loc.x; + chan_loc.y = sb_loc.y; + chan_loc.layer_num = sb_loc.layer_num; + chan_type = e_rr_type::CHANY; + return chan_details_y; + break; + case LEFT: + // this is x-channel on top of the tile in the same layer + chan_loc.x = sb_loc.x; + chan_loc.y = sb_loc.y; + chan_loc.layer_num = sb_loc.layer_num; + chan_type = e_rr_type::CHANX; + return chan_details_x; + break; + default: + VPR_FATAL_ERROR(VPR_ERROR_ARCH, "index_into_correct_chan: unknown side specified: %d\n", src_side); + break; + } + VTR_ASSERT(false); + return chan_details_x; // Unreachable +} + +bool chan_coords_out_of_bounds(const t_physical_tile_loc& loc, e_rr_type chan_type) { + const DeviceGrid& grid = g_vpr_ctx.device().grid; + + const int grid_width = grid.width(); + const int grid_height = grid.height(); + const int grid_layers = grid.get_num_layers(); + + // the layer that channel is located at must be legal regardless of chan_type + if (loc.layer_num < 0 || loc.layer_num >= grid_layers) { + return true; + } + + if (e_rr_type::CHANX == chan_type) { + // there is no x-channel at x=0 + if (loc.x <= 0 || loc.x >= grid_width - 1 || loc.y < 0 || loc.y >= grid_height - 1) { + return true; + } + } else if (e_rr_type::CHANY == chan_type) { + // there is no y-channel at y=0 + if (loc.x < 0 || loc.x >= grid_width - 1 || loc.y <= 0 || loc.y >= grid_height - 1) { + return true; + } + } else { + VPR_FATAL_ERROR(VPR_ERROR_ARCH, "chan_coords_out_of_bounds(): illegal channel type %d\n", chan_type); + } + + return false; +} + +std::pair count_wire_type_sizes(const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + const t_chan_width& nodes_per_chan) { + + // We assume that x & y channels have the same ratios of wire types. i.e., looking at a single + // channel is representative of all channels in the FPGA. + + // Count the number of wires in each wire type in the specified channel. Note that this is representative of + // the wire count for every channel in direction due to the assumption stated above. + // This will not hold if we + // 1) support different horizontal and vertical segment distributions + // 2) support non-uniform channel distributions. + + t_wire_type_sizes wire_type_sizes_x = count_chan_wire_type_sizes(chan_details_x[0][0].data(), nodes_per_chan.x_max); + t_wire_type_sizes wire_type_sizes_y = count_chan_wire_type_sizes(chan_details_y[0][0].data(), nodes_per_chan.y_max); + + return {wire_type_sizes_x, wire_type_sizes_y}; +} + +int get_switchpoint_of_wire(e_rr_type chan_type, + const t_chan_seg_details& wire_details, + int seg_coord, + e_side sb_side) { + // this function calculates the switchpoint of a given wire by first calculating + // the subsegment number of the specified wire. For instance, for a wire with L=4: + // + // switchpoint: 0-------1-------2-------3-------0 + // subsegment_num: 0 1 2 3 + // + // So knowing the wire's subsegment_num and which switchblock side it connects to is + // enough to calculate the switchpoint + + const DeviceGrid& grid = g_vpr_ctx.device().grid; + + // Get the minimum and maximum segment coordinate which a wire in this channel type can take */ + int min_seg = 1; + int max_seg = grid.width() - 2; // -2 for no perim channels + if (chan_type == e_rr_type::CHANY) { + max_seg = grid.height() - 2; // -2 for no perim channels + } + + // Check whether the current seg_coord/sb_side coordinate specifies a perimeter switch block side at which all wire segments terminate/start. + // in this case only segments with switchpoints = 0 can exist + bool perimeter_connection = false; + if ((seg_coord == min_seg && (sb_side == RIGHT || sb_side == TOP)) || (seg_coord == max_seg && (sb_side == LEFT || sb_side == BOTTOM))) { + perimeter_connection = true; + } + + int switchpoint; + if (perimeter_connection) { + switchpoint = 0; + } else { + int wire_length = get_wire_segment_length(chan_type, wire_details); + int subsegment_num = get_wire_subsegment_num(chan_type, wire_details, seg_coord); + + Direction direction = wire_details.direction(); + if (LEFT == sb_side || BOTTOM == sb_side) { + switchpoint = (subsegment_num + 1) % wire_length; + if (direction == Direction::DEC) { + switchpoint = subsegment_num; + } + } else { + VTR_ASSERT(RIGHT == sb_side || TOP == sb_side); + switchpoint = subsegment_num; + if (direction == Direction::DEC) { + switchpoint = (subsegment_num + 1) % wire_length; + } + } + } + + return switchpoint; +} + +int evaluate_num_conns_formula(vtr::FormulaParser& formula_parser, + vtr::t_formula_data& formula_data, + const std::string& num_conns_formula, + size_t from_wire_count, + size_t to_wire_count) { + formula_data.clear(); + + formula_data.set_var_value("from", from_wire_count); + formula_data.set_var_value("to", to_wire_count); + + return formula_parser.parse_formula(num_conns_formula, formula_data); +} diff --git a/vpr/src/route/rr_graph_generation/switchblock_scatter_gather_common_utils.h b/vpr/src/route/rr_graph_generation/switchblock_scatter_gather_common_utils.h new file mode 100644 index 00000000000..33bbbc14eac --- /dev/null +++ b/vpr/src/route/rr_graph_generation/switchblock_scatter_gather_common_utils.h @@ -0,0 +1,108 @@ + +#pragma once + +#include "device_grid.h" +#include "rr_types.h" +#include "rr_graph_type.h" +#include "vtr_expr_eval.h" + +#include + +/** Contains info about a wire segment type */ +struct t_wire_info { + int length; ///< the length of this type of wire segment in tiles + int num_wires; ///< total number of wires in a channel segment (basically W) + int start; ///< the wire index at which this type starts in the channel segment (0..W-1) + + void set(int len, int wires, int st) { + length = len; + num_wires = wires; + start = st; + } + + t_wire_info() { + this->set(0, 0, 0); + } + + t_wire_info(int len, int wires, int st) { + this->set(len, wires, st); + } +}; + +struct t_wire_switchpoint { + int wire; ///< Wire index within the channel + int switchpoint; ///< Switchpoint of the wire +}; + +/// Used to get info about a given wire type based on the name +typedef vtr::flat_map t_wire_type_sizes; + +/** + * @brief check whether a switch block exists in a specified coordinate within the device grid + * + * @param grid device grid + * @param inter_cluster_rr used to check whether inter-cluster programmable routing resources exist in the current layer + * @param loc Coordinates of the given location to be evaluated. + * @param sb switchblock information specified in the architecture file + * + * @return true if a switch block exists at the specified location, false otherwise. + */ +bool sb_not_here(const DeviceGrid& grid, + const std::vector& inter_cluster_rr, + const t_physical_tile_loc& loc, + e_sb_location sb_location, + const t_specified_loc& specified_loc = t_specified_loc()); + +/** + * @brief finds the correct channel (x or y), and the coordinates to index into it based on the + * specified tile coordinates (x,y,layer) and the switch block side. + * + * @param sb_loc Coordinates of the switch blocks + * @param src_side The side of switch block where the routing channels segment is located at. + * @param chan_details_x x-channel segment details (length, start and end points, ...) + * @param chan_details_y x-channel segment details (length, start and end points, ...) + * @param chan_loc Coordinate of the indexed routing channel segment. To be filled by this function. + * @param chan_type The type of the indexed routing channel segment. To be filled by this function. + * + * @return returns the type of channel that we are indexing into (ie, CHANX or CHANY) and channel coordinates and type + */ +const t_chan_details& index_into_correct_chan(const t_physical_tile_loc& sb_loc, + e_side src_side, + const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + t_physical_tile_loc& chan_loc, + e_rr_type& chan_type); + +/** + * @brief Check whether a specific switch block location is valid within the device grid + * @param loc Coordinates of the location to be evaluated. + * @param chan_type Routing channel type (CHANX or CHANY), required since device perimeter does not have certain channels + * + * @return True if the given location is outside the device grid, false otherwise. + */ +bool chan_coords_out_of_bounds(const t_physical_tile_loc& loc, e_rr_type chan_type); + +std::pair count_wire_type_sizes(const t_chan_details& chan_details_x, + const t_chan_details& chan_details_y, + const t_chan_width& nodes_per_chan); + +/** + * Returns the switchpoint of the wire specified by wire_details at a segment coordinate + * of seg_coord, and connection to the sb_side of the switchblock + */ +int get_switchpoint_of_wire(e_rr_type chan_type, + const t_chan_seg_details& wire_details, + int seg_coord, + e_side sb_side); + +/** + * @brief Evaluates a connection formula for scatter/gather and custom switchblock patterns. + * + * Sets variables "from" and "to" to the given wire counts and evaluates + * the formula string using the provided parser + */ +int evaluate_num_conns_formula(vtr::FormulaParser& formula_parser, + vtr::t_formula_data& formula_data, + const std::string& num_conns_formula, + size_t from_wire_count, + size_t to_wire_count); diff --git a/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_builder.cpp b/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_builder.cpp index 491bd952ae3..29f4c52f62b 100644 --- a/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_builder.cpp +++ b/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_builder.cpp @@ -80,9 +80,9 @@ void build_tileable_unidir_rr_graph(const std::vector& typ const int& wire_to_arch_ipin_switch, const float R_minW_nmos, const float R_minW_pmos, - const enum e_base_cost_type& base_cost_type, + const e_base_cost_type& base_cost_type, const std::vector& directs, - int* wire_to_rr_ipin_switch, + RRSwitchId* wire_to_rr_ipin_switch, const bool& shrink_boundary, const bool& perimeter_cb, const bool& through_channel, @@ -156,6 +156,7 @@ void build_tileable_unidir_rr_graph(const std::vector& typ t_unified_to_parallel_seg_index segment_index_map; std::vector segment_inf_x = get_parallel_segs(segment_inf, segment_index_map, e_parallel_axis::X_AXIS, true); std::vector segment_inf_y = get_parallel_segs(segment_inf, segment_index_map, e_parallel_axis::Y_AXIS, true); + std::vector segment_inf_z = get_parallel_segs(segment_inf, segment_index_map, e_parallel_axis::Z_AXIS, true); // Get vib grid const auto& vib_grid = device_ctx.vib_grid; @@ -264,7 +265,7 @@ void build_tileable_unidir_rr_graph(const std::vector& typ auto clb_to_clb_directs = alloc_and_load_clb_to_clb_directs(directs, delayless_switch); std::vector clb2clb_directs; for (size_t idirect = 0; idirect < directs.size(); ++idirect) { - /* Sanity checks on rr switch id */ + // Sanity checks on rr switch id VTR_ASSERT(true == device_ctx.rr_graph.valid_switch(RRSwitchId(clb_to_clb_directs[idirect].switch_index))); clb2clb_directs.push_back(clb_to_clb_directs[idirect]); } @@ -290,8 +291,7 @@ void build_tileable_unidir_rr_graph(const std::vector& typ // Allocate external data structures // a. cost_index // b. RC tree - rr_graph_externals(segment_inf, segment_inf_x, segment_inf_y, - *wire_to_rr_ipin_switch, base_cost_type); + rr_graph_externals(segment_inf, segment_inf_x, segment_inf_y, segment_inf_z, *wire_to_rr_ipin_switch, base_cost_type); // Sanitizer for the rr_graph, check connectivities of rr_nodes // Essential check for rr_graph, build look-up and diff --git a/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_builder.h b/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_builder.h index d8395927de1..1793b1fad18 100644 --- a/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_builder.h +++ b/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_builder.h @@ -25,9 +25,9 @@ void build_tileable_unidir_rr_graph(const std::vector& typ const int& wire_to_arch_ipin_switch, const float R_minW_nmos, const float R_minW_pmos, - const enum e_base_cost_type& base_cost_type, + const e_base_cost_type& base_cost_type, const std::vector& directs, - int* wire_to_rr_ipin_switch, + RRSwitchId* wire_to_rr_ipin_switch, const bool& shrink_boundary, const bool& perimeter_cb, const bool& through_channel, diff --git a/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_gsb.cpp b/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_gsb.cpp index 541a0b76b72..5fbcfbdfaff 100644 --- a/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_gsb.cpp +++ b/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_gsb.cpp @@ -220,11 +220,11 @@ static std::vector get_switch_block_to_track_id(const e_switch_block_typ size_t actual_from_track = from_track % num_to_tracks; switch (switch_block_type) { - case SUBSET: /* NB: Global routing uses SUBSET too */ + case e_switch_block_type::SUBSET: /* NB: Global routing uses SUBSET too */ to_tracks = get_to_track_list(Fs, actual_from_track, num_to_tracks); /* Finish, we return */ return to_tracks; - case UNIVERSAL: + case e_switch_block_type::UNIVERSAL: if ((from_side == LEFT) || (from_side == RIGHT)) { /* For the prev_side, to_track is from_track @@ -257,7 +257,7 @@ static std::vector get_switch_block_to_track_id(const e_switch_block_typ /* Finish, we return */ return to_tracks; /* End switch_block_type == UNIVERSAL case. */ - case WILTON: + case e_switch_block_type::WILTON: /* See S. Wilton Phd thesis, U of T, 1996 p. 103 for details on following. */ if (from_side == LEFT) { if (to_side == RIGHT) { /* CHANX to CHANX */ diff --git a/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_node_builder.cpp b/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_node_builder.cpp index 45a631b254a..5c1f7fca5bb 100644 --- a/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_node_builder.cpp +++ b/vpr/src/route/rr_graph_generation/tileable_rr_graph/tileable_rr_graph_node_builder.cpp @@ -478,7 +478,8 @@ static void load_one_grid_opin_nodes_basic_info(RRGraphBuilder& rr_graph_builder rr_graph_builder.set_node_pin_num(node, pin_num); rr_graph_builder.set_node_capacity(node, 1); - rr_graph_builder.set_node_layer(node, layer); + rr_graph_builder.set_node_layer_low(node, layer); + rr_graph_builder.set_node_layer_high(node, layer); // cost index is a FIXED value for OPIN rr_graph_builder.set_node_cost_index(node, RRIndexedDataId(OPIN_COST_INDEX)); @@ -531,7 +532,8 @@ static void load_one_grid_ipin_nodes_basic_info(RRGraphBuilder& rr_graph_builder rr_graph_builder.set_node_pin_num(node, pin_num); rr_graph_builder.set_node_capacity(node, 1); - rr_graph_builder.set_node_layer(node, layer); + rr_graph_builder.set_node_layer_low(node, layer); + rr_graph_builder.set_node_layer_high(node, layer); // cost index is a FIXED value for OPIN rr_graph_builder.set_node_cost_index(node, RRIndexedDataId(IPIN_COST_INDEX)); @@ -577,7 +579,8 @@ static void load_one_grid_source_nodes_basic_info(RRGraphBuilder& rr_graph_build grid_coordinate.x() + phy_tile_type->width - 1, grid_coordinate.y() + phy_tile_type->height - 1); rr_graph_builder.set_node_class_num(node, iclass); - rr_graph_builder.set_node_layer(node, (int)layer); + rr_graph_builder.set_node_layer_low(node, (short)layer); + rr_graph_builder.set_node_layer_high(node, (short)layer); // The capacity should be the number of pins in this class rr_graph_builder.set_node_capacity(node, phy_tile_type->class_inf[iclass].num_pins); @@ -623,7 +626,8 @@ static void load_one_grid_sink_nodes_basic_info(RRGraphBuilder& rr_graph_builder grid_coordinate.x() + phy_tile_type->width - 1, grid_coordinate.y() + phy_tile_type->height - 1); rr_graph_builder.set_node_class_num(node, iclass); - rr_graph_builder.set_node_layer(node, layer); + rr_graph_builder.set_node_layer_low(node, layer); + rr_graph_builder.set_node_layer_high(node, layer); rr_graph_builder.set_node_capacity(node, 1); @@ -663,7 +667,8 @@ static void load_one_grid_mux_nodes_basic_info(RRGraphBuilder& rr_graph_builder, rr_graph_builder.set_node_mux_num(node, i_mux); rr_graph_builder.set_node_capacity(node, 1); - rr_graph_builder.set_node_layer(node, layer); + rr_graph_builder.set_node_layer_low(node, layer); + rr_graph_builder.set_node_layer_high(node, layer); // cost index is a FIXED value for MUX rr_graph_builder.set_node_cost_index(node, RRIndexedDataId(MUX_COST_INDEX)); @@ -841,7 +846,8 @@ static void load_one_chan_rr_nodes_basic_info(const RRGraphView& rr_graph, rr_node_track_ids[node].push_back(itrack); rr_graph_builder.set_node_capacity(node, 1); - rr_graph_builder.set_node_layer(node, layer); + rr_graph_builder.set_node_layer_low(node, layer); + rr_graph_builder.set_node_layer_high(node, layer); // assign switch id size_t seg_id = chan_details.get_track_segment_id(itrack); diff --git a/vpr/src/route/serial_connection_router.cpp b/vpr/src/route/serial_connection_router.cpp index 85538d12301..4ad7ef06e59 100644 --- a/vpr/src/route/serial_connection_router.cpp +++ b/vpr/src/route/serial_connection_router.cpp @@ -255,8 +255,8 @@ void SerialConnectionRouter::timing_driven_expand_neighbour(const RTExplor " (to node location %d,%d,%d x %d,%d,%d outside of expanded" " net bounding box %d,%d,%d x %d,%d,%d)\n", from_node, size_t(from_edge), size_t(to_node), - this->rr_graph_->node_xlow(to_node), this->rr_graph_->node_ylow(to_node), this->rr_graph_->node_layer(to_node), - this->rr_graph_->node_xhigh(to_node), this->rr_graph_->node_yhigh(to_node), this->rr_graph_->node_layer(to_node), + this->rr_graph_->node_xlow(to_node), this->rr_graph_->node_ylow(to_node), this->rr_graph_->node_layer_low(to_node), + this->rr_graph_->node_xhigh(to_node), this->rr_graph_->node_yhigh(to_node), this->rr_graph_->node_layer_low(to_node), bounding_box.xmin, bounding_box.ymin, bounding_box.layer_min, bounding_box.xmax, bounding_box.ymax, bounding_box.layer_max); return; /* Node is outside (expanded) bounding box. */ @@ -273,7 +273,7 @@ void SerialConnectionRouter::timing_driven_expand_neighbour(const RTExplor // IPIN's of the target block should be contained within it's bounding box int to_xlow = this->rr_graph_->node_xlow(to_node); int to_ylow = this->rr_graph_->node_ylow(to_node); - int to_layer = this->rr_graph_->node_layer(to_node); + int to_layer = this->rr_graph_->node_layer_low(to_node); int to_xhigh = this->rr_graph_->node_xhigh(to_node); int to_yhigh = this->rr_graph_->node_yhigh(to_node); if (to_xlow < target_bb.xmin diff --git a/vpr/src/util/vpr_utils.cpp b/vpr/src/util/vpr_utils.cpp index 2fa284c0de6..1651c955169 100644 --- a/vpr/src/util/vpr_utils.cpp +++ b/vpr/src/util/vpr_utils.cpp @@ -62,15 +62,15 @@ std::string rr_node_arch_name(RRNodeId inode, bool is_flat) { std::string rr_node_arch_name; if (rr_graph.node_type(inode) == e_rr_type::OPIN || rr_graph.node_type(inode) == e_rr_type::IPIN) { //Pin names - auto type = device_ctx.grid.get_physical_type({rr_graph.node_xlow(rr_node), - rr_graph.node_ylow(rr_node), - rr_graph.node_layer(rr_node)}); + t_physical_tile_type_ptr type = device_ctx.grid.get_physical_type({rr_graph.node_xlow(rr_node), + rr_graph.node_ylow(rr_node), + rr_graph.node_layer_low(rr_node)}); rr_node_arch_name += block_type_pin_index_to_name(type, rr_graph.node_pin_num(rr_node), is_flat); } else if (rr_graph.node_type(inode) == e_rr_type::SOURCE || rr_graph.node_type(inode) == e_rr_type::SINK) { //Set of pins associated with SOURCE/SINK - auto type = device_ctx.grid.get_physical_type({rr_graph.node_xlow(rr_node), - rr_graph.node_ylow(rr_node), - rr_graph.node_layer(rr_node)}); + t_physical_tile_type_ptr type = device_ctx.grid.get_physical_type({rr_graph.node_xlow(rr_node), + rr_graph.node_ylow(rr_node), + rr_graph.node_layer_low(rr_node)}); auto pin_names = block_type_class_index_to_pin_names(type, rr_graph.node_class_num(rr_node), is_flat); if (pin_names.size() > 1) { rr_node_arch_name += rr_graph.node_type_string(inode); @@ -84,7 +84,7 @@ std::string rr_node_arch_name(RRNodeId inode, bool is_flat) { } else { VTR_ASSERT(rr_graph.node_type(inode) == e_rr_type::CHANX || rr_graph.node_type(inode) == e_rr_type::CHANY); //Wire segment name - auto cost_index = rr_graph.node_cost_index(inode); + RRIndexedDataId cost_index = rr_graph.node_cost_index(inode); int seg_index = device_ctx.rr_indexed_data[cost_index].seg_index; rr_node_arch_name += rr_graph.rr_segments(RRSegmentId(seg_index)).name; @@ -1633,32 +1633,32 @@ bool is_inter_cluster_node(const RRGraphView& rr_graph_view, e_rr_type node_type = rr_graph_view.node_type(node_id); if (node_type == e_rr_type::CHANX || node_type == e_rr_type::CHANY || node_type == e_rr_type::CHANZ || node_type == e_rr_type::MUX) { return true; + } + + int x_low = rr_graph_view.node_xlow(node_id); + int y_low = rr_graph_view.node_ylow(node_id); + int layer = rr_graph_view.node_layer_low(node_id); + int node_ptc = rr_graph_view.node_ptc_num(node_id); + const t_physical_tile_type_ptr physical_tile = g_vpr_ctx.device().grid.get_physical_type({x_low, y_low, layer}); + if (node_type == e_rr_type::IPIN || node_type == e_rr_type::OPIN) { + return is_pin_on_tile(physical_tile, node_ptc); } else { - int x_low = rr_graph_view.node_xlow(node_id); - int y_low = rr_graph_view.node_ylow(node_id); - int layer = rr_graph_view.node_layer(node_id); - int node_ptc = rr_graph_view.node_ptc_num(node_id); - const t_physical_tile_type_ptr physical_tile = g_vpr_ctx.device().grid.get_physical_type({x_low, y_low, layer}); - if (node_type == e_rr_type::IPIN || node_type == e_rr_type::OPIN) { - return is_pin_on_tile(physical_tile, node_ptc); - } else { - VTR_ASSERT_DEBUG(node_type == e_rr_type::SINK || node_type == e_rr_type::SOURCE); - return is_class_on_tile(physical_tile, node_ptc); - } + VTR_ASSERT_DEBUG(node_type == e_rr_type::SINK || node_type == e_rr_type::SOURCE); + return is_class_on_tile(physical_tile, node_ptc); } } int get_rr_node_max_ptc(const RRGraphView& rr_graph_view, RRNodeId node_id, bool is_flat) { - auto node_type = rr_graph_view.node_type(node_id); + e_rr_type node_type = rr_graph_view.node_type(node_id); VTR_ASSERT(node_type == e_rr_type::IPIN || node_type == e_rr_type::OPIN || node_type == e_rr_type::SINK || node_type == e_rr_type::SOURCE); const DeviceContext& device_ctx = g_vpr_ctx.device(); - auto physical_type = device_ctx.grid.get_physical_type({rr_graph_view.node_xlow(node_id), - rr_graph_view.node_ylow(node_id), - rr_graph_view.node_layer(node_id)}); + t_physical_tile_type_ptr physical_type = device_ctx.grid.get_physical_type({rr_graph_view.node_xlow(node_id), + rr_graph_view.node_ylow(node_id), + rr_graph_view.node_layer_low(node_id)}); if (node_type == e_rr_type::SINK || node_type == e_rr_type::SOURCE) { return get_tile_class_max_ptc(physical_type, is_flat); @@ -1746,7 +1746,7 @@ std::pair get_rr_node_cluster_blk_id_pb_graph_p int pin_physical_num = device_ctx.rr_graph.node_ptc_num(rr_node_id); int x = device_ctx.rr_graph.node_xlow(rr_node_id); int y = device_ctx.rr_graph.node_ylow(rr_node_id); - int layer = device_ctx.rr_graph.node_layer(rr_node_id); + int layer = device_ctx.rr_graph.node_layer_low(rr_node_id); t_physical_tile_type_ptr physical_tile = device_ctx.grid.get_physical_type({x, y, layer}); @@ -1777,19 +1777,19 @@ AtomPinId get_rr_node_atom_pin_id(RRNodeId rr_node_id) { bool node_in_same_physical_tile(RRNodeId node_first, RRNodeId node_second) { const auto& device_ctx = g_vpr_ctx.device(); const auto& rr_graph = device_ctx.rr_graph; - auto firse_rr_type = rr_graph.node_type(node_first); - auto second_rr_type = rr_graph.node_type(node_second); + e_rr_type first_rr_type = rr_graph.node_type(node_first); + e_rr_type second_rr_type = rr_graph.node_type(node_second); // If one of the given node's type is CHANX/Y nodes are definitely not in the same physical tile - if (firse_rr_type == e_rr_type::CHANX || firse_rr_type == e_rr_type::CHANY || second_rr_type == e_rr_type::CHANX || second_rr_type == e_rr_type::CHANY) { + if (first_rr_type == e_rr_type::CHANX || first_rr_type == e_rr_type::CHANY || second_rr_type == e_rr_type::CHANX || second_rr_type == e_rr_type::CHANY) { return false; } else { - VTR_ASSERT(firse_rr_type == e_rr_type::IPIN || firse_rr_type == e_rr_type::OPIN || firse_rr_type == e_rr_type::SINK || firse_rr_type == e_rr_type::SOURCE); + VTR_ASSERT(first_rr_type == e_rr_type::IPIN || first_rr_type == e_rr_type::OPIN || first_rr_type == e_rr_type::SINK || first_rr_type == e_rr_type::SOURCE); VTR_ASSERT(second_rr_type == e_rr_type::IPIN || second_rr_type == e_rr_type::OPIN || second_rr_type == e_rr_type::SINK || second_rr_type == e_rr_type::SOURCE); - int first_layer = rr_graph.node_layer(node_first); + int first_layer = rr_graph.node_layer_low(node_first); int first_x = rr_graph.node_xlow(node_first); int first_y = rr_graph.node_ylow(node_first); - int sec_layer = rr_graph.node_layer(node_second); + int sec_layer = rr_graph.node_layer_low(node_second); int sec_x = rr_graph.node_xlow(node_second); int sec_y = rr_graph.node_ylow(node_second); @@ -1986,10 +1986,11 @@ float get_min_cross_layer_delay() { const auto& rr_graph = g_vpr_ctx.device().rr_graph; float min_delay = std::numeric_limits::max(); - for (const auto& driver_node : rr_graph.nodes()) { + for (const RRNodeId driver_node : rr_graph.nodes()) { for (size_t edge_id = 0; edge_id < rr_graph.num_edges(driver_node); edge_id++) { - const auto& sink_node = rr_graph.edge_sink_node(driver_node, edge_id); - if (rr_graph.node_layer(driver_node) != rr_graph.node_layer(sink_node)) { + const RRNodeId sink_node = rr_graph.edge_sink_node(driver_node, edge_id); + + if (rr_graph.node_type(sink_node) == e_rr_type::CHANZ) { int i_switch = rr_graph.edge_switch(driver_node, edge_id); float edge_delay = rr_graph.rr_switch_inf(RRSwitchId(i_switch)).Tdel; min_delay = std::min(min_delay, edge_delay); diff --git a/vpr/src/util/vpr_utils.h b/vpr/src/util/vpr_utils.h index fe1986eea55..3c3f4e324fd 100644 --- a/vpr/src/util/vpr_utils.h +++ b/vpr/src/util/vpr_utils.h @@ -339,9 +339,8 @@ void add_pb_child_to_list(std::list& pb_list, const t_pb* parent_pb void apply_route_constraints(const UserRouteConstraints& constraint); /** - * @brief Iterate over all inter-layer switch types and return the minimum delay of it. - * useful four router lookahead to to have some estimate of the cost of crossing a layer - * @return + * @brief Iterate over all inter-layer switch types and return the minimum delay of them. + * Useful for router lookahead to have some estimate of the cost of crossing a layer. */ float get_min_cross_layer_delay(); diff --git a/vtr_flow/arch/multi_die/simple_arch/3d_k4_N4_90nm.xml b/vtr_flow/arch/multi_die/simple_arch/3d_k4_N4_90nm.xml index 0f525323384..500df33875f 100644 --- a/vtr_flow/arch/multi_die/simple_arch/3d_k4_N4_90nm.xml +++ b/vtr_flow/arch/multi_die/simple_arch/3d_k4_N4_90nm.xml @@ -96,6 +96,7 @@ + @@ -104,6 +105,9 @@ 1 1 1 + + + diff --git a/vtr_flow/arch/multi_die/stratixiv_3d/3d_SB_inter_die_stratixiv_arch.timing.xml b/vtr_flow/arch/multi_die/stratixiv_3d/3d_SB_inter_die_stratixiv_arch.timing.xml index d2dc23f5005..7a3ba51eca8 100644 --- a/vtr_flow/arch/multi_die/stratixiv_3d/3d_SB_inter_die_stratixiv_arch.timing.xml +++ b/vtr_flow/arch/multi_die/stratixiv_3d/3d_SB_inter_die_stratixiv_arch.timing.xml @@ -5072,6 +5072,8 @@ powerful. --> + + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + + + + @@ -48253,54 +48259,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -48368,4 +48326,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_stratixiv_arch.timing.xml b/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_stratixiv_arch.timing.xml index 206a64dd7eb..141e357fe06 100644 --- a/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_stratixiv_arch.timing.xml +++ b/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_stratixiv_arch.timing.xml @@ -5116,6 +5116,8 @@ --> + + @@ -5235,6 +5237,9 @@ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + + + diff --git a/vtr_flow/arch/scatter-gather/k6_frac_N10_frac_chain_mem32K_40nm_sg.xml b/vtr_flow/arch/scatter-gather/k6_frac_N10_frac_chain_mem32K_40nm_sg.xml deleted file mode 100644 index dd06c897395..00000000000 --- a/vtr_flow/arch/scatter-gather/k6_frac_N10_frac_chain_mem32K_40nm_sg.xml +++ /dev/null @@ -1,1606 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - io.outpad io.inpad io.clock - io.outpad io.inpad io.clock - io.outpad io.inpad io.clock - io.outpad io.inpad io.clock - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1 1 1 1 1 - 1 1 1 1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 235e-12 - 235e-12 - 235e-12 - 235e-12 - 235e-12 - - - 174e-12 - 174e-12 - 174e-12 - 174e-12 - 174e-12 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 195e-12 - 195e-12 - 195e-12 - 195e-12 - - - 144e-12 - 144e-12 - 144e-12 - 144e-12 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 261e-12 - 261e-12 - 261e-12 - 261e-12 - 261e-12 - 261e-12 - - - 174e-12 - 174e-12 - 174e-12 - 174e-12 - 174e-12 - 174e-12 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_scatter_gather/config/config.txt b/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_scatter_gather/config/config.txt deleted file mode 100644 index 76a3a6293fe..00000000000 --- a/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_scatter_gather/config/config.txt +++ /dev/null @@ -1,27 +0,0 @@ -############################################## -# Configuration file for running experiments -############################################## - -# Path to directory of circuits to use -circuits_dir=benchmarks/verilog - -# Path to directory of architectures to use -archs_dir=arch/scatter-gather - -# Add circuits to list to sweep -circuit_list_add=ch_intrinsics.v - -# Add architectures to list to sweep -arch_list_add=k6_frac_N10_frac_chain_mem32K_40nm_sg.xml - -# Parse info and how to parse -parse_file=vpr_standard.txt - -# How to parse QoR info -qor_parse_file=qor_standard.txt - -# Pass requirements -pass_requirements_file=pass_requirements.txt - -# Script parameters -script_params_common = -track_memory_usage diff --git a/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_scatter_gather/config/golden_results.txt b/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_scatter_gather/config/golden_results.txt deleted file mode 100644 index ecae57d76d6..00000000000 --- a/vtr_flow/tasks/regression_tests/vtr_reg_strong/strong_scatter_gather/config/golden_results.txt +++ /dev/null @@ -1,2 +0,0 @@ -arch circuit script_params vtr_flow_elapsed_time vtr_max_mem_stage vtr_max_mem error odin_synth_time max_odin_mem parmys_synth_time max_parmys_mem abc_depth abc_synth_time abc_cec_time abc_sec_time max_abc_mem ace_time max_ace_mem num_clb num_io num_memories num_mult vpr_status vpr_revision vpr_build_info vpr_compiler vpr_compiled hostname rundir max_vpr_mem num_primary_inputs num_primary_outputs num_pre_packed_nets num_pre_packed_blocks num_netlist_clocks num_post_packed_nets num_post_packed_blocks device_width device_height device_grid_tiles device_limiting_resources device_name pack_mem pack_time initial_placed_wirelength_est placed_wirelength_est total_swap accepted_swap rejected_swap aborted_swap place_mem place_time place_quench_time initial_placed_CPD_est placed_CPD_est placed_setup_TNS_est placed_setup_WNS_est placed_geomean_nonvirtual_intradomain_critical_path_delay_est place_delay_matrix_lookup_time place_quench_timing_analysis_time place_quench_sta_time place_total_timing_analysis_time place_total_sta_time ap_mem ap_time ap_full_legalizer_mem ap_full_legalizer_time min_chan_width routed_wirelength min_chan_width_route_success_iteration logic_block_area_total logic_block_area_used min_chan_width_routing_area_total min_chan_width_routing_area_per_tile min_chan_width_route_time min_chan_width_total_timing_analysis_time min_chan_width_total_sta_time crit_path_num_rr_graph_nodes crit_path_num_rr_graph_edges crit_path_collapsed_nodes crit_path_routed_wirelength crit_path_route_success_iteration crit_path_total_nets_routed crit_path_total_connections_routed crit_path_total_heap_pushes crit_path_total_heap_pops critical_path_delay geomean_nonvirtual_intradomain_critical_path_delay setup_TNS setup_WNS hold_TNS hold_WNS crit_path_routing_area_total crit_path_routing_area_per_tile router_lookahead_computation_time crit_path_route_time crit_path_create_rr_graph_time crit_path_create_intra_cluster_rr_graph_time crit_path_tile_lookahead_computation_time crit_path_router_lookahead_computation_time crit_path_total_timing_analysis_time crit_path_total_sta_time -k6_frac_N10_frac_chain_mem32K_40nm_sg.xml ch_intrinsics.v common 2.49 vpr 71.47 MiB -1 -1 0.16 30900 3 0.07 -1 -1 37084 -1 -1 68 99 1 0 success v8.0.0-13673-g028e6044f-dirty release VTR_ASSERT_LEVEL=2 GNU 15.1.1 on Linux-6.14.9-300.fc42.x86_64 x86_64 2025-08-25T13:13:32 betzgrp-pcamir.eecg /home/amirpoolad/Dev/vtr-verilog-to-routing 73184 99 130 344 474 1 227 298 12 12 144 clb auto 32.5 MiB 0.15 1668.56 665 69948 18708 40810 10430 71.5 MiB 0.19 0.00 2.40104 1.86413 -122.75 -1.86413 1.86413 0.12 0.000537934 0.000489526 0.0618774 0.0565413 -1 -1 -1 -1 44 1308 13 5.66058e+06 4.21279e+06 360780. 2505.42 0.92 0.280685 0.252587 13374 71755 -1 1113 9 385 601 24354 7746 1.97022 1.97022 -144.54 -1.97022 0 0 470760. 3269.17 0.01 0.03 0.05 -1 -1 0.01 0.0184111 0.0172572 diff --git a/vtr_flow/tasks/regression_tests/vtr_reg_strong/task_list.txt b/vtr_flow/tasks/regression_tests/vtr_reg_strong/task_list.txt index 9c25c849c96..f94619b0bcd 100644 --- a/vtr_flow/tasks/regression_tests/vtr_reg_strong/task_list.txt +++ b/vtr_flow/tasks/regression_tests/vtr_reg_strong/task_list.txt @@ -119,4 +119,3 @@ regression_tests/vtr_reg_strong/strong_3d/3d_cb regression_tests/vtr_reg_strong/strong_3d/3d_sb regression_tests/vtr_reg_strong/strong_xilinx_simple regression_tests/vtr_reg_strong/strong_xilinx_flagship -regression_tests/vtr_reg_strong/strong_scatter_gather