From 402de31ae7e3cae6d3ce18f8ee8938ba7925035a Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Fri, 5 Jul 2024 15:29:13 -0400 Subject: [PATCH 01/39] update generate_noc_mesh() to support 3d mesh --- libs/libarchfpga/src/physical_types.h | 6 +- .../src/read_xml_arch_file_noc_tag.cpp | 132 +++++++++++------- vpr/src/base/vpr_context.h | 7 +- vpr/src/pack/attraction_groups.cpp | 2 +- 4 files changed, 90 insertions(+), 57 deletions(-) diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index 422fb107535..edd66aaf162 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -1958,10 +1958,12 @@ struct t_router { /** A value representing the approximate horizontal position on the FPGA device where the router * tile is located*/ - double device_x_position = -1; + float device_x_position = -1; /** A value representing the approximate vertical position on the FPGA device where the router * tile is located*/ - double device_y_position = -1; + float device_y_position = -1; + /** A value representing the exact layer in the FPGA device where the router tile is located.*/ + int device_layer_position = -1; /** A list of router ids that are connected to the current router*/ std::vector connection_list; diff --git a/libs/libarchfpga/src/read_xml_arch_file_noc_tag.cpp b/libs/libarchfpga/src/read_xml_arch_file_noc_tag.cpp index 84fbb1226d0..1dc995f3f31 100644 --- a/libs/libarchfpga/src/read_xml_arch_file_noc_tag.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file_noc_tag.cpp @@ -68,8 +68,9 @@ static void process_mesh_topology(pugi::xml_node mesh_topology_tag, static void generate_noc_mesh(pugi::xml_node mesh_topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, - double mesh_region_start_x, double mesh_region_end_x, - double mesh_region_start_y, double mesh_region_end_y, + float mesh_region_start_x, float mesh_region_end_x, + float mesh_region_start_y, float mesh_region_end_y, + int mesh_region_start_layer, int mesh_region_end_layer, int mesh_size); /** @@ -233,11 +234,13 @@ static void process_mesh_topology(pugi::xml_node mesh_topology_tag, pugiutil::expect_only_attributes(mesh_topology_tag, expected_router_attributes, loc_data); // go through the attributes and store their values - double mesh_region_start_x = pugiutil::get_attribute(mesh_topology_tag, "startx", loc_data, pugiutil::REQUIRED).as_double(ATTRIBUTE_CONVERSION_FAILURE); - double mesh_region_end_x = pugiutil::get_attribute(mesh_topology_tag, "endx", loc_data, pugiutil::REQUIRED).as_double(ATTRIBUTE_CONVERSION_FAILURE); - double mesh_region_start_y = pugiutil::get_attribute(mesh_topology_tag, "starty", loc_data, pugiutil::REQUIRED).as_double(ATTRIBUTE_CONVERSION_FAILURE); - double mesh_region_end_y = pugiutil::get_attribute(mesh_topology_tag, "endy", loc_data, pugiutil::REQUIRED).as_double(ATTRIBUTE_CONVERSION_FAILURE); + float mesh_region_start_x = pugiutil::get_attribute(mesh_topology_tag, "startx", loc_data, pugiutil::REQUIRED).as_float(ATTRIBUTE_CONVERSION_FAILURE); + float mesh_region_end_x = pugiutil::get_attribute(mesh_topology_tag, "endx", loc_data, pugiutil::REQUIRED).as_float(ATTRIBUTE_CONVERSION_FAILURE); + float mesh_region_start_y = pugiutil::get_attribute(mesh_topology_tag, "starty", loc_data, pugiutil::REQUIRED).as_float(ATTRIBUTE_CONVERSION_FAILURE); + float mesh_region_end_y = pugiutil::get_attribute(mesh_topology_tag, "endy", loc_data, pugiutil::REQUIRED).as_float(ATTRIBUTE_CONVERSION_FAILURE); + int mesh_region_start_layer = pugiutil::get_attribute(mesh_topology_tag, "startlayer", loc_data, pugiutil::OPTIONAL).as_int(ATTRIBUTE_CONVERSION_FAILURE); + int mesh_region_end_layer = pugiutil::get_attribute(mesh_topology_tag, "endlayer", loc_data, pugiutil::OPTIONAL).as_int(ATTRIBUTE_CONVERSION_FAILURE); int mesh_size = pugiutil::get_attribute(mesh_topology_tag, "size", loc_data, pugiutil::REQUIRED).as_int(ATTRIBUTE_CONVERSION_FAILURE); // verify that the attributes provided were legal @@ -246,16 +249,29 @@ static void process_mesh_topology(pugi::xml_node mesh_topology_tag, "The parameters for the mesh topology have to be positive values."); } + if (mesh_region_start_x == ATTRIBUTE_CONVERSION_FAILURE || mesh_region_end_layer == ATTRIBUTE_CONVERSION_FAILURE) { + VTR_LOGF_WARN(loc_data.filename_c_str(), loc_data.line(mesh_topology_tag), + "Optional 'startlayer' and 'endlayer' attributes were not set for the tag. " + "The default value of zero is used for both of them.\n"); + mesh_region_start_layer = 0; + mesh_region_end_layer = 0; + } + // now create the mesh topology for the noc // create routers, make connections and determine positions - generate_noc_mesh(mesh_topology_tag, loc_data, noc_ref, mesh_region_start_x, mesh_region_end_x, mesh_region_start_y, mesh_region_end_y, mesh_size); + generate_noc_mesh(mesh_topology_tag, loc_data, noc_ref, + mesh_region_start_x, mesh_region_end_x, + mesh_region_start_y, mesh_region_end_y, + mesh_region_start_layer, mesh_region_end_layer, + mesh_size); } static void generate_noc_mesh(pugi::xml_node mesh_topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, - double mesh_region_start_x, double mesh_region_end_x, - double mesh_region_start_y, double mesh_region_end_y, + float mesh_region_start_x, float mesh_region_end_x, + float mesh_region_start_y, float mesh_region_end_y, + int mesh_region_start_layer, int mesh_region_end_layer, int mesh_size) { // check that the mesh size of the router is not 0 if (mesh_size == 0) { @@ -285,62 +301,74 @@ static void generate_noc_mesh(pugi::xml_node mesh_topology_tag, * * THe reasoning for this is to reduce the number of calculated router positions. */ - double vertical_router_separation = (mesh_region_end_y - mesh_region_start_y) / (mesh_size - 1); - double horizontal_router_separation = (mesh_region_end_x - mesh_region_start_x) / (mesh_size - 1); - - t_router temp_router; + float vertical_router_separation = (mesh_region_end_y - mesh_region_start_y) / (mesh_size - 1); + float horizontal_router_separation = (mesh_region_end_x - mesh_region_start_x) / (mesh_size - 1); // improper region check - if ((vertical_router_separation <= 0) || (horizontal_router_separation <= 0)) { + if (vertical_router_separation <= 0 || horizontal_router_separation <= 0 || + mesh_region_end_layer < mesh_region_start_layer) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(mesh_topology_tag), "The NoC region is invalid."); } // create routers and their connections // start with router id 0 (bottom left of the chip) to the maximum router id (top right of the chip) - for (int j = 0; j < mesh_size; j++) { - for (int i = 0; i < mesh_size; i++) { - // assign router id - temp_router.id = (mesh_size * j) + i; - - // calculate router position - /* The first and last router of each column or row will be located on the mesh region boundary, - * the remaining routers will be placed within the region and seperated from other routers - * using the distance calculated previously. - */ - temp_router.device_x_position = (i * horizontal_router_separation) + mesh_region_start_x; - temp_router.device_y_position = (j * vertical_router_separation) + mesh_region_start_y; - - // assign connections - // check if there is a router to the left - if ((i - 1) >= 0) { - // add the left router as a connection - temp_router.connection_list.push_back((mesh_size * j) + i - 1); - } + for (int l = mesh_region_start_layer; l <= mesh_region_end_layer; l++) { + for (int j = 0; j < mesh_size; j++) { + for (int i = 0; i < mesh_size; i++) { + t_router temp_router; + + // assign router id + temp_router.id = (mesh_size * mesh_size * (l - mesh_region_start_layer)) + (mesh_size * j) + i; + + // calculate router position + /* The first and last router of each column or row will be located on the mesh region boundary, + * the remaining routers will be placed within the region and seperated from other routers + * using the distance calculated previously. + */ + temp_router.device_x_position = (i * horizontal_router_separation) + mesh_region_start_x; + temp_router.device_y_position = (j * vertical_router_separation) + mesh_region_start_y; + temp_router.device_layer_position = l; + + // assign connections + + // check if there is a router to the left + if (i >= 1) { + // add the left router as a connection + temp_router.connection_list.push_back(temp_router.id - 1); + } - // check if there is a router to the top - if ((j + 1) <= (mesh_size - 1)) { - // add the top router as a connection - temp_router.connection_list.push_back((mesh_size * (j + 1)) + i); - } + // check if there is a router to the top + if (j <= mesh_size - 2) { + // add the top router as a connection + temp_router.connection_list.push_back(temp_router.id + mesh_size); + } - // check if there is a router to the right - if ((i + 1) <= (mesh_size - 1)) { - // add the router located to the right - temp_router.connection_list.push_back((mesh_size * j) + i + 1); - } + // check if there is a router to the right + if (i <= mesh_size - 2) { + // add the router located to the right + temp_router.connection_list.push_back(temp_router.id + 1); + } - // check of there is a router below - if ((j - 1) >= (0)) { - // add the bottom router as a connection - temp_router.connection_list.push_back((mesh_size * (j - 1)) + i); - } + // check if there is a router below + if (j >= 1) { + // add the bottom router as a connection + temp_router.connection_list.push_back(temp_router.id - mesh_size); + } - // add the router to the list - noc_ref->router_list.push_back(temp_router); + // check if there is a router on the layer above + if (l < mesh_region_end_layer) { + temp_router.connection_list.push_back(temp_router.id + (mesh_size * mesh_size)); + } - // clear the current router information for the next router - temp_router.connection_list.clear(); + // check if there is a router on the layer below + if (l > mesh_region_start_layer) { + temp_router.connection_list.push_back(temp_router.id - (mesh_size * mesh_size)); + } + + // add the router to the list + noc_ref->router_list.push_back(temp_router); + } } } } diff --git a/vpr/src/base/vpr_context.h b/vpr/src/base/vpr_context.h index bf79e52ed05..f001f66a83d 100644 --- a/vpr/src/base/vpr_context.h +++ b/vpr/src/base/vpr_context.h @@ -157,7 +157,9 @@ struct DeviceContext : public Context { /** * @brief The device grid * - * This represents the physical layout of the device. To get the physical tile at each location (layer_num, x, y) the helper functions in this data structure should be used. + * This represents the physical layout of the device. + * To get the physical tile at each location (layer_num, x, y) the helper functions + * in this data structure should be used. */ DeviceGrid grid; /* @@ -563,7 +565,8 @@ struct NocContext : public Context { /** * @brief Stores all the communication happening between routers in the NoC * - * Contains all of the traffic flows that describe which pairs of logical routers are communicating and also some metrics and constraints on the data transfer between the two routers. + * Contains all of the traffic flows that describe which pairs of logical routers are + * communicating and also some metrics and constraints on the data transfer between the two routers. * * * This is created from a user supplied .flows file. diff --git a/vpr/src/pack/attraction_groups.cpp b/vpr/src/pack/attraction_groups.cpp index b8f0351d6a7..5ce9e0f6441 100644 --- a/vpr/src/pack/attraction_groups.cpp +++ b/vpr/src/pack/attraction_groups.cpp @@ -58,7 +58,7 @@ void AttractionInfo::create_att_groups_for_overfull_regions() { */ /* - * Create an attraction group for each parition with an overfull region. + * Create an attraction group for each partition with an overfull region. */ for (int ipart = 0; ipart < num_parts; ipart++) { From 82a8dce71b81e695f8bdc813f825e6fae824ea90 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Fri, 5 Jul 2024 16:04:42 -0400 Subject: [PATCH 02/39] add pairs() method to vtr::vector --- libs/libvtrutil/src/vtr_vector.h | 51 +++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/libs/libvtrutil/src/vtr_vector.h b/libs/libvtrutil/src/vtr_vector.h index 27102a38eef..19ec5c237d2 100644 --- a/libs/libvtrutil/src/vtr_vector.h +++ b/libs/libvtrutil/src/vtr_vector.h @@ -56,6 +56,9 @@ class vector : private std::vector { class key_iterator; typedef vtr::Range key_range; + class pair_iterator; + typedef vtr::Range pair_range; + public: //Pass through std::vector's types using typename storage::allocator_type; @@ -153,6 +156,11 @@ class vector : private std::vector { return vtr::make_range(key_begin(), key_end()); } + /// @brief Returns a range containing the key-value pairs + pair_range pairs() const { + return vtr::make_range(pair_begin(), pair_end()); + } + public: /** * @brief Iterator class which is convertable to the key_type @@ -188,7 +196,7 @@ class vector : private std::vector { value_ = value_type(size_t(value_) - 1); return *this; } - ///@brief dereference oeprator + ///@brief dereference operator reference operator*() { return value_; } ///@brief -> operator pointer operator->() { return &value_; } @@ -202,9 +210,50 @@ class vector : private std::vector { value_type value_; }; + class pair_iterator { + public: + using iterator_category = std::bidirectional_iterator_tag; + using difference_type = std::ptrdiff_t; + using value_type = std::pair; + using pointer = value_type*; + using reference = value_type&; + + /// @brief constructor + pair_iterator(vector& vec, key_type init) + : vec_(vec), value_(init, vec[init]) {} + + /// @brief ++ operator + pair_iterator& operator++() { + value_ = std::make_pair(key_type(size_t(value_.first) + 1), vec_[key_type(size_t(value_.first) + 1)]); + return *this; + } + /// @brief -- operator + pair_iterator& operator--() { + value_ = std::make_pair(key_type(size_t(value_.first) - 1), vec_[key_type(size_t(value_.first) - 1)]); + return *this; + } + /// @brief dereference operator + reference operator*() { return value_; } + /// @brief -> operator + pointer operator->() { return &value_; } + + /// @brief == operator + friend bool operator==(const pair_iterator& lhs, const pair_iterator& rhs) { return lhs.value_.first == rhs.value_.first; } + /// @brief != operator + friend bool operator!=(const pair_iterator& lhs, const pair_iterator& rhs) { return !(lhs == rhs); } + + private: + vector& vec_; + value_type value_; + }; + private: key_iterator key_begin() const { return key_iterator(key_type(0)); } key_iterator key_end() const { return key_iterator(key_type(size())); } + + pair_iterator pair_begin() const { return pair_iterator(*const_cast*>(this), key_type(0)); } + pair_iterator pair_end() const { return pair_iterator(*const_cast*>(this), key_type(size())); } +}; }; } // namespace vtr From ee02db080b505e212ea434c781f50b410c3d6623 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Fri, 5 Jul 2024 16:23:56 -0400 Subject: [PATCH 03/39] check that logical and physical routers are on the same layer in create_noc_routers() --- vpr/src/base/setup_noc.cpp | 64 ++++++++++++++++---------------------- vpr/src/base/setup_noc.h | 14 ++++----- 2 files changed, 33 insertions(+), 45 deletions(-) diff --git a/vpr/src/base/setup_noc.cpp b/vpr/src/base/setup_noc.cpp index b2eabc33842..9a7e1ff2630 100644 --- a/vpr/src/base/setup_noc.cpp +++ b/vpr/src/base/setup_noc.cpp @@ -64,13 +64,13 @@ void setup_noc(const t_arch& arch) { } } -std::vector identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, - std::string_view noc_router_tile_name) { +vtr::vector identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, + std::string_view noc_router_tile_name) { const int num_layers = device_grid.get_num_layers(); const int grid_width = (int)device_grid.width(); const int grid_height = (int)device_grid.height(); - std::vector noc_router_tiles; + vtr::vector noc_router_tiles; // go through the device for (int layer_num = 0; layer_num < num_layers; layer_num++) { @@ -95,8 +95,8 @@ std::vector identify_and_store_noc_router_tile_posit */ if (noc_router_tile_name == curr_tile_name && !curr_tile_width_offset && !curr_tile_height_offset) { // calculating the centroid position of the current tile - double curr_tile_centroid_x = (curr_tile_width - 1) / (double)2 + i; - double curr_tile_centroid_y = (curr_tile_height - 1) / (double)2 + j; + float curr_tile_centroid_x = (curr_tile_width - 1) / 2.0f + i; + float curr_tile_centroid_y = (curr_tile_height - 1) / 2.0f + j; noc_router_tiles.emplace_back(i, j, layer_num, curr_tile_centroid_x, curr_tile_centroid_y); } @@ -109,7 +109,7 @@ std::vector identify_and_store_noc_router_tile_posit void generate_noc(const t_arch& arch, NocContext& noc_ctx, - const std::vector& noc_router_tiles) { + const vtr::vector& noc_router_tiles) { // references to the noc NocStorage* noc_model = &noc_ctx.noc_model; // reference to the noc description @@ -130,19 +130,7 @@ void generate_noc(const t_arch& arch, void create_noc_routers(const t_noc_inf& noc_info, NocStorage* noc_model, - const std::vector& noc_router_tiles) { - // keep track of the shortest distance between a user described router (noc description in the arch file) and a physical router on the FPGA - double shortest_distance; - // stores the index of a physical router within the noc_router_tiles that is closest to a given user described router - int closest_physical_router; - - // keep track of the index of each physical router (this helps uniquely identify them) - int curr_physical_router_index = 0; - - // keep track of the ids of the routers that create the case where multiple routers have the same distance to a physical router tile - int error_case_physical_router_index_1; - int error_case_physical_router_index_2; - + const vtr::vector& noc_router_tiles) { // keep track of the router assignments (store the user router id that was assigned to each physical router tile) // this is used in error checking, after determining the closest physical router for a user described router in the arch file, // the datastructure below can be used to check if that physical router was already assigned previously @@ -153,31 +141,27 @@ void create_noc_routers(const t_noc_inf& noc_info, // go through each user described router in the arch file and assign it to a physical router on the FPGA for (const auto& logical_router : noc_info.router_list) { - // assign the shortest distance to a large value (this is done so that the first distance calculated, and we can replace this) - shortest_distance = std::numeric_limits::max(); - // get position of the current logical router - double curr_logical_router_position_x = logical_router.device_x_position; - double curr_logical_router_position_y = logical_router.device_y_position; - - closest_physical_router = 0; + // keep track of the shortest distance between a user described router (noc description in the arch file) and a physical router on the FPGA + float shortest_distance = std::numeric_limits::max(); - // the starting index of the physical router list - curr_physical_router_index = 0; + // stores the index of a physical router within the noc_router_tiles that is closest to a given user described router + int closest_physical_router = 0; // initialize the router ids that track the error case where two physical router tiles have the same distance to a user described router // we initialize it to an invalid index, so that it reflects the situation where we never hit this case - error_case_physical_router_index_1 = INVALID_PHYSICAL_ROUTER_INDEX; - error_case_physical_router_index_2 = INVALID_PHYSICAL_ROUTER_INDEX; + int error_case_physical_router_index_1 = INVALID_PHYSICAL_ROUTER_INDEX; + int error_case_physical_router_index_2 = INVALID_PHYSICAL_ROUTER_INDEX; // determine the physical router tile that is closest to the current user described router in the arch file - for (const auto& physical_router : noc_router_tiles) { - // get the position of the current physical router tile on the FPGA device - double curr_physical_router_pos_x = physical_router.tile_centroid_x; - double curr_physical_router_pos_y = physical_router.tile_centroid_y; + for (const auto& [curr_physical_router_index, physical_router] : noc_router_tiles.pairs()) { + // make sure that we only compute the distance between logical and physical routers on the same layer + if (physical_router.layer_position != logical_router.device_layer_position) { + continue; + } // use Euclidean distance to calculate the length between the current user described router and the physical router - double curr_calculated_distance = std::hypot(curr_physical_router_pos_x - curr_logical_router_position_x, - curr_physical_router_pos_y - curr_logical_router_position_y); + float curr_calculated_distance = std::hypot(physical_router.tile_centroid_x - logical_router.device_x_position, + physical_router.tile_centroid_y - logical_router.device_y_position); // if the current distance is the same as the previous shortest distance if (vtr::isclose(curr_calculated_distance, shortest_distance)) { @@ -191,9 +175,13 @@ void create_noc_routers(const t_noc_inf& noc_info, shortest_distance = curr_calculated_distance; closest_physical_router = curr_physical_router_index; } + } - // update the index for the next physical router - curr_physical_router_index++; + // make sure that there was at least one physical router on the same layer as the logical router + if (shortest_distance == std::numeric_limits::max()) { + VPR_FATAL_ERROR(VPR_ERROR_OTHER, + "Router with ID:'%d' is located on layer %d, but no physical router was found on this layer.", + logical_router.id, logical_router.device_layer_position); } // check the case where two physical router tiles have the same distance to the given logical router diff --git a/vpr/src/base/setup_noc.h b/vpr/src/base/setup_noc.h index 56434095fd7..98c8834d1c6 100644 --- a/vpr/src/base/setup_noc.h +++ b/vpr/src/base/setup_noc.h @@ -39,7 +39,7 @@ // a data structure to store the position information of a noc router in the FPGA device struct t_noc_router_tile_position { - t_noc_router_tile_position(int x, int y, int layer_num, double centroid_x, double centroid_y) + t_noc_router_tile_position(int x, int y, int layer_num, float centroid_x, float centroid_y) : grid_width_position(x) , grid_height_position(y) , layer_position(layer_num) @@ -50,8 +50,8 @@ struct t_noc_router_tile_position { int grid_height_position; int layer_position; - double tile_centroid_x; - double tile_centroid_y; + float tile_centroid_x; + float tile_centroid_y; }; /** @@ -79,8 +79,8 @@ void setup_noc(const t_arch& arch); * * @return The grid position information for all NoC router tiles in the FPGA. */ -std::vector identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, - std::string_view noc_router_tile_name); +vtr::vector identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, + std::string_view noc_router_tile_name); /** * @brief Creates NoC routers and adds them to the NoC model based @@ -97,7 +97,7 @@ std::vector identify_and_store_noc_router_tile_posit */ void generate_noc(const t_arch& arch, NocContext& noc_ctx, - const std::vector& list_of_noc_router_tiles); + const vtr::vector& list_of_noc_router_tiles); /** * @brief Go through the routers described by the user @@ -116,7 +116,7 @@ void generate_noc(const t_arch& arch, */ void create_noc_routers(const t_noc_inf& noc_info, NocStorage* noc_model, - const std::vector& list_of_noc_router_tiles); + const vtr::vector& list_of_noc_router_tiles); /** * @brief Goes through the topology information as described in the FPGA From c32a0cb7ba5213184291306c131f70c75abf9117 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Fri, 5 Jul 2024 16:26:51 -0400 Subject: [PATCH 04/39] fix compilation errors in test_setup_noc.cpp --- libs/libvtrutil/src/vtr_vector.h | 1 - vpr/test/test_setup_noc.cpp | 52 ++++++++++++++++---------------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/libs/libvtrutil/src/vtr_vector.h b/libs/libvtrutil/src/vtr_vector.h index 19ec5c237d2..cb6f68e338e 100644 --- a/libs/libvtrutil/src/vtr_vector.h +++ b/libs/libvtrutil/src/vtr_vector.h @@ -254,7 +254,6 @@ class vector : private std::vector { pair_iterator pair_begin() const { return pair_iterator(*const_cast*>(this), key_type(0)); } pair_iterator pair_end() const { return pair_iterator(*const_cast*>(this), key_type(size())); } }; -}; } // namespace vtr #endif diff --git a/vpr/test/test_setup_noc.cpp b/vpr/test/test_setup_noc.cpp index 4c6f0a3942a..d5143e39940 100644 --- a/vpr/test/test_setup_noc.cpp +++ b/vpr/test/test_setup_noc.cpp @@ -39,7 +39,7 @@ TEST_CASE("test_identify_and_store_noc_router_tile_positions", "[vpr_setup_noc]" router_tile.width = 2; // results from the test function - std::vector list_of_routers; + vtr::vector list_of_routers; // make sure the test result is not corrupted REQUIRE(list_of_routers.empty()); @@ -140,26 +140,26 @@ TEST_CASE("test_identify_and_store_noc_router_tile_positions", "[vpr_setup_noc]" // check the bottom left router REQUIRE(list_of_routers[0].grid_width_position == 0); REQUIRE(list_of_routers[0].grid_height_position == 0); - REQUIRE(vtr::isclose(list_of_routers[0].tile_centroid_x, 0.5)); - REQUIRE(vtr::isclose(list_of_routers[0].tile_centroid_y, 0.5)); + REQUIRE(vtr::isclose(list_of_routers[0].tile_centroid_x, 0.5f)); + REQUIRE(vtr::isclose(list_of_routers[0].tile_centroid_y, 0.5f)); // check the bottom right router REQUIRE(list_of_routers[1].grid_width_position == 0); REQUIRE(list_of_routers[1].grid_height_position == 8); - REQUIRE(vtr::isclose(list_of_routers[1].tile_centroid_x, 0.5)); - REQUIRE(vtr::isclose(list_of_routers[1].tile_centroid_y, 8.5)); + REQUIRE(vtr::isclose(list_of_routers[1].tile_centroid_x, 0.5f)); + REQUIRE(vtr::isclose(list_of_routers[1].tile_centroid_y, 8.5f)); // check the top left router REQUIRE(list_of_routers[2].grid_width_position == 8); REQUIRE(list_of_routers[2].grid_height_position == 0); - REQUIRE(vtr::isclose(list_of_routers[2].tile_centroid_x, 8.5)); - REQUIRE(vtr::isclose(list_of_routers[2].tile_centroid_y, 0.5)); + REQUIRE(vtr::isclose(list_of_routers[2].tile_centroid_x, 8.5f)); + REQUIRE(vtr::isclose(list_of_routers[2].tile_centroid_y, 0.5f)); // check the top right router REQUIRE(list_of_routers[3].grid_width_position == 8); REQUIRE(list_of_routers[3].grid_height_position == 8); - REQUIRE(vtr::isclose(list_of_routers[3].tile_centroid_x, 8.5)); - REQUIRE(vtr::isclose(list_of_routers[3].tile_centroid_y, 8.5)); + REQUIRE(vtr::isclose(list_of_routers[3].tile_centroid_x, 8.5f)); + REQUIRE(vtr::isclose(list_of_routers[3].tile_centroid_y, 8.5f)); } SECTION("All routers are horizontally connected to another router") { // in this test, the routers will be on the 4 corners of the FPGA @@ -257,26 +257,26 @@ TEST_CASE("test_identify_and_store_noc_router_tile_positions", "[vpr_setup_noc]" // check the bottom left router REQUIRE(list_of_routers[0].grid_width_position == 0); REQUIRE(list_of_routers[0].grid_height_position == 5); - REQUIRE(vtr::isclose(list_of_routers[0].tile_centroid_x, 0.5)); - REQUIRE(vtr::isclose(list_of_routers[0].tile_centroid_y, 5.5)); + REQUIRE(vtr::isclose(list_of_routers[0].tile_centroid_x, 0.5f)); + REQUIRE(vtr::isclose(list_of_routers[0].tile_centroid_y, 5.5f)); // check the bottom right router REQUIRE(list_of_routers[1].grid_width_position == 2); REQUIRE(list_of_routers[1].grid_height_position == 5); - REQUIRE(vtr::isclose(list_of_routers[1].tile_centroid_x, 2.5)); - REQUIRE(vtr::isclose(list_of_routers[1].tile_centroid_y, 5.5)); + REQUIRE(vtr::isclose(list_of_routers[1].tile_centroid_x, 2.5f)); + REQUIRE(vtr::isclose(list_of_routers[1].tile_centroid_y, 5.5f)); // check the top left router REQUIRE(list_of_routers[2].grid_width_position == 3); REQUIRE(list_of_routers[2].grid_height_position == 0); - REQUIRE(vtr::isclose(list_of_routers[2].tile_centroid_x, 3.5)); - REQUIRE(vtr::isclose(list_of_routers[2].tile_centroid_y, 0.5)); + REQUIRE(vtr::isclose(list_of_routers[2].tile_centroid_x, 3.5f)); + REQUIRE(vtr::isclose(list_of_routers[2].tile_centroid_y, 0.5f)); // check the top right router REQUIRE(list_of_routers[3].grid_width_position == 5); REQUIRE(list_of_routers[3].grid_height_position == 0); - REQUIRE(vtr::isclose(list_of_routers[3].tile_centroid_x, 5.5)); - REQUIRE(vtr::isclose(list_of_routers[3].tile_centroid_y, 0.5)); + REQUIRE(vtr::isclose(list_of_routers[3].tile_centroid_x, 5.5f)); + REQUIRE(vtr::isclose(list_of_routers[3].tile_centroid_y, 0.5f)); } SECTION("All routers are vertically connected to another router") { // in this test, the routers will be on the 4 corners of the FPGA @@ -374,31 +374,31 @@ TEST_CASE("test_identify_and_store_noc_router_tile_positions", "[vpr_setup_noc]" // check the bottom left router REQUIRE(list_of_routers[0].grid_width_position == 0); REQUIRE(list_of_routers[0].grid_height_position == 2); - REQUIRE(vtr::isclose(list_of_routers[0].tile_centroid_x, 0.5)); - REQUIRE(vtr::isclose(list_of_routers[0].tile_centroid_y, 2.5)); + REQUIRE(vtr::isclose(list_of_routers[0].tile_centroid_x, 0.5f)); + REQUIRE(vtr::isclose(list_of_routers[0].tile_centroid_y, 2.5f)); // check the bottom right router REQUIRE(list_of_routers[1].grid_width_position == 0); REQUIRE(list_of_routers[1].grid_height_position == 4); - REQUIRE(vtr::isclose(list_of_routers[1].tile_centroid_x, 0.5)); - REQUIRE(vtr::isclose(list_of_routers[1].tile_centroid_y, 4.5)); + REQUIRE(vtr::isclose(list_of_routers[1].tile_centroid_x, 0.5f)); + REQUIRE(vtr::isclose(list_of_routers[1].tile_centroid_y, 4.5f)); // check the top left router REQUIRE(list_of_routers[2].grid_width_position == 7); REQUIRE(list_of_routers[2].grid_height_position == 6); - REQUIRE(vtr::isclose(list_of_routers[2].tile_centroid_x, 7.5)); - REQUIRE(vtr::isclose(list_of_routers[2].tile_centroid_y, 6.5)); + REQUIRE(vtr::isclose(list_of_routers[2].tile_centroid_x, 7.5f)); + REQUIRE(vtr::isclose(list_of_routers[2].tile_centroid_y, 6.5f)); // check the top right router REQUIRE(list_of_routers[3].grid_width_position == 7); REQUIRE(list_of_routers[3].grid_height_position == 8); - REQUIRE(vtr::isclose(list_of_routers[3].tile_centroid_x, 7.5)); - REQUIRE(vtr::isclose(list_of_routers[3].tile_centroid_y, 8.5)); + REQUIRE(vtr::isclose(list_of_routers[3].tile_centroid_x, 7.5f)); + REQUIRE(vtr::isclose(list_of_routers[3].tile_centroid_y, 8.5f)); } } TEST_CASE("test_create_noc_routers", "[vpr_setup_noc]") { // datastructure to hold the list of physical tiles - std::vector list_of_routers; + vtr::vector list_of_routers; /* * Setup: From 097b5ee08366bd3c7e18d79a8a0d52b5edef0c90 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Fri, 5 Jul 2024 17:24:45 -0400 Subject: [PATCH 05/39] update XYRouting to support 3d noc --- libs/libarchfpga/src/physical_types.h | 4 +- libs/libvtrutil/src/vtr_util.h | 15 +++++ vpr/src/noc/bfs_routing.cpp | 3 +- vpr/src/noc/noc_router.cpp | 7 +-- vpr/src/noc/turn_model_routing.h | 2 + vpr/src/noc/xy_routing.cpp | 91 ++++++++++----------------- vpr/src/noc/xy_routing.h | 10 ++- 7 files changed, 62 insertions(+), 70 deletions(-) diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index edd66aaf162..4d840850159 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -822,10 +822,10 @@ struct t_physical_pin { /** * @brief Describes The location of a physical tile - * @param layer_num The die number of the physical tile. If the FPGA only has one die, or the physical tile is located - * on the base die, layer_num is equal to zero. If it is one the die above base die, it is one, etc. * @param x The x location of the physical tile on the given die * @param y The y location of the physical tile on the given die + * @param layer_num The die number of the physical tile. If the FPGA only has one die, or the physical tile is located + * on the base die, layer_num is equal to zero. If it is one the die above base die, it is one, etc. */ struct t_physical_tile_loc { int x = OPEN; diff --git a/libs/libvtrutil/src/vtr_util.h b/libs/libvtrutil/src/vtr_util.h index b5737372557..12f4d4f11bf 100644 --- a/libs/libvtrutil/src/vtr_util.h +++ b/libs/libvtrutil/src/vtr_util.h @@ -48,6 +48,9 @@ std::string join(Container container, std::string_view delim); template std::string join(std::initializer_list list, std::string_view delim); +template +bool exactly_k_conditions(int k, Conditions... conditions); + template void uniquify(Container container); @@ -116,6 +119,18 @@ void uniquify(Container container) { container.end()); } +template +bool exactly_k_conditions(int k, Conditions... conditions) { + bool conditionArray[] = {conditions...}; + int count = 0; + for (bool condition : conditionArray) { + if (condition) { + count++; + } + } + return count == k; +} + int get_pid(); } // namespace vtr diff --git a/vpr/src/noc/bfs_routing.cpp b/vpr/src/noc/bfs_routing.cpp index 2fdc2650a7d..b80551958d6 100644 --- a/vpr/src/noc/bfs_routing.cpp +++ b/vpr/src/noc/bfs_routing.cpp @@ -94,7 +94,8 @@ void BFSRouting::route_flow(NocRouterId src_router_id, } else { // a path was not found so throw an error to the user VPR_FATAL_ERROR(VPR_ERROR_OTHER, - "No route could be found from starting router with id:'%d' and the destination router with id:'%d' using the breadth-first search routing algorithm.", + "No route could be found from starting router with id:'%d' and the destination router with id:'%d' " + "using the breadth-first search routing algorithm.", src_router.get_router_user_id(), sink_router.get_router_user_id()); } diff --git a/vpr/src/noc/noc_router.cpp b/vpr/src/noc/noc_router.cpp index ab4bb4ea42a..4af296c02ef 100644 --- a/vpr/src/noc/noc_router.cpp +++ b/vpr/src/noc/noc_router.cpp @@ -31,12 +31,7 @@ int NocRouter::get_router_layer_position() const { } t_physical_tile_loc NocRouter::get_router_physical_location() const { - const int x = get_router_grid_position_x(); - const int y = get_router_grid_position_y(); - const int layer = get_router_layer_position(); - t_physical_tile_loc phy_loc{x, y, layer}; - - return phy_loc; + return {router_grid_position_x, router_grid_position_y, router_layer_position}; } double NocRouter::get_latency() const { diff --git a/vpr/src/noc/turn_model_routing.h b/vpr/src/noc/turn_model_routing.h index 68d64f4e12f..1274218bc09 100644 --- a/vpr/src/noc/turn_model_routing.h +++ b/vpr/src/noc/turn_model_routing.h @@ -113,6 +113,8 @@ class TurnModelRouting : public NocRouting { RIGHT, /*!< Moving towards the positive X-axis*/ UP, /*!< Moving towards the positive Y-axis*/ DOWN, /*!< Moving towards the negative Y-axis*/ + ABOVE, /*!< Moving towards the positive Z-axis*/ + BELOW, /*!< Moving towards the negative Z-axis*/ INVALID /*!< Invalid direction*/ }; diff --git a/vpr/src/noc/xy_routing.cpp b/vpr/src/noc/xy_routing.cpp index f3f1f7e4dfa..ddc51b6f6a8 100644 --- a/vpr/src/noc/xy_routing.cpp +++ b/vpr/src/noc/xy_routing.cpp @@ -2,6 +2,7 @@ #include #include "xy_routing.h" +#include "vtr_util.h" XYRouting::~XYRouting() = default; @@ -20,84 +21,51 @@ const std::vector& XYRouting::get_legal_directions( /* In XY-routing, we first move along the X-axis until * the current router has the same x-coordinate as the * destination. Then we start moving along the y-axis. + * Finally, we move along the z-axis. */ - if (curr_router_pos.x != dst_router_pos.x) { - return x_axis_directions; + + if (dst_router_pos.x > curr_router_pos.x) { + return right_direction; + } else if (dst_router_pos.x < curr_router_pos.x) { + return left_direction; + } else if (dst_router_pos.y > curr_router_pos.y) { + return up_direction; + } else if (dst_router_pos.y < curr_router_pos.y) { + return down_direction; + } else if (dst_router_pos.layer_num > curr_router_pos.layer_num) { + return above_direction; + } else if (dst_router_pos.layer_num < curr_router_pos.layer_num) { + return below_direction; } else { - return y_axis_directions; + return no_direction; } } TurnModelRouting::Direction XYRouting::select_next_direction(const std::vector& legal_directions, NocRouterId /*src_router_id*/, - NocRouterId dst_router_id, - NocRouterId curr_router_id, + NocRouterId /*dst_router_id*/, + NocRouterId /*curr_router_id*/, NocTrafficFlowId /*traffic_flow_id*/, - const NocStorage& noc_model) { - // get current and destination NoC routers - const auto& curr_router = noc_model.get_single_noc_router(curr_router_id); - const auto& dst_router = noc_model.get_single_noc_router(dst_router_id); + const NocStorage& /*noc_model*/) { - // get the position of current and destination NoC routers - const auto curr_router_pos = curr_router.get_router_physical_location(); - const auto dst_router_pos = dst_router.get_router_physical_location(); - - // indicates whether the next direction that moves us - // closer to the destination router is found among - // legal directions - bool found_next_direction = false; - - // Iterate over legal directions and find the one that moves us closer to the destination - for (const auto& direction : legal_directions) { - switch (direction) { - case TurnModelRouting::Direction::LEFT: - if (dst_router_pos.x < curr_router_pos.x) { - found_next_direction = true; - } - break; - case TurnModelRouting::Direction::RIGHT: - if (dst_router_pos.x > curr_router_pos.x) { - found_next_direction = true; - } - break; - case TurnModelRouting::Direction::UP: - if (dst_router_pos.y > curr_router_pos.y) { - found_next_direction = true; - } - break; - case TurnModelRouting::Direction::DOWN: - if (dst_router_pos.y < curr_router_pos.y) { - found_next_direction = true; - } - break; - default: - break; - } - - if (found_next_direction) { - return direction; - } + if (legal_directions.size() == 1) { + return legal_directions[0]; } return TurnModelRouting::Direction::INVALID; } bool XYRouting::is_turn_legal(const std::array, 3>& noc_routers) const { - const int x1 = noc_routers[0].get().get_router_grid_position_x(); - const int y1 = noc_routers[0].get().get_router_grid_position_y(); - - const int x2 = noc_routers[1].get().get_router_grid_position_x(); - const int y2 = noc_routers[1].get().get_router_grid_position_y(); - - const int x3 = noc_routers[2].get().get_router_grid_position_x(); - const int y3 = noc_routers[2].get().get_router_grid_position_y(); + const auto[x1, y1, z1] = noc_routers[0].get().get_router_physical_location(); + const auto[x2, y2, z2] = noc_routers[1].get().get_router_physical_location(); + const auto[x3, y3, z3] = noc_routers[2].get().get_router_physical_location(); // check if the given routers can be traversed one after another - VTR_ASSERT(x2 == x1 || y2 == y1); - VTR_ASSERT(x3 == x2 || y3 == y2); + VTR_ASSERT(vtr::exactly_k_conditions(2, x1 == x2, y1 == y2, z1 == z2)); + VTR_ASSERT(vtr::exactly_k_conditions(2, x2 == x3, y2 == y3, z2 == z3)); // going back to the first router is not allowed - if (x1 == x3 && y1 == y3) { + if (x1 == x3 && y1 == y3 && z1 == z3) { return false; } @@ -106,5 +74,10 @@ bool XYRouting::is_turn_legal(const std::array, 3>& noc_routers) const override; private: - const std::vector x_axis_directions {TurnModelRouting::Direction::LEFT, TurnModelRouting::Direction::RIGHT}; - const std::vector y_axis_directions {TurnModelRouting::Direction::UP, TurnModelRouting::Direction::DOWN}; + const std::vector right_direction {TurnModelRouting::Direction::RIGHT}; + const std::vector left_direction {TurnModelRouting::Direction::LEFT}; + const std::vector up_direction {TurnModelRouting::Direction::UP}; + const std::vector down_direction {TurnModelRouting::Direction::DOWN}; + const std::vector above_direction {TurnModelRouting::Direction::ABOVE}; + const std::vector below_direction {TurnModelRouting::Direction::BELOW}; + const std::vector no_direction; + }; #endif \ No newline at end of file From 6d3023234d64dc146e1d1e724b7640d5641d8094 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Fri, 5 Jul 2024 19:18:19 -0400 Subject: [PATCH 06/39] 3d support in negative first routing algrotihtm --- vpr/src/noc/negative_first_routing.cpp | 60 ++++++++++++++------------ vpr/src/noc/odd_even_routing.cpp | 4 +- vpr/src/noc/turn_model_routing.cpp | 16 ++++++- vpr/src/noc/turn_model_routing.h | 9 ++-- 4 files changed, 54 insertions(+), 35 deletions(-) diff --git a/vpr/src/noc/negative_first_routing.cpp b/vpr/src/noc/negative_first_routing.cpp index eaec531a554..5d398817b49 100644 --- a/vpr/src/noc/negative_first_routing.cpp +++ b/vpr/src/noc/negative_first_routing.cpp @@ -37,6 +37,11 @@ const std::vector& NegativeFirstRouting::get_legal_ returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); } + // check whether moving below keeps us on a minimal route + if (dst_router_pos.layer_num < curr_router_pos.layer_num) { + returned_legal_direction.push_back(TurnModelRouting::Direction::BELOW); + } + // if at least one of the negative directions is legal, // we don't need to check the positive ones and can return if (!returned_legal_direction.empty()) { @@ -58,6 +63,11 @@ const std::vector& NegativeFirstRouting::get_legal_ returned_legal_direction.push_back(TurnModelRouting::Direction::UP); } + // check whether moving above keeps us on a minimal route + if (dst_router_pos.layer_num > curr_router_pos.layer_num) { + returned_legal_direction.push_back(TurnModelRouting::Direction::ABOVE); + } + return returned_legal_direction; } @@ -92,53 +102,47 @@ TurnModelRouting::Direction NegativeFirstRouting::select_next_direction(const st const uint32_t max_uint32_t_val = std::numeric_limits::max(); // get the distance from the current router to the destination in each coordination - int delta_x = abs(dst_router_pos.x - curr_router_pos.x); - int delta_y = abs(dst_router_pos.y - curr_router_pos.y); + const int delta_x = abs(dst_router_pos.x - curr_router_pos.x); + const int delta_y = abs(dst_router_pos.y - curr_router_pos.y); + const int delta_z = abs(dst_router_pos.layer_num - curr_router_pos.layer_num); + const int manhattan_dist = delta_x + delta_y + delta_z; // compute the probability of going to north/south direction - uint32_t ns_probability = delta_y * (max_uint32_t_val / (delta_x + delta_y)); + uint32_t ns_probability = delta_y * (max_uint32_t_val / manhattan_dist); + // compute the probability of going to north/south direction + uint32_t z_probability = delta_z * (max_uint32_t_val / manhattan_dist); + TurnModelRouting::Direction selected_direction = TurnModelRouting::Direction::INVALID; - if (hash_val < ns_probability) { - selected_direction = select_vertical_direction(legal_directions); + if (hash_val < z_probability) { + selected_direction = select_z_direction(legal_directions); + } else if (hash_val < ns_probability + z_probability) { + selected_direction = select_y_direction(legal_directions); } else { - selected_direction = select_horizontal_direction(legal_directions); + selected_direction = select_x_direction(legal_directions); } return selected_direction; } bool NegativeFirstRouting::is_turn_legal(const std::array, 3>& noc_routers) const { - const int x1 = noc_routers[0].get().get_router_grid_position_x(); - const int y1 = noc_routers[0].get().get_router_grid_position_y(); - - const int x2 = noc_routers[1].get().get_router_grid_position_x(); - const int y2 = noc_routers[1].get().get_router_grid_position_y(); - - const int x3 = noc_routers[2].get().get_router_grid_position_x(); - const int y3 = noc_routers[2].get().get_router_grid_position_y(); + const auto[x1, y1, z1] = noc_routers[0].get().get_router_physical_location(); + const auto[x2, y2, z2] = noc_routers[1].get().get_router_physical_location(); + const auto[x3, y3, z3] = noc_routers[2].get().get_router_physical_location(); // check if the given routers can be traversed one after another - VTR_ASSERT(x2 == x1 || y2 == y1); - VTR_ASSERT(x3 == x2 || y3 == y2); + VTR_ASSERT(vtr::exactly_k_conditions(2, x1 == x2, y1 == y2, z1 == z2)); + VTR_ASSERT(vtr::exactly_k_conditions(2, x2 == x3, y2 == y3, z2 == z3)); // going back to the first router is not allowed - if (x1 == x3 && y1 == y3) { - return false; - } - - /* In negative-first routing algorithm, a traffic flow - * can't take a downward turn if it is travelling toward right direction. - */ - if (x2 > x1 && y3 < y2) { + if (x1 == x3 && y1 == y3 && z1 == z3) { return false; } - /* In negative-first routing algorithm, a traffic flow - * can't take a left turn if it is travelling upwards. - */ - if (y2 > y1 && x3 < x2) { + // In negative-first routing algorithm, these 6 90-degree turns are prohibited. + if ((x2 > x1 && y3 < y2) || (y2 > y1 && x3 < x2) || (z2 > z1 && x3 < x2) || + (x2 > x1 && z3 < z2) || (z2 > z1 && y3 < y2) || (y2 > y1 && z3 < z2)) { return false; } diff --git a/vpr/src/noc/odd_even_routing.cpp b/vpr/src/noc/odd_even_routing.cpp index 68a6b59a479..d9f08ab2725 100644 --- a/vpr/src/noc/odd_even_routing.cpp +++ b/vpr/src/noc/odd_even_routing.cpp @@ -139,9 +139,9 @@ TurnModelRouting::Direction OddEvenRouting::select_next_direction(const std::vec // choose whether move vertically or horizontally if (hash_val < vertical_probability) { - selected_direction = select_vertical_direction(legal_directions); + selected_direction = select_y_direction(legal_directions); } else { - selected_direction = select_horizontal_direction(legal_directions); + selected_direction = select_x_direction(legal_directions); } return selected_direction; diff --git a/vpr/src/noc/turn_model_routing.cpp b/vpr/src/noc/turn_model_routing.cpp index 802a2fa5104..13339df4d21 100644 --- a/vpr/src/noc/turn_model_routing.cpp +++ b/vpr/src/noc/turn_model_routing.cpp @@ -197,7 +197,7 @@ uint32_t TurnModelRouting::murmur3_32(const std::vector& key, uint32_t return h; } -TurnModelRouting::Direction TurnModelRouting::select_vertical_direction(const std::vector& directions) { +TurnModelRouting::Direction TurnModelRouting::select_y_direction(const std::vector& directions) { // iterate over the given iterations and return the first vertical one for (const auto& direction : directions) { if (direction == TurnModelRouting::Direction::DOWN || direction == TurnModelRouting::Direction::UP) { @@ -209,7 +209,7 @@ TurnModelRouting::Direction TurnModelRouting::select_vertical_direction(const st return TurnModelRouting::Direction::INVALID; } -TurnModelRouting::Direction TurnModelRouting::select_horizontal_direction(const std::vector& directions) { +TurnModelRouting::Direction TurnModelRouting::select_x_direction(const std::vector& directions) { // iterate over the given iterations and return the first horizontal one for (const auto& direction : directions) { if (direction == TurnModelRouting::Direction::RIGHT || direction == TurnModelRouting::Direction::LEFT) { @@ -221,6 +221,18 @@ TurnModelRouting::Direction TurnModelRouting::select_horizontal_direction(const return TurnModelRouting::Direction::INVALID; } +TurnModelRouting::Direction TurnModelRouting::select_z_direction(const std::vector& directions) { + // iterate over the given iterations and return the first one along the z axis + for (const auto& direction : directions) { + if (direction == TurnModelRouting::Direction::ABOVE || direction == TurnModelRouting::Direction::BELOW) { + return direction; + } + } + + // if there was not any horizontal directions, return INVALID + return TurnModelRouting::Direction::INVALID; +} + TurnModelRouting::Direction TurnModelRouting::select_direction_other_than(const std::vector& directions, TurnModelRouting::Direction other_than) { // Iterate over all given directions and return the first one which is not "other_than" diff --git a/vpr/src/noc/turn_model_routing.h b/vpr/src/noc/turn_model_routing.h index 1274218bc09..b482c1b363b 100644 --- a/vpr/src/noc/turn_model_routing.h +++ b/vpr/src/noc/turn_model_routing.h @@ -115,6 +115,7 @@ class TurnModelRouting : public NocRouting { DOWN, /*!< Moving towards the negative Y-axis*/ ABOVE, /*!< Moving towards the positive Z-axis*/ BELOW, /*!< Moving towards the negative Z-axis*/ + N_DIRECTIONS, INVALID /*!< Invalid direction*/ }; @@ -139,7 +140,7 @@ class TurnModelRouting : public NocRouting { * @return Direction The first vertical direction found or INVALID if there * is no vertical direction among given directions. */ - TurnModelRouting::Direction select_vertical_direction(const std::vector& directions); + TurnModelRouting::Direction select_y_direction(const std::vector& directions); /** * @brief Returns the first horizontal direction found among given directions. @@ -149,7 +150,9 @@ class TurnModelRouting : public NocRouting { * @return Direction The first horizontal direction found or INVALID if there * is no horizontal direction among given directions. */ - TurnModelRouting::Direction select_horizontal_direction(const std::vector& directions); + TurnModelRouting::Direction select_x_direction(const std::vector& directions); + + TurnModelRouting::Direction select_z_direction(const std::vector& directions); /** * @brief Returns the first direction among given direction @@ -265,7 +268,7 @@ class TurnModelRouting : public NocRouting { protected: // get_legal_directions() return a reference to this vector to avoid allocating a new vector // each time it is called - std::vector returned_legal_direction{4}; + std::vector returned_legal_direction{TurnModelRouting::Direction::N_DIRECTIONS}; private: std::vector inputs_to_murmur3_hasher{4}; From 2c872bf41efa1c843a924c08615128c495f18ba3 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Fri, 5 Jul 2024 19:49:56 -0400 Subject: [PATCH 07/39] select_next_direction() method is no longer pure virtual --- vpr/src/noc/negative_first_routing.cpp | 55 -------------------------- vpr/src/noc/negative_first_routing.h | 26 ------------ vpr/src/noc/turn_model_routing.cpp | 43 ++++++++++++++++++++ vpr/src/noc/turn_model_routing.h | 3 +- 4 files changed, 44 insertions(+), 83 deletions(-) diff --git a/vpr/src/noc/negative_first_routing.cpp b/vpr/src/noc/negative_first_routing.cpp index 5d398817b49..49d29d124b3 100644 --- a/vpr/src/noc/negative_first_routing.cpp +++ b/vpr/src/noc/negative_first_routing.cpp @@ -71,61 +71,6 @@ const std::vector& NegativeFirstRouting::get_legal_ return returned_legal_direction; } -TurnModelRouting::Direction NegativeFirstRouting::select_next_direction(const std::vector& legal_directions, - NocRouterId src_router_id, - NocRouterId dst_router_id, - NocRouterId curr_router_id, - NocTrafficFlowId traffic_flow_id, - const NocStorage& noc_model) { - // get current and destination NoC routers - const auto& curr_router = noc_model.get_single_noc_router(curr_router_id); - const auto& dst_router = noc_model.get_single_noc_router(dst_router_id); - - // get the position of current and destination NoC routers - const auto curr_router_pos = curr_router.get_router_physical_location(); - const auto dst_router_pos = dst_router.get_router_physical_location(); - - // if there is only one legal direction, take it - if (legal_directions.size() == 1) { - return legal_directions[0]; - } - - /* If the function reaches this point, - * the destination routed is located at SW or NE of - * the current router. We adopt a similar approach to - * WestFirstRouting to select between south/north and west/east. - */ - - // compute the hash value - uint32_t hash_val = get_hash_value(src_router_id, dst_router_id, curr_router_id, traffic_flow_id); - // get the maximum value that can be represented by size_t - const uint32_t max_uint32_t_val = std::numeric_limits::max(); - - // get the distance from the current router to the destination in each coordination - const int delta_x = abs(dst_router_pos.x - curr_router_pos.x); - const int delta_y = abs(dst_router_pos.y - curr_router_pos.y); - const int delta_z = abs(dst_router_pos.layer_num - curr_router_pos.layer_num); - const int manhattan_dist = delta_x + delta_y + delta_z; - - // compute the probability of going to north/south direction - uint32_t ns_probability = delta_y * (max_uint32_t_val / manhattan_dist); - // compute the probability of going to north/south direction - uint32_t z_probability = delta_z * (max_uint32_t_val / manhattan_dist); - - - TurnModelRouting::Direction selected_direction = TurnModelRouting::Direction::INVALID; - - if (hash_val < z_probability) { - selected_direction = select_z_direction(legal_directions); - } else if (hash_val < ns_probability + z_probability) { - selected_direction = select_y_direction(legal_directions); - } else { - selected_direction = select_x_direction(legal_directions); - } - - return selected_direction; -} - bool NegativeFirstRouting::is_turn_legal(const std::array, 3>& noc_routers) const { const auto[x1, y1, z1] = noc_routers[0].get().get_router_physical_location(); const auto[x2, y2, z2] = noc_routers[1].get().get_router_physical_location(); diff --git a/vpr/src/noc/negative_first_routing.h b/vpr/src/noc/negative_first_routing.h index 3a465e3cc28..40c4dd211c5 100644 --- a/vpr/src/noc/negative_first_routing.h +++ b/vpr/src/noc/negative_first_routing.h @@ -40,32 +40,6 @@ class NegativeFirstRouting : public TurnModelRouting { NocRouterId dst_router_id, const NocStorage& noc_model) override; - /** - * @brief Selects a direction from legal directions. The traffic flow - * travels in the selected direction. When there are both horizontal and - * vertical directions available, this method selects one of the available - * directions randomly. The chance of horizontal and vertical directions - * are weighted by the horizontal and vertical distance between the - * current NoC router and the destination router. - * - * @param legal_directions Legal directions that the traffic flow can follow. - * Legal directions are usually a subset of all possible directions to ensure - * deadlock freedom. - * @param src_router_id A unique ID identifying the source NoC router. - * @param dst_router_id A unique ID identifying the destination NoC router. - * @param curr_router_id A unique ID identifying the current NoC router. - * @param noc_model A model of the NoC. This might be used by the derived class - * to determine the position of NoC routers. - * - * @return Direction The direction to travel next - */ - TurnModelRouting::Direction select_next_direction(const std::vector& legal_directions, - NocRouterId src_router_id, - NocRouterId dst_router_id, - NocRouterId curr_router_id, - NocTrafficFlowId traffic_flow_id, - const NocStorage& noc_model) override; - bool is_turn_legal(const std::array, 3>& noc_routers) const override; }; diff --git a/vpr/src/noc/turn_model_routing.cpp b/vpr/src/noc/turn_model_routing.cpp index 13339df4d21..b51d9af9841 100644 --- a/vpr/src/noc/turn_model_routing.cpp +++ b/vpr/src/noc/turn_model_routing.cpp @@ -281,3 +281,46 @@ std::vector> TurnModelRouting::get_all_illegal_t return illegal_turns; } +TurnModelRouting::Direction TurnModelRouting::select_next_direction(const std::vector& legal_directions, + NocRouterId src_router_id, + NocRouterId dst_router_id, + NocRouterId curr_router_id, + NocTrafficFlowId traffic_flow_id, + const NocStorage& noc_model) { + // get current and destination NoC routers + const auto& curr_router = noc_model.get_single_noc_router(curr_router_id); + const auto& dst_router = noc_model.get_single_noc_router(dst_router_id); + + // get the position of current and destination NoC routers + const auto curr_router_pos = curr_router.get_router_physical_location(); + const auto dst_router_pos = dst_router.get_router_physical_location(); + + // if there is only one legal direction, take it + if (legal_directions.size() == 1) { + return legal_directions[0]; + } + + // compute the hash value + uint32_t hash_val = get_hash_value(src_router_id, dst_router_id, curr_router_id, traffic_flow_id); + + // get the distance from the current router to the destination in each coordination + const int delta_x = abs(dst_router_pos.x - curr_router_pos.x); + const int delta_y = abs(dst_router_pos.y - curr_router_pos.y); + const int delta_z = abs(dst_router_pos.layer_num - curr_router_pos.layer_num); + const int manhattan_dist = delta_x + delta_y + delta_z; + + int hash_val_remainder = hash_val % manhattan_dist; + + + TurnModelRouting::Direction selected_direction = TurnModelRouting::Direction::INVALID; + + if (hash_val_remainder < delta_x) { + selected_direction = select_x_direction(legal_directions); + } else if (hash_val_remainder < delta_x + delta_y) { + selected_direction = select_y_direction(legal_directions); + } else { + selected_direction = select_z_direction(legal_directions); + } + + return selected_direction; +} diff --git a/vpr/src/noc/turn_model_routing.h b/vpr/src/noc/turn_model_routing.h index b482c1b363b..0977c4fabc9 100644 --- a/vpr/src/noc/turn_model_routing.h +++ b/vpr/src/noc/turn_model_routing.h @@ -251,8 +251,7 @@ class TurnModelRouting : public NocRouting { NocRouterId dst_router_id, NocRouterId curr_router_id, NocTrafficFlowId traffic_flow_id, - const NocStorage& noc_model) - = 0; + const NocStorage& noc_model); /** * @brief Determines whether a turn specified by 3 NoC routers visited in the turn From b3649d36fb0840e48d4f44e1e68ac64e18923c95 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Fri, 5 Jul 2024 19:50:58 -0400 Subject: [PATCH 08/39] 3d north-last routing algorithm --- vpr/src/noc/north_last_routing.cpp | 61 ++++++------------------------ vpr/src/noc/north_last_routing.h | 26 ------------- 2 files changed, 12 insertions(+), 75 deletions(-) diff --git a/vpr/src/noc/north_last_routing.cpp b/vpr/src/noc/north_last_routing.cpp index 7bfc58791c0..113029dad32 100644 --- a/vpr/src/noc/north_last_routing.cpp +++ b/vpr/src/noc/north_last_routing.cpp @@ -42,60 +42,23 @@ const std::vector& NorthLastRouting::get_legal_dire returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); } - // consider north only when none of other directions are legal - if (returned_legal_direction.empty() && dst_router_pos.y > curr_router_pos.y) { - returned_legal_direction.push_back(TurnModelRouting::Direction::UP); + // check if the destination router is at the layer below of the current router + if (dst_router_pos.layer_num < curr_router_pos.layer_num) { + returned_legal_direction.push_back(TurnModelRouting::Direction::BELOW); } - return returned_legal_direction; -} - -TurnModelRouting::Direction NorthLastRouting::select_next_direction(const std::vector& legal_directions, - NocRouterId src_router_id, - NocRouterId dst_router_id, - NocRouterId curr_router_id, - NocTrafficFlowId traffic_flow_id, - const NocStorage& noc_model) { - // get current and destination NoC routers - const auto& curr_router = noc_model.get_single_noc_router(curr_router_id); - const auto& dst_router = noc_model.get_single_noc_router(dst_router_id); - - // get the position of current and destination NoC routers - const auto curr_router_pos = curr_router.get_router_physical_location(); - const auto dst_router_pos = dst_router.get_router_physical_location(); + // consider north and up only when none of other directions are legal + if (returned_legal_direction.empty()) { + if (dst_router_pos.y > curr_router_pos.y) { + returned_legal_direction.push_back(TurnModelRouting::Direction::UP); + } - // if there is only one legal direction, take it - if (legal_directions.size() == 1) { - return legal_directions[0]; + if (dst_router_pos.layer_num > curr_router_pos.layer_num) { + returned_legal_direction.push_back(TurnModelRouting::Direction::ABOVE); + } } - /* If the function reaches this point, - * the destination routed is located at SE or SW of - * the current router. We adopt a similar approach to - * WestFirstRouting to select between south and west/east. - */ - - // compute the hash value - uint32_t hash_val = get_hash_value(src_router_id, dst_router_id, curr_router_id, traffic_flow_id); - // get the maximum value that can be represented by size_t - const uint32_t max_uint32_t_val = std::numeric_limits::max(); - - // get the distance from the current router to the destination in each coordination - int delta_x = abs(dst_router_pos.x - curr_router_pos.x); - int delta_y = abs(dst_router_pos.y - curr_router_pos.y); - - // compute the probability of going to the down (south) direction - uint32_t south_probability = delta_y * (max_uint32_t_val / (delta_x + delta_y)); - - TurnModelRouting::Direction selected_direction = TurnModelRouting::Direction::INVALID; - - if (hash_val < south_probability) { // sometimes turn south - selected_direction = TurnModelRouting::Direction::DOWN; - } else { // if turning south was rejected, take the other option (east/west) - selected_direction = select_direction_other_than(legal_directions, TurnModelRouting::Direction::DOWN); - } - - return selected_direction; + return returned_legal_direction; } bool NorthLastRouting::is_turn_legal(const std::array, 3>& noc_routers) const { diff --git a/vpr/src/noc/north_last_routing.h b/vpr/src/noc/north_last_routing.h index 61aaf8caa4b..5bb3422233e 100644 --- a/vpr/src/noc/north_last_routing.h +++ b/vpr/src/noc/north_last_routing.h @@ -41,32 +41,6 @@ class NorthLastRouting : public TurnModelRouting { NocRouterId dst_router_id, const NocStorage& noc_model) override; - /** - * @brief Selects a direction from legal directions. The traffic flow - * travels in that direction. When there are both horizontal and - * vertical directions available, this method selects one of the available - * directions randomly. The chance of horizontal and vertical directions - * are weighted by the horizontal and vertical distance between the - * current NoC router and the destination router. - * - * @param legal_directions Legal directions that the traffic flow can follow. - * Legal directions are usually a subset of all possible directions to ensure - * deadlock freedom. - * @param src_router_id A unique ID identifying the source NoC router. - * @param dst_router_id A unique ID identifying the destination NoC router. - * @param curr_router_id A unique ID identifying the current NoC router. - * @param noc_model A model of the NoC. This might be used by the derived class - * to determine the position of NoC routers. - * - * @return Direction The direction to travel next - */ - TurnModelRouting::Direction select_next_direction(const std::vector& legal_directions, - NocRouterId src_router_id, - NocRouterId dst_router_id, - NocRouterId curr_router_id, - NocTrafficFlowId traffic_flow_id, - const NocStorage& noc_model) override; - bool is_turn_legal(const std::array, 3>& noc_routers) const override; }; From 6defaef6d969fcce910888930ec0791b520610eb Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Mon, 8 Jul 2024 14:27:49 -0400 Subject: [PATCH 09/39] forbid 6 90-degree turns in 3d north-last algorithm --- vpr/src/noc/north_last_routing.cpp | 29 +++++++++++------------------ vpr/src/noc/xy_routing.cpp | 6 +++--- 2 files changed, 14 insertions(+), 21 deletions(-) diff --git a/vpr/src/noc/north_last_routing.cpp b/vpr/src/noc/north_last_routing.cpp index 113029dad32..b417944f68c 100644 --- a/vpr/src/noc/north_last_routing.cpp +++ b/vpr/src/noc/north_last_routing.cpp @@ -42,7 +42,7 @@ const std::vector& NorthLastRouting::get_legal_dire returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); } - // check if the destination router is at the layer below of the current router + // check if the destination router is at the layer below the current router if (dst_router_pos.layer_num < curr_router_pos.layer_num) { returned_legal_direction.push_back(TurnModelRouting::Direction::BELOW); } @@ -62,30 +62,23 @@ const std::vector& NorthLastRouting::get_legal_dire } bool NorthLastRouting::is_turn_legal(const std::array, 3>& noc_routers) const { - const int x1 = noc_routers[0].get().get_router_grid_position_x(); - const int y1 = noc_routers[0].get().get_router_grid_position_y(); - - const int x2 = noc_routers[1].get().get_router_grid_position_x(); - const int y2 = noc_routers[1].get().get_router_grid_position_y(); - - const int x3 = noc_routers[2].get().get_router_grid_position_x(); - const int y3 = noc_routers[2].get().get_router_grid_position_y(); + const auto [x1, y1, z1] = noc_routers[0].get().get_router_physical_location(); + const auto [x2, y2, z2] = noc_routers[1].get().get_router_physical_location(); + const auto [x3, y3, z3] = noc_routers[2].get().get_router_physical_location(); // check if the given routers can be traversed one after another - VTR_ASSERT(x2 == x1 || y2 == y1); - VTR_ASSERT(x3 == x2 || y3 == y2); + VTR_ASSERT(vtr::exactly_k_conditions(2, x1 == x2, y1 == y2, z1 == z2)); + VTR_ASSERT(vtr::exactly_k_conditions(2, x2 == x3, y2 == y3, z2 == z3)); + // going back to the first router is not allowed - if (x1 == x3 && y1 == y3) { + if (x1 == x3 && y1 == y3 && z1 == z3) { return false; } - /* In the north-last algorithm, once the north direction is taken, no other - * direction can be followed. Therefore, if the first link moves upward, the - * second one cannot move horizontally. The case where the second link goes - * back to the first router was checked in the previous if statement. - */ - if (y2 > y1 && x2 != x3) { + // In north-last routing algorithm, these 6 90-degree turns are prohibited. + if ((z2 > z1 && x3 < x2) || (z2 > z1 && x3 > x2) || (z2 > z1 && y3 < y2) || + (y2 > y1 && z3 < z2) || (y2 > y1 && x3 < x2) || (y2 > y1 && x3 > x2)) { return false; } diff --git a/vpr/src/noc/xy_routing.cpp b/vpr/src/noc/xy_routing.cpp index ddc51b6f6a8..0c6bff655b2 100644 --- a/vpr/src/noc/xy_routing.cpp +++ b/vpr/src/noc/xy_routing.cpp @@ -56,9 +56,9 @@ TurnModelRouting::Direction XYRouting::select_next_direction(const std::vector, 3>& noc_routers) const { - const auto[x1, y1, z1] = noc_routers[0].get().get_router_physical_location(); - const auto[x2, y2, z2] = noc_routers[1].get().get_router_physical_location(); - const auto[x3, y3, z3] = noc_routers[2].get().get_router_physical_location(); + const auto [x1, y1, z1] = noc_routers[0].get().get_router_physical_location(); + const auto [x2, y2, z2] = noc_routers[1].get().get_router_physical_location(); + const auto [x3, y3, z3] = noc_routers[2].get().get_router_physical_location(); // check if the given routers can be traversed one after another VTR_ASSERT(vtr::exactly_k_conditions(2, x1 == x2, y1 == y2, z1 == z2)); From 75eae08e75761eb3a8da2d551b4eefb1ad5da945 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Mon, 8 Jul 2024 14:37:32 -0400 Subject: [PATCH 10/39] 3d west-first routing algorithm --- vpr/src/noc/west_first_routing.cpp | 39 ++++++++++++++++++------------ 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/vpr/src/noc/west_first_routing.cpp b/vpr/src/noc/west_first_routing.cpp index 5fc4a13e696..a51077785da 100644 --- a/vpr/src/noc/west_first_routing.cpp +++ b/vpr/src/noc/west_first_routing.cpp @@ -23,17 +23,28 @@ const std::vector& WestFirstRouting::get_legal_dire * as the destination router. Otherwise, we can move south, north, * and east adaptively. */ + if (dst_router_pos.x < curr_router_pos.x) { returned_legal_direction.push_back(TurnModelRouting::Direction::LEFT); - } else { // to the east or the same column - if (dst_router_pos.x > curr_router_pos.x) { // not the same column + } + + if (dst_router_pos.y < curr_router_pos.y) { + returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); + } + + if (returned_legal_direction.empty()) { + if (dst_router_pos.x > curr_router_pos.x) { returned_legal_direction.push_back(TurnModelRouting::Direction::RIGHT); } if (dst_router_pos.y > curr_router_pos.y) { returned_legal_direction.push_back(TurnModelRouting::Direction::UP); - } else if (dst_router_pos.y < curr_router_pos.y) { - returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); + } + + if (dst_router_pos.layer_num > curr_router_pos.layer_num) { + returned_legal_direction.push_back(TurnModelRouting::Direction::ABOVE); + } else if (dst_router_pos.layer_num < curr_router_pos.layer_num) { + returned_legal_direction.push_back(TurnModelRouting::Direction::BELOW); } } @@ -96,21 +107,16 @@ TurnModelRouting::Direction WestFirstRouting::select_next_direction(const std::v } bool WestFirstRouting::is_turn_legal(const std::array, 3>& noc_routers) const { - const int x1 = noc_routers[0].get().get_router_grid_position_x(); - const int y1 = noc_routers[0].get().get_router_grid_position_y(); - - const int x2 = noc_routers[1].get().get_router_grid_position_x(); - const int y2 = noc_routers[1].get().get_router_grid_position_y(); - - const int x3 = noc_routers[2].get().get_router_grid_position_x(); - const int y3 = noc_routers[2].get().get_router_grid_position_y(); + const auto [x1, y1, z1] = noc_routers[0].get().get_router_physical_location(); + const auto [x2, y2, z2] = noc_routers[1].get().get_router_physical_location(); + const auto [x3, y3, z3] = noc_routers[2].get().get_router_physical_location(); // check if the given routers can be traversed one after another - VTR_ASSERT(x2 == x1 || y2 == y1); - VTR_ASSERT(x3 == x2 || y3 == y2); + VTR_ASSERT(vtr::exactly_k_conditions(2, x1 == x2, y1 == y2, z1 == z2)); + VTR_ASSERT(vtr::exactly_k_conditions(2, x2 == x3, y2 == y3, z2 == z3)); // going back to the first router is not allowed - if (x1 == x3 && y1 == y3) { + if (x1 == x3 && y1 == y3 && z1 == z3) { return false; } @@ -119,7 +125,8 @@ bool WestFirstRouting::is_turn_legal(const std::array z1 && x3 < x2) || (z2 < z1 && x3 < x2) || (z2 > z1 && y3 < y2) || + (z2 < z1 && y3 < y2) || (y2 > y1 && x3 < x2) || (x2 > x1 && y3 > y2)) { return false; } From 6b17b255ff44fb3766d46e9b66d899cabe5d41af Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Tue, 9 Jul 2024 14:17:06 -0400 Subject: [PATCH 11/39] remove select_next_direction() override in westfirstrouting --- vpr/src/noc/west_first_routing.cpp | 55 ------------------------------ vpr/src/noc/west_first_routing.h | 26 -------------- 2 files changed, 81 deletions(-) diff --git a/vpr/src/noc/west_first_routing.cpp b/vpr/src/noc/west_first_routing.cpp index a51077785da..80185c58bf4 100644 --- a/vpr/src/noc/west_first_routing.cpp +++ b/vpr/src/noc/west_first_routing.cpp @@ -51,61 +51,6 @@ const std::vector& WestFirstRouting::get_legal_dire return returned_legal_direction; } -TurnModelRouting::Direction WestFirstRouting::select_next_direction(const std::vector& legal_directions, - NocRouterId src_router_id, - NocRouterId dst_router_id, - NocRouterId curr_router_id, - NocTrafficFlowId traffic_flow_id, - const NocStorage& noc_model) { - // get current and destination NoC routers - const auto& curr_router = noc_model.get_single_noc_router(curr_router_id); - const auto& dst_router = noc_model.get_single_noc_router(dst_router_id); - - // get the position of current and destination NoC routers - const auto curr_router_pos = curr_router.get_router_physical_location(); - const auto dst_router_pos = dst_router.get_router_physical_location(); - - // if there is only one legal direction, take it - if (legal_directions.size() == 1) { - return legal_directions[0]; - } - - /* - * If the function has not already returned, - * the destination router is either to NE or SE of - * the current router. Therefore, we have two - * directions to choose from. A hash value is generated - * based on the source, current, and destination router IDs - * along with the traffic flow ID. Then, we select one direction - * by flipping a biased coin. For example if - * 1) dst_router_pos.x - curr_router_pos.x = 2 - * 2) dst_router_pos.y - curr_router_pos.y = 8 - * We take the UP direction with 80% chance, and RIGHT with 20%. - */ - - // compute the hash value - uint32_t hash_val = get_hash_value(src_router_id, dst_router_id, curr_router_id, traffic_flow_id); - // get the maximum value that can be represented by size_t - const uint32_t max_uint32_t_val = std::numeric_limits::max(); - - // get the distance from the current router to the destination in each coordination - int delta_x = abs(dst_router_pos.x - curr_router_pos.x); - int delta_y = abs(dst_router_pos.y - curr_router_pos.y); - - // compute the probability of going to the right direction - uint32_t east_probability = delta_x * (max_uint32_t_val / (delta_x + delta_y)); - - TurnModelRouting::Direction selected_direction = TurnModelRouting::Direction::INVALID; - - if (hash_val < east_probability) { // sometimes turn right - selected_direction = TurnModelRouting::Direction::RIGHT; - } else { // if turning right was rejected, take the other option (north or south) - selected_direction = select_direction_other_than(legal_directions, TurnModelRouting::Direction::RIGHT); - } - - return selected_direction; -} - bool WestFirstRouting::is_turn_legal(const std::array, 3>& noc_routers) const { const auto [x1, y1, z1] = noc_routers[0].get().get_router_physical_location(); const auto [x2, y2, z2] = noc_routers[1].get().get_router_physical_location(); diff --git a/vpr/src/noc/west_first_routing.h b/vpr/src/noc/west_first_routing.h index 17b3fa9cc74..f37adbbe35b 100644 --- a/vpr/src/noc/west_first_routing.h +++ b/vpr/src/noc/west_first_routing.h @@ -40,32 +40,6 @@ class WestFirstRouting : public TurnModelRouting { NocRouterId dst_router_id, const NocStorage& noc_model) override; - /** - * @brief Selects a direction from legal directions. The traffic flow - * travels in that direction. When there are both horizontal and - * vertical directions available, this method selects one of the available - * directions randomly. The chance of horizontal and vertical directions - * are weighted by the horizontal and vertical distance between the - * current NoC router and the destination router. - * - * @param legal_directions Legal directions that the traffic flow can follow. - * Legal directions are usually a subset of all possible directions to ensure - * deadlock freedom. - * @param src_router_id A unique ID identifying the source NoC router. - * @param dst_router_id A unique ID identifying the destination NoC router. - * @param curr_router_id A unique ID identifying the current NoC router. - * @param noc_model A model of the NoC. This might be used by the derived class - * to determine the position of NoC routers. - * - * @return Direction The direction to travel next - */ - TurnModelRouting::Direction select_next_direction(const std::vector& legal_directions, - NocRouterId src_router_id, - NocRouterId dst_router_id, - NocRouterId curr_router_id, - NocTrafficFlowId traffic_flow_id, - const NocStorage& noc_model) override; - bool is_turn_legal(const std::array, 3>& noc_routers) const override; }; From ba20efcbbea92a38e9256bebbd4aae89e526babd Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Tue, 9 Jul 2024 14:18:51 -0400 Subject: [PATCH 12/39] 3d support in OddEvenRouting::is_turn_legal() --- vpr/src/noc/odd_even_routing.cpp | 104 ++++++++++--------------------- vpr/src/noc/odd_even_routing.h | 7 --- 2 files changed, 33 insertions(+), 78 deletions(-) diff --git a/vpr/src/noc/odd_even_routing.cpp b/vpr/src/noc/odd_even_routing.cpp index d9f08ab2725..3d864bf35a7 100644 --- a/vpr/src/noc/odd_even_routing.cpp +++ b/vpr/src/noc/odd_even_routing.cpp @@ -97,56 +97,6 @@ const std::vector& OddEvenRouting::get_legal_direct return returned_legal_direction; } -TurnModelRouting::Direction OddEvenRouting::select_next_direction(const std::vector& legal_directions, - NocRouterId src_router_id, - NocRouterId dst_router_id, - NocRouterId curr_router_id, - NocTrafficFlowId traffic_flow_id, - const NocStorage& noc_model) { - // if there is only one legal direction, take it - if (legal_directions.size() == 1) { - return legal_directions[0]; - } - - // get current and destination NoC routers - const auto& curr_router = noc_model.get_single_noc_router(curr_router_id); - const auto& dst_router = noc_model.get_single_noc_router(dst_router_id); - - // get the position of current and destination NoC routers - const auto curr_router_pos = curr_router.get_router_physical_location(); - const auto dst_router_pos = dst_router.get_router_physical_location(); - - /* get_legal_directions() proposes legal directions for minimal routing. - * Therefore, if the function reaches this point, there are two available - * directions: a vertical (N/S) and a horizontal (W/E) direction. - * The direction is chosen based on the distance to the destination - * in each co-ordinate. - */ - - // compute the hash value - uint32_t hash_val = get_hash_value(src_router_id, dst_router_id, curr_router_id, traffic_flow_id); - // get the maximum value that can be represented by size_t - const uint32_t max_uint32_t_val = std::numeric_limits::max(); - - // get the distance from the current router to the destination in each coordination - int delta_x = abs(dst_router_pos.x - curr_router_pos.x); - int delta_y = abs(dst_router_pos.y - curr_router_pos.y); - - // compute the probability of choosing the vertical direction - uint32_t vertical_probability = delta_y * (max_uint32_t_val / (delta_x + delta_y)); - - TurnModelRouting::Direction selected_direction = TurnModelRouting::Direction::INVALID; - - // choose whether move vertically or horizontally - if (hash_val < vertical_probability) { - selected_direction = select_y_direction(legal_directions); - } else { - selected_direction = select_x_direction(legal_directions); - } - - return selected_direction; -} - bool OddEvenRouting::is_odd(int number) { return (number % 2) == 1; } @@ -156,6 +106,14 @@ bool OddEvenRouting::is_even(int number) { } bool OddEvenRouting::is_turn_legal(const std::array, 3>& noc_routers) const { + const auto [x1, y1, z1] = noc_routers[0].get().get_router_physical_location(); + const auto [x2, y2, z2] = noc_routers[1].get().get_router_physical_location(); + const auto [x3, y3, z3] = noc_routers[2].get().get_router_physical_location(); + + // check if the given routers can be traversed one after another + VTR_ASSERT(vtr::exactly_k_conditions(2, x1 == x2, y1 == y2, z1 == z2)); + VTR_ASSERT(vtr::exactly_k_conditions(2, x2 == x3, y2 == y3, z2 == z3)); + // used to access NoC compressed grid const auto& place_ctx = g_vpr_ctx.placement(); // used to get NoC logical block type @@ -165,19 +123,6 @@ bool OddEvenRouting::is_turn_legal(const std::array YZ turns at a router + * located in an even yz-place. */ + if (is_even(compressed_2_loc.x)) { + if (x2 > x1 && (y3 != y2 || z3 != z2)) { + return false; + } + } + + /* A packet is not allowed to take any of the YZ ---> X- turns at a router + * located in an odd yz-plane. */ if (is_odd(compressed_2_loc.x)) { - if (y2 != y1 && x3 < x2) { - return false; + if ((y1 != y2 || z1 != z2) && x2 < x1) { + return false; + } + } + + + // check if the turn is compatible with odd-even routing algorithm turn restrictions + if (is_odd(compressed_2_loc.y)) { + if ((z2 > z1 && y3 < y2) || (z2 < z1 && y3 < y2)) { + return false; } - } else { // even column - if (x2 > x1 && y2 != y3) { - return false; + } else { // y is even + if ((y2 > y1 && z3 > z2) || (y2 > y1 && z3 < z2)) { + return false; } } diff --git a/vpr/src/noc/odd_even_routing.h b/vpr/src/noc/odd_even_routing.h index deaf67f9c10..e75280146df 100644 --- a/vpr/src/noc/odd_even_routing.h +++ b/vpr/src/noc/odd_even_routing.h @@ -29,13 +29,6 @@ class OddEvenRouting : public TurnModelRouting{ NocRouterId dst_router_id, const NocStorage& noc_model) override; - TurnModelRouting::Direction select_next_direction(const std::vector& legal_directions, - NocRouterId src_router_id, - NocRouterId dst_router_id, - NocRouterId curr_router_id, - NocTrafficFlowId traffic_flow_id, - const NocStorage& noc_model) override; - bool is_turn_legal(const std::array, 3>& noc_routers) const override; /** From d1df10819300860a432336b89e5113b547a30681 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Tue, 9 Jul 2024 14:40:17 -0400 Subject: [PATCH 13/39] rename directions --- vpr/src/noc/negative_first_routing.cpp | 12 +++++------ vpr/src/noc/north_last_routing.cpp | 12 +++++------ vpr/src/noc/odd_even_routing.cpp | 30 ++++++++++---------------- vpr/src/noc/turn_model_routing.cpp | 14 ++++++------ vpr/src/noc/turn_model_routing.h | 12 +++++------ vpr/src/noc/west_first_routing.cpp | 12 +++++------ vpr/src/noc/xy_routing.cpp | 12 +++++------ vpr/src/noc/xy_routing.h | 8 +++---- 8 files changed, 52 insertions(+), 60 deletions(-) diff --git a/vpr/src/noc/negative_first_routing.cpp b/vpr/src/noc/negative_first_routing.cpp index 49d29d124b3..aee5fbcbea0 100644 --- a/vpr/src/noc/negative_first_routing.cpp +++ b/vpr/src/noc/negative_first_routing.cpp @@ -29,17 +29,17 @@ const std::vector& NegativeFirstRouting::get_legal_ // check whether moving west keeps us on a minimal route if (dst_router_pos.x < curr_router_pos.x) { - returned_legal_direction.push_back(TurnModelRouting::Direction::LEFT); + returned_legal_direction.push_back(TurnModelRouting::Direction::WEST); } // check whether moving south keeps us on a minimal route if (dst_router_pos.y < curr_router_pos.y) { - returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); + returned_legal_direction.push_back(TurnModelRouting::Direction::SOUTH); } // check whether moving below keeps us on a minimal route if (dst_router_pos.layer_num < curr_router_pos.layer_num) { - returned_legal_direction.push_back(TurnModelRouting::Direction::BELOW); + returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); } // if at least one of the negative directions is legal, @@ -55,17 +55,17 @@ const std::vector& NegativeFirstRouting::get_legal_ // check whether moving east keeps us on a minimal route if (dst_router_pos.x > curr_router_pos.x) { - returned_legal_direction.push_back(TurnModelRouting::Direction::RIGHT); + returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); } // check whether moving north keeps us on a minimal route if (dst_router_pos.y > curr_router_pos.y) { - returned_legal_direction.push_back(TurnModelRouting::Direction::UP); + returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); } // check whether moving above keeps us on a minimal route if (dst_router_pos.layer_num > curr_router_pos.layer_num) { - returned_legal_direction.push_back(TurnModelRouting::Direction::ABOVE); + returned_legal_direction.push_back(TurnModelRouting::Direction::UP); } return returned_legal_direction; diff --git a/vpr/src/noc/north_last_routing.cpp b/vpr/src/noc/north_last_routing.cpp index b417944f68c..15e8c64a441 100644 --- a/vpr/src/noc/north_last_routing.cpp +++ b/vpr/src/noc/north_last_routing.cpp @@ -32,29 +32,29 @@ const std::vector& NorthLastRouting::get_legal_dire // check if the destination is at the west/east of the current router if (dst_router_pos.x < curr_router_pos.x) { - returned_legal_direction.push_back(TurnModelRouting::Direction::LEFT); + returned_legal_direction.push_back(TurnModelRouting::Direction::WEST); } else if (dst_router_pos.x > curr_router_pos.x) { - returned_legal_direction.push_back(TurnModelRouting::Direction::RIGHT); + returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); } // check if the destination router is at the south of the current router if (dst_router_pos.y < curr_router_pos.y) { - returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); + returned_legal_direction.push_back(TurnModelRouting::Direction::SOUTH); } // check if the destination router is at the layer below the current router if (dst_router_pos.layer_num < curr_router_pos.layer_num) { - returned_legal_direction.push_back(TurnModelRouting::Direction::BELOW); + returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); } // consider north and up only when none of other directions are legal if (returned_legal_direction.empty()) { if (dst_router_pos.y > curr_router_pos.y) { - returned_legal_direction.push_back(TurnModelRouting::Direction::UP); + returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); } if (dst_router_pos.layer_num > curr_router_pos.layer_num) { - returned_legal_direction.push_back(TurnModelRouting::Direction::ABOVE); + returned_legal_direction.push_back(TurnModelRouting::Direction::UP); } } diff --git a/vpr/src/noc/odd_even_routing.cpp b/vpr/src/noc/odd_even_routing.cpp index 3d864bf35a7..d61e337a41a 100644 --- a/vpr/src/noc/odd_even_routing.cpp +++ b/vpr/src/noc/odd_even_routing.cpp @@ -48,6 +48,8 @@ const std::vector& OddEvenRouting::get_legal_direct // calculate the distance between the current router and the destination const int diff_x = compressed_dst_loc.x - compressed_curr_loc.x; const int diff_y = compressed_dst_loc.y - compressed_curr_loc.y; + const int diff_z = compressed_dst_loc.layer_num - compressed_curr_loc.layer_num; + /* The implementation below is a carbon copy of the Fig. 2 in the following paper * Chiu GM. The odd-even turn model for adaptive routing. @@ -57,38 +59,38 @@ const std::vector& OddEvenRouting::get_legal_direct */ if (diff_x == 0) { // the same column as the destination. Only north or south are allowed if (diff_y > 0) { - returned_legal_direction.push_back(TurnModelRouting::Direction::UP); + returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); } else { - returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); + returned_legal_direction.push_back(TurnModelRouting::Direction::SOUTH); } } else { // currently in a different column than the destination if (diff_x > 0) { // eastbound message if (diff_y == 0) { // already in the same row as the destination. Just move to the east - returned_legal_direction.push_back(TurnModelRouting::Direction::RIGHT); + returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); } else { /* Since EN and ES turns are forbidden in even columns, we move along the vertical * direction only in we are in an odd column. */ if (is_odd(compressed_curr_loc.x) || compressed_curr_loc.x == compressed_src_loc.x) { if (diff_y > 0) { - returned_legal_direction.push_back(TurnModelRouting::Direction::UP); + returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); } else { - returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); + returned_legal_direction.push_back(TurnModelRouting::Direction::SOUTH); } } // the destination column is odd and there are more than 1 column left to destination if (is_odd(compressed_dst_loc.x) || diff_x != 1) { - returned_legal_direction.push_back(TurnModelRouting::Direction::RIGHT); + returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); } } } else { // westbound message - returned_legal_direction.push_back(TurnModelRouting::Direction::LEFT); + returned_legal_direction.push_back(TurnModelRouting::Direction::WEST); /* Since NW and SW turns are forbidden in odd columns, we allow * moving along vertical axis only in even columns */ if (is_even(compressed_curr_loc.x)) { if (diff_y > 0) { - returned_legal_direction.push_back(TurnModelRouting::Direction::UP); + returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); } else { - returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); + returned_legal_direction.push_back(TurnModelRouting::Direction::SOUTH); } } } @@ -170,13 +172,3 @@ bool OddEvenRouting::is_turn_legal(const std::array curr_router_position.x) { found_next_router = true; } break; - case TurnModelRouting::Direction::UP: + case TurnModelRouting::Direction::NORTH: if (next_router_position.y > curr_router_position.y) { found_next_router = true; } break; - case TurnModelRouting::Direction::DOWN: + case TurnModelRouting::Direction::SOUTH: if (next_router_position.y < curr_router_position.y) { found_next_router = true; } @@ -200,7 +200,7 @@ uint32_t TurnModelRouting::murmur3_32(const std::vector& key, uint32_t TurnModelRouting::Direction TurnModelRouting::select_y_direction(const std::vector& directions) { // iterate over the given iterations and return the first vertical one for (const auto& direction : directions) { - if (direction == TurnModelRouting::Direction::DOWN || direction == TurnModelRouting::Direction::UP) { + if (direction == TurnModelRouting::Direction::SOUTH || direction == TurnModelRouting::Direction::NORTH) { return direction; } } @@ -212,7 +212,7 @@ TurnModelRouting::Direction TurnModelRouting::select_y_direction(const std::vect TurnModelRouting::Direction TurnModelRouting::select_x_direction(const std::vector& directions) { // iterate over the given iterations and return the first horizontal one for (const auto& direction : directions) { - if (direction == TurnModelRouting::Direction::RIGHT || direction == TurnModelRouting::Direction::LEFT) { + if (direction == TurnModelRouting::Direction::EAST || direction == TurnModelRouting::Direction::WEST) { return direction; } } @@ -224,7 +224,7 @@ TurnModelRouting::Direction TurnModelRouting::select_x_direction(const std::vect TurnModelRouting::Direction TurnModelRouting::select_z_direction(const std::vector& directions) { // iterate over the given iterations and return the first one along the z axis for (const auto& direction : directions) { - if (direction == TurnModelRouting::Direction::ABOVE || direction == TurnModelRouting::Direction::BELOW) { + if (direction == TurnModelRouting::Direction::UP || direction == TurnModelRouting::Direction::DOWN) { return direction; } } diff --git a/vpr/src/noc/turn_model_routing.h b/vpr/src/noc/turn_model_routing.h index 0977c4fabc9..bd95b349648 100644 --- a/vpr/src/noc/turn_model_routing.h +++ b/vpr/src/noc/turn_model_routing.h @@ -109,12 +109,12 @@ class TurnModelRouting : public NocRouting { * choose to travel. */ enum class Direction { - LEFT, /*!< Moving towards the negative X-axis*/ - RIGHT, /*!< Moving towards the positive X-axis*/ - UP, /*!< Moving towards the positive Y-axis*/ - DOWN, /*!< Moving towards the negative Y-axis*/ - ABOVE, /*!< Moving towards the positive Z-axis*/ - BELOW, /*!< Moving towards the negative Z-axis*/ + WEST, /*!< Moving towards the negative X-axis*/ + EAST, /*!< Moving towards the positive X-axis*/ + NORTH, /*!< Moving towards the positive Y-axis*/ + SOUTH, /*!< Moving towards the negative Y-axis*/ + UP, /*!< Moving towards the positive Z-axis*/ + DOWN, /*!< Moving towards the negative Z-axis*/ N_DIRECTIONS, INVALID /*!< Invalid direction*/ }; diff --git a/vpr/src/noc/west_first_routing.cpp b/vpr/src/noc/west_first_routing.cpp index 80185c58bf4..30a97ee315e 100644 --- a/vpr/src/noc/west_first_routing.cpp +++ b/vpr/src/noc/west_first_routing.cpp @@ -25,26 +25,26 @@ const std::vector& WestFirstRouting::get_legal_dire */ if (dst_router_pos.x < curr_router_pos.x) { - returned_legal_direction.push_back(TurnModelRouting::Direction::LEFT); + returned_legal_direction.push_back(TurnModelRouting::Direction::WEST); } if (dst_router_pos.y < curr_router_pos.y) { - returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); + returned_legal_direction.push_back(TurnModelRouting::Direction::SOUTH); } if (returned_legal_direction.empty()) { if (dst_router_pos.x > curr_router_pos.x) { - returned_legal_direction.push_back(TurnModelRouting::Direction::RIGHT); + returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); } if (dst_router_pos.y > curr_router_pos.y) { - returned_legal_direction.push_back(TurnModelRouting::Direction::UP); + returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); } if (dst_router_pos.layer_num > curr_router_pos.layer_num) { - returned_legal_direction.push_back(TurnModelRouting::Direction::ABOVE); + returned_legal_direction.push_back(TurnModelRouting::Direction::UP); } else if (dst_router_pos.layer_num < curr_router_pos.layer_num) { - returned_legal_direction.push_back(TurnModelRouting::Direction::BELOW); + returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); } } diff --git a/vpr/src/noc/xy_routing.cpp b/vpr/src/noc/xy_routing.cpp index 0c6bff655b2..2b29de94466 100644 --- a/vpr/src/noc/xy_routing.cpp +++ b/vpr/src/noc/xy_routing.cpp @@ -25,17 +25,17 @@ const std::vector& XYRouting::get_legal_directions( */ if (dst_router_pos.x > curr_router_pos.x) { - return right_direction; + return east_direction; } else if (dst_router_pos.x < curr_router_pos.x) { - return left_direction; + return west_direction; } else if (dst_router_pos.y > curr_router_pos.y) { - return up_direction; + return north_direction; } else if (dst_router_pos.y < curr_router_pos.y) { - return down_direction; + return south_direction; } else if (dst_router_pos.layer_num > curr_router_pos.layer_num) { - return above_direction; + return up_direction; } else if (dst_router_pos.layer_num < curr_router_pos.layer_num) { - return below_direction; + return down_direction; } else { return no_direction; } diff --git a/vpr/src/noc/xy_routing.h b/vpr/src/noc/xy_routing.h index f49b8bca634..e0f9cb6ce59 100644 --- a/vpr/src/noc/xy_routing.h +++ b/vpr/src/noc/xy_routing.h @@ -108,12 +108,12 @@ class XYRouting : public TurnModelRouting { bool is_turn_legal(const std::array, 3>& noc_routers) const override; private: - const std::vector right_direction {TurnModelRouting::Direction::RIGHT}; - const std::vector left_direction {TurnModelRouting::Direction::LEFT}; + const std::vector east_direction{TurnModelRouting::Direction::EAST}; + const std::vector west_direction {TurnModelRouting::Direction::WEST}; + const std::vector north_direction {TurnModelRouting::Direction::NORTH}; + const std::vector south_direction {TurnModelRouting::Direction::SOUTH}; const std::vector up_direction {TurnModelRouting::Direction::UP}; const std::vector down_direction {TurnModelRouting::Direction::DOWN}; - const std::vector above_direction {TurnModelRouting::Direction::ABOVE}; - const std::vector below_direction {TurnModelRouting::Direction::BELOW}; const std::vector no_direction; }; From adb503cbff701b53d3fbcb2ff7132104054075ef Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Tue, 9 Jul 2024 14:48:03 -0400 Subject: [PATCH 14/39] Update TurnModelRouting::move_to_next_router() for 3d support --- vpr/src/noc/turn_model_routing.cpp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/vpr/src/noc/turn_model_routing.cpp b/vpr/src/noc/turn_model_routing.cpp index cfc768444ca..a27a4d2b8ef 100644 --- a/vpr/src/noc/turn_model_routing.cpp +++ b/vpr/src/noc/turn_model_routing.cpp @@ -98,19 +98,19 @@ NocLinkId TurnModelRouting::move_to_next_router(NocRouterId& curr_router_id, bool visited_next_router = false; // get all the outgoing links for the current router - const auto& router_connections = noc_model.get_noc_router_outgoing_links(curr_router_id); + const std::vector& router_connections = noc_model.get_noc_router_outgoing_links(curr_router_id); // go through each outgoing link and determine whether the link leads towards the intended route direction - for (auto connecting_link : router_connections) { + for (NocLinkId connecting_link : router_connections) { // get the current outgoing link which is being processed const NocLink& curr_outgoing_link = noc_model.get_single_noc_link(connecting_link); // get the next router that we will visit if we travel across the current link - auto next_router_id = curr_outgoing_link.get_sink_router(); + NocRouterId next_router_id = curr_outgoing_link.get_sink_router(); const NocRouter& next_router = noc_model.get_single_noc_router(next_router_id); // get the coordinates of the next router - auto next_router_position = next_router.get_router_physical_location(); + t_physical_tile_loc next_router_position = next_router.get_router_physical_location(); /* Using the position of the next router we will visit if we take the current link, * determine if the travel direction through the link matches @@ -138,6 +138,16 @@ NocLinkId TurnModelRouting::move_to_next_router(NocRouterId& curr_router_id, found_next_router = true; } break; + case TurnModelRouting::Direction::UP: + if (next_router_position.layer_num > curr_router_position.layer_num) { + found_next_router = true; + } + break; + case TurnModelRouting::Direction::DOWN: + if (next_router_position.layer_num < curr_router_position.layer_num) { + found_next_router = true; + } + break; default: break; } From 59485452776dad0cee2854036e8bbe0066eb0c39 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Wed, 10 Jul 2024 13:12:17 -0400 Subject: [PATCH 15/39] temp commit before changing the get_legal_directions()' signature --- vpr/src/noc/odd_even_routing.cpp | 49 ++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/vpr/src/noc/odd_even_routing.cpp b/vpr/src/noc/odd_even_routing.cpp index d61e337a41a..294a2681380 100644 --- a/vpr/src/noc/odd_even_routing.cpp +++ b/vpr/src/noc/odd_even_routing.cpp @@ -50,6 +50,55 @@ const std::vector& OddEvenRouting::get_legal_direct const int diff_y = compressed_dst_loc.y - compressed_curr_loc.y; const int diff_z = compressed_dst_loc.layer_num - compressed_curr_loc.layer_num; + if (diff_x > 0) { + if (is_even(compressed_curr_loc.x) || (diff_y == 0 && diff_z == 0)) { + returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); + } + } else if (diff_x < 0) { + if (is_even(compressed_curr_loc.x) || + (compressed_curr_loc.y == compressed_src_loc.y && compressed_curr_loc.layer_num == compressed_src_loc.layer_num)) { + returned_legal_direction.push_back(TurnModelRouting::Direction::WEST); + } + } + + + + if (diff_y == 0) { // the same column as the destination. Only north or south are allowed + if (diff_z > 0) { + returned_legal_direction.push_back(TurnModelRouting::Direction::UP); + } else { + returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); + } + } else if (diff_y > 0) { // eastbound message + if (diff_z == 0) { // already in the same row as the destination. Just move to the east + returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); + } else { + /* Since EN and ES turns are forbidden in even columns, we move along the vertical + * direction only in we are in an odd column. */ + if (is_odd(compressed_curr_loc.y) || compressed_curr_loc.y == compressed_src_loc.y) { + if (diff_z > 0) { + returned_legal_direction.push_back(TurnModelRouting::Direction::UP); + } else { + returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); + } + } + // the destination column is odd and there are more than 1 column left to destination + if (is_odd(compressed_dst_loc.y) || diff_y > 1) { + returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); + } + } + } else { // westbound message + returned_legal_direction.push_back(TurnModelRouting::Direction::SOUTH); + /* Since NW and SW turns are forbidden in odd columns, we allow + * moving along vertical axis only in even columns */ + if (is_even(compressed_curr_loc.y)) { + if (diff_z > 0) { + returned_legal_direction.push_back(TurnModelRouting::Direction::UP); + } else { + returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); + } + } + } /* The implementation below is a carbon copy of the Fig. 2 in the following paper * Chiu GM. The odd-even turn model for adaptive routing. From 29ddd6ebc2095540d115bf6e90d06d38e1948c2b Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Wed, 10 Jul 2024 19:47:45 -0400 Subject: [PATCH 16/39] add prev_dir argument to get_legal_directions() --- vpr/src/noc/negative_first_routing.cpp | 1 + vpr/src/noc/negative_first_routing.h | 1 + vpr/src/noc/north_last_routing.cpp | 1 + vpr/src/noc/north_last_routing.h | 1 + vpr/src/noc/odd_even_routing.cpp | 1 + vpr/src/noc/odd_even_routing.h | 1 + vpr/src/noc/turn_model_routing.cpp | 20 ++++++++++++-------- vpr/src/noc/turn_model_routing.h | 1 + vpr/src/noc/west_first_routing.cpp | 1 + vpr/src/noc/west_first_routing.h | 1 + vpr/src/noc/xy_routing.cpp | 1 + vpr/src/noc/xy_routing.h | 1 + 12 files changed, 23 insertions(+), 8 deletions(-) diff --git a/vpr/src/noc/negative_first_routing.cpp b/vpr/src/noc/negative_first_routing.cpp index aee5fbcbea0..feba4de24e7 100644 --- a/vpr/src/noc/negative_first_routing.cpp +++ b/vpr/src/noc/negative_first_routing.cpp @@ -6,6 +6,7 @@ NegativeFirstRouting::~NegativeFirstRouting() = default; const std::vector& NegativeFirstRouting::get_legal_directions(NocRouterId /*src_router_id*/, NocRouterId curr_router_id, NocRouterId dst_router_id, + TurnModelRouting::Direction /*prev_dir*/, const NocStorage& noc_model) { // get current and destination NoC routers const auto& curr_router = noc_model.get_single_noc_router(curr_router_id); diff --git a/vpr/src/noc/negative_first_routing.h b/vpr/src/noc/negative_first_routing.h index 40c4dd211c5..a8942ffa33f 100644 --- a/vpr/src/noc/negative_first_routing.h +++ b/vpr/src/noc/negative_first_routing.h @@ -38,6 +38,7 @@ class NegativeFirstRouting : public TurnModelRouting { const std::vector& get_legal_directions(NocRouterId src_router_id, NocRouterId curr_router_id, NocRouterId dst_router_id, + TurnModelRouting::Direction prev_dir, const NocStorage& noc_model) override; bool is_turn_legal(const std::array, 3>& noc_routers) const override; diff --git a/vpr/src/noc/north_last_routing.cpp b/vpr/src/noc/north_last_routing.cpp index 15e8c64a441..c239286bc83 100644 --- a/vpr/src/noc/north_last_routing.cpp +++ b/vpr/src/noc/north_last_routing.cpp @@ -6,6 +6,7 @@ NorthLastRouting::~NorthLastRouting() = default; const std::vector& NorthLastRouting::get_legal_directions(NocRouterId /*src_router_id*/, NocRouterId curr_router_id, NocRouterId dst_router_id, + TurnModelRouting::Direction /*prev_dir*/, const NocStorage& noc_model) { // get current and destination NoC routers const auto& curr_router = noc_model.get_single_noc_router(curr_router_id); diff --git a/vpr/src/noc/north_last_routing.h b/vpr/src/noc/north_last_routing.h index 5bb3422233e..d294db15499 100644 --- a/vpr/src/noc/north_last_routing.h +++ b/vpr/src/noc/north_last_routing.h @@ -39,6 +39,7 @@ class NorthLastRouting : public TurnModelRouting { const std::vector& get_legal_directions(NocRouterId src_router_id, NocRouterId curr_router_id, NocRouterId dst_router_id, + TurnModelRouting::Direction prev_dir, const NocStorage& noc_model) override; bool is_turn_legal(const std::array, 3>& noc_routers) const override; diff --git a/vpr/src/noc/odd_even_routing.cpp b/vpr/src/noc/odd_even_routing.cpp index 294a2681380..ebcb93b634b 100644 --- a/vpr/src/noc/odd_even_routing.cpp +++ b/vpr/src/noc/odd_even_routing.cpp @@ -8,6 +8,7 @@ OddEvenRouting::~OddEvenRouting() = default; const std::vector& OddEvenRouting::get_legal_directions(NocRouterId src_router_id, NocRouterId curr_router_id, NocRouterId dst_router_id, + TurnModelRouting::Direction /*prev_dir*/, const NocStorage& noc_model) { // used to access NoC compressed grid auto& place_ctx = g_vpr_ctx.placement(); diff --git a/vpr/src/noc/odd_even_routing.h b/vpr/src/noc/odd_even_routing.h index e75280146df..d100a002599 100644 --- a/vpr/src/noc/odd_even_routing.h +++ b/vpr/src/noc/odd_even_routing.h @@ -27,6 +27,7 @@ class OddEvenRouting : public TurnModelRouting{ const std::vector& get_legal_directions(NocRouterId src_router_id, NocRouterId curr_router_id, NocRouterId dst_router_id, + TurnModelRouting::Direction prev_dir, const NocStorage& noc_model) override; bool is_turn_legal(const std::array, 3>& noc_routers) const override; diff --git a/vpr/src/noc/turn_model_routing.cpp b/vpr/src/noc/turn_model_routing.cpp index a27a4d2b8ef..39e3f80ab28 100644 --- a/vpr/src/noc/turn_model_routing.cpp +++ b/vpr/src/noc/turn_model_routing.cpp @@ -50,6 +50,9 @@ void TurnModelRouting::route_flow(NocRouterId src_router_id, */ std::unordered_set visited_routers; + // indicates the last direction taken in the route which is being formed. + TurnModelRouting::Direction prev_dir = TurnModelRouting::Direction::INVALID; + // The route is terminated when we reach at the destination router while (curr_router_id != dst_router_id) { // get the current router (the last one added to the route) @@ -59,20 +62,21 @@ void TurnModelRouting::route_flow(NocRouterId src_router_id, auto curr_router_pos = curr_router.get_router_physical_location(); // get all directions that moves us closer to the destination router - const auto legal_directions = get_legal_directions(src_router_id, curr_router_id, dst_router_id, noc_model); + const auto& legal_directions = get_legal_directions(src_router_id, curr_router_id, dst_router_id, prev_dir, noc_model); // select the next direction from the available options - auto next_step_direction = select_next_direction(legal_directions, - src_router_id, - dst_router_id, - curr_router_id, - traffic_flow_id, - noc_model); + TurnModelRouting::Direction next_step_direction = select_next_direction(legal_directions, + src_router_id, + dst_router_id, + curr_router_id, + traffic_flow_id, + noc_model); - auto next_link = move_to_next_router(curr_router_id, curr_router_pos, next_step_direction, visited_routers, noc_model); + NocLinkId next_link = move_to_next_router(curr_router_id, curr_router_pos, next_step_direction, visited_routers, noc_model); if (next_link) { flow_route.push_back(next_link); + prev_dir = next_step_direction; } else { VPR_FATAL_ERROR(VPR_ERROR_OTHER, "No route could be found from starting router with ID:'%d' " "and the destination router with ID:'%d' using the XY-Routing algorithm.", diff --git a/vpr/src/noc/turn_model_routing.h b/vpr/src/noc/turn_model_routing.h index bd95b349648..17ff14d17b8 100644 --- a/vpr/src/noc/turn_model_routing.h +++ b/vpr/src/noc/turn_model_routing.h @@ -229,6 +229,7 @@ class TurnModelRouting : public NocRouting { virtual const std::vector& get_legal_directions(NocRouterId src_router_id, NocRouterId curr_router_id, NocRouterId dst_router_id, + TurnModelRouting::Direction prev_dir, const NocStorage& noc_model) = 0; /** diff --git a/vpr/src/noc/west_first_routing.cpp b/vpr/src/noc/west_first_routing.cpp index 30a97ee315e..971e4c93409 100644 --- a/vpr/src/noc/west_first_routing.cpp +++ b/vpr/src/noc/west_first_routing.cpp @@ -5,6 +5,7 @@ WestFirstRouting::~WestFirstRouting() = default; const std::vector& WestFirstRouting::get_legal_directions(NocRouterId /*src_router_id*/, NocRouterId curr_router_id, NocRouterId dst_router_id, + TurnModelRouting::Direction /*prev_dir*/, const NocStorage& noc_model) { // get current and destination NoC routers const auto& curr_router = noc_model.get_single_noc_router(curr_router_id); diff --git a/vpr/src/noc/west_first_routing.h b/vpr/src/noc/west_first_routing.h index f37adbbe35b..0e6c7a75c9e 100644 --- a/vpr/src/noc/west_first_routing.h +++ b/vpr/src/noc/west_first_routing.h @@ -38,6 +38,7 @@ class WestFirstRouting : public TurnModelRouting { const std::vector& get_legal_directions(NocRouterId src_router_id, NocRouterId curr_router_id, NocRouterId dst_router_id, + TurnModelRouting::Direction prev_dir, const NocStorage& noc_model) override; bool is_turn_legal(const std::array, 3>& noc_routers) const override; diff --git a/vpr/src/noc/xy_routing.cpp b/vpr/src/noc/xy_routing.cpp index 2b29de94466..47813ec768d 100644 --- a/vpr/src/noc/xy_routing.cpp +++ b/vpr/src/noc/xy_routing.cpp @@ -9,6 +9,7 @@ XYRouting::~XYRouting() = default; const std::vector& XYRouting::get_legal_directions(NocRouterId /*src_router_id*/, NocRouterId curr_router_id, NocRouterId dst_router_id, + TurnModelRouting::Direction /*prev_dir*/, const NocStorage& noc_model) { // get current and destination NoC routers const auto& curr_router = noc_model.get_single_noc_router(curr_router_id); diff --git a/vpr/src/noc/xy_routing.h b/vpr/src/noc/xy_routing.h index e0f9cb6ce59..d9cd447c425 100644 --- a/vpr/src/noc/xy_routing.h +++ b/vpr/src/noc/xy_routing.h @@ -96,6 +96,7 @@ class XYRouting : public TurnModelRouting { const std::vector& get_legal_directions(NocRouterId src_router_id, NocRouterId curr_router_id, NocRouterId dst_router_id, + TurnModelRouting::Direction prev_dir, const NocStorage& noc_model) override; TurnModelRouting::Direction select_next_direction(const std::vector& legal_directions, From 381ff615f400cadc6150213c178fb7a40016665a Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Wed, 10 Jul 2024 19:57:25 -0400 Subject: [PATCH 17/39] add is_noc_3d() method --- vpr/src/noc/noc_storage.cpp | 11 +++++++++++ vpr/src/noc/noc_storage.h | 13 +++++++++++++ 2 files changed, 24 insertions(+) diff --git a/vpr/src/noc/noc_storage.cpp b/vpr/src/noc/noc_storage.cpp index f3fe939eecc..55d4e58ff3e 100644 --- a/vpr/src/noc/noc_storage.cpp +++ b/vpr/src/noc/noc_storage.cpp @@ -99,6 +99,10 @@ NocRouterId NocStorage::get_router_at_grid_location(const t_pl_loc& hard_router_ return hard_router_block->second; } +bool NocStorage::is_noc_3d() const { + return multi_layer_noc_; +} + // setters for the NoC void NocStorage::add_router(int id, @@ -240,6 +244,13 @@ void NocStorage::finished_building_noc() { return a.get_latency() != b.get_latency(); }); detailed_link_latency_ = (link_latency_it != link_storage.end()); + + auto router_layer_it = std::adjacent_find(router_storage.begin(), router_storage.end(), + [](const NocRouter& a, const NocRouter& b) { + return a.get_router_layer_position() != b.get_router_layer_position(); + }); + + multi_layer_noc_ = (router_layer_it != router_storage.end()); } void NocStorage::clear_noc() { diff --git a/vpr/src/noc/noc_storage.h b/vpr/src/noc/noc_storage.h index bbefe9b4fa9..dbaa9cfdb5b 100644 --- a/vpr/src/noc/noc_storage.h +++ b/vpr/src/noc/noc_storage.h @@ -139,6 +139,13 @@ class NocStorage { */ bool detailed_link_latency_; + /** + * @brief Indicates whether the NoC is 3D or 2D. + * A 3D NoC has routers in at least two different layers. + * In a 3D FPGA architecture, the NoC is not necessarily 3D. + */ + bool multi_layer_noc_; + /** * @brief A constant reference to this vector is returned by get_noc_links(...). * This is used to avoid memory allocation whenever get_noc_links(...) is called. @@ -351,6 +358,12 @@ class NocStorage { */ NocRouterId get_router_at_grid_location(const t_pl_loc& hard_router_location) const; + /** + * @brief Indicates whether the NoC is 3D. + * @return True if there are NoC routers in different layers. + */ + bool is_noc_3d() const; + // setters for the NoC /** From 2de853ec84fca4bb280cfc74c48405ecb12e0388 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Sun, 14 Jul 2024 16:43:29 -0400 Subject: [PATCH 18/39] add noc_is_3d arg to is_turn_legal() --- vpr/src/noc/negative_first_routing.cpp | 15 +++-- vpr/src/noc/negative_first_routing.h | 3 +- vpr/src/noc/north_last_routing.cpp | 16 ++++-- vpr/src/noc/north_last_routing.h | 3 +- vpr/src/noc/odd_even_routing.cpp | 54 +++++++++++------- vpr/src/noc/odd_even_routing.h | 3 +- vpr/src/noc/turn_model_routing.cpp | 4 +- vpr/src/noc/turn_model_routing.h | 4 +- vpr/src/noc/west_first_routing.cpp | 76 +++++++++++++++++--------- vpr/src/noc/west_first_routing.h | 3 +- vpr/src/noc/xy_routing.cpp | 3 +- vpr/src/noc/xy_routing.h | 3 +- 12 files changed, 125 insertions(+), 62 deletions(-) diff --git a/vpr/src/noc/negative_first_routing.cpp b/vpr/src/noc/negative_first_routing.cpp index feba4de24e7..0413d2746d4 100644 --- a/vpr/src/noc/negative_first_routing.cpp +++ b/vpr/src/noc/negative_first_routing.cpp @@ -72,7 +72,8 @@ const std::vector& NegativeFirstRouting::get_legal_ return returned_legal_direction; } -bool NegativeFirstRouting::is_turn_legal(const std::array, 3>& noc_routers) const { +bool NegativeFirstRouting::is_turn_legal(const std::array, 3>& noc_routers, + bool noc_is_3d) const { const auto[x1, y1, z1] = noc_routers[0].get().get_router_physical_location(); const auto[x2, y2, z2] = noc_routers[1].get().get_router_physical_location(); const auto[x3, y3, z3] = noc_routers[2].get().get_router_physical_location(); @@ -87,9 +88,15 @@ bool NegativeFirstRouting::is_turn_legal(const std::array x1 && y3 < y2) || (y2 > y1 && x3 < x2) || (z2 > z1 && x3 < x2) || - (x2 > x1 && z3 < z2) || (z2 > z1 && y3 < y2) || (y2 > y1 && z3 < z2)) { - return false; + if (noc_is_3d) { + if ((x2 > x1 && y3 < y2) || (y2 > y1 && x3 < x2) || (z2 > z1 && x3 < x2) || + (x2 > x1 && z3 < z2) || (z2 > z1 && y3 < y2) || (y2 > y1 && z3 < z2)) { + return false; + } + } else { + if ((x2 > x1 && y3 < y2) || (y2 > y1 && x3 < x2)) { + return false; + } } return true; diff --git a/vpr/src/noc/negative_first_routing.h b/vpr/src/noc/negative_first_routing.h index a8942ffa33f..2d165329e74 100644 --- a/vpr/src/noc/negative_first_routing.h +++ b/vpr/src/noc/negative_first_routing.h @@ -41,7 +41,8 @@ class NegativeFirstRouting : public TurnModelRouting { TurnModelRouting::Direction prev_dir, const NocStorage& noc_model) override; - bool is_turn_legal(const std::array, 3>& noc_routers) const override; + bool is_turn_legal(const std::array, 3>& noc_routers, + bool noc_is_3d) const override; }; #endif //VTR_NEGATIVE_FIRST_ROUTING_H diff --git a/vpr/src/noc/north_last_routing.cpp b/vpr/src/noc/north_last_routing.cpp index c239286bc83..0010601e8f7 100644 --- a/vpr/src/noc/north_last_routing.cpp +++ b/vpr/src/noc/north_last_routing.cpp @@ -62,7 +62,8 @@ const std::vector& NorthLastRouting::get_legal_dire return returned_legal_direction; } -bool NorthLastRouting::is_turn_legal(const std::array, 3>& noc_routers) const { +bool NorthLastRouting::is_turn_legal(const std::array, 3>& noc_routers, + bool noc_is_3d) const { const auto [x1, y1, z1] = noc_routers[0].get().get_router_physical_location(); const auto [x2, y2, z2] = noc_routers[1].get().get_router_physical_location(); const auto [x3, y3, z3] = noc_routers[2].get().get_router_physical_location(); @@ -78,10 +79,17 @@ bool NorthLastRouting::is_turn_legal(const std::array z1 && x3 < x2) || (z2 > z1 && x3 > x2) || (z2 > z1 && y3 < y2) || - (y2 > y1 && z3 < z2) || (y2 > y1 && x3 < x2) || (y2 > y1 && x3 > x2)) { - return false; + if (noc_is_3d) { + if ((z2 > z1 && x3 < x2) || (z2 > z1 && x3 > x2) || (z2 > z1 && y3 < y2) || + (y2 > y1 && z3 < z2) || (y2 > y1 && x3 < x2) || (y2 > y1 && x3 > x2)) { + return false; + } + } else { + if ((y2 > y1 && x3 > x2) || (y2 > y1 && x3 < x2)) { + return false; + } } + return true; } diff --git a/vpr/src/noc/north_last_routing.h b/vpr/src/noc/north_last_routing.h index d294db15499..806e7bdb472 100644 --- a/vpr/src/noc/north_last_routing.h +++ b/vpr/src/noc/north_last_routing.h @@ -42,7 +42,8 @@ class NorthLastRouting : public TurnModelRouting { TurnModelRouting::Direction prev_dir, const NocStorage& noc_model) override; - bool is_turn_legal(const std::array, 3>& noc_routers) const override; + bool is_turn_legal(const std::array, 3>& noc_routers, + bool noc_is_3d) const override; }; #endif //VTR_NORTH_LAST_ROUTING_H diff --git a/vpr/src/noc/odd_even_routing.cpp b/vpr/src/noc/odd_even_routing.cpp index ebcb93b634b..c5efba6aff3 100644 --- a/vpr/src/noc/odd_even_routing.cpp +++ b/vpr/src/noc/odd_even_routing.cpp @@ -157,7 +157,8 @@ bool OddEvenRouting::is_even(int number) { return (number % 2) == 0; } -bool OddEvenRouting::is_turn_legal(const std::array, 3>& noc_routers) const { +bool OddEvenRouting::is_turn_legal(const std::array, 3>& noc_routers, + bool noc_is_3d) const { const auto [x1, y1, z1] = noc_routers[0].get().get_router_physical_location(); const auto [x2, y2, z2] = noc_routers[1].get().get_router_physical_location(); const auto [x3, y3, z3] = noc_routers[2].get().get_router_physical_location(); @@ -187,36 +188,49 @@ bool OddEvenRouting::is_turn_legal(const std::array YZ turns at a router - * located in an even yz-place. */ - if (is_even(compressed_2_loc.x)) { - if (x2 > x1 && (y3 != y2 || z3 != z2)) { - return false; + if (noc_is_3d) { + /* A packet is not allowed to take any of the X+ --> YZ turns at a router + * located in an even yz-place. */ + if (is_even(compressed_2_loc.x)) { + if (x2 > x1 && (y3 != y2 || z3 != z2)) { + return false; + } } - } - /* A packet is not allowed to take any of the YZ ---> X- turns at a router - * located in an odd yz-plane. */ - if (is_odd(compressed_2_loc.x)) { - if ((y1 != y2 || z1 != z2) && x2 < x1) { - return false; + /* A packet is not allowed to take any of the YZ ---> X- turns at a router + * located in an odd yz-plane. */ + if (is_odd(compressed_2_loc.x)) { + if ((y1 != y2 || z1 != z2) && x2 < x1) { + return false; + } } - } - // check if the turn is compatible with odd-even routing algorithm turn restrictions - if (is_odd(compressed_2_loc.y)) { - if ((z2 > z1 && y3 < y2) || (z2 < z1 && y3 < y2)) { - return false; + // check if the turn is compatible with odd-even routing algorithm turn restrictions + if (is_odd(compressed_2_loc.y)) { + if ((z2 > z1 && y3 < y2) || (z2 < z1 && y3 < y2)) { + return false; + } + } else { // y is even + if ((y2 > y1 && z3 > z2) || (y2 > y1 && z3 < z2)) { + return false; + } } - } else { // y is even - if ((y2 > y1 && z3 > z2) || (y2 > y1 && z3 < z2)) { - return false; + } else { // 2D NoC + if (is_odd(compressed_2_loc.x)) { + if (y2 != y1 && x3 < x2) { + return false; + } + } else { // even column + if (x2 > x1 && y2 != y3) { + return false; + } } } diff --git a/vpr/src/noc/odd_even_routing.h b/vpr/src/noc/odd_even_routing.h index d100a002599..42772a8fd0c 100644 --- a/vpr/src/noc/odd_even_routing.h +++ b/vpr/src/noc/odd_even_routing.h @@ -30,7 +30,8 @@ class OddEvenRouting : public TurnModelRouting{ TurnModelRouting::Direction prev_dir, const NocStorage& noc_model) override; - bool is_turn_legal(const std::array, 3>& noc_routers) const override; + bool is_turn_legal(const std::array, 3>& noc_routers, + bool noc_is_3d) const override; /** * Checks whether the given umber is odd. diff --git a/vpr/src/noc/turn_model_routing.cpp b/vpr/src/noc/turn_model_routing.cpp index 39e3f80ab28..a25208a00ef 100644 --- a/vpr/src/noc/turn_model_routing.cpp +++ b/vpr/src/noc/turn_model_routing.cpp @@ -263,6 +263,8 @@ TurnModelRouting::Direction TurnModelRouting::select_direction_other_than(const std::vector> TurnModelRouting::get_all_illegal_turns(const NocStorage& noc_model) const { std::vector> illegal_turns; + const bool noc_is_3d = noc_model.is_noc_3d(); + /* Iterate over all sets of three routers that can be traversed in sequence. * Check if traversing these three routes involves any turns, and if so, * check if the resulting turn is illegal under the restrictions of a turn model @@ -285,7 +287,7 @@ std::vector> TurnModelRouting::get_all_illegal_t const NocLink& second_noc_link = noc_model.get_single_noc_link(second_noc_link_id); const NocRouterId third_noc_router_id = second_noc_link.get_sink_router(); const NocRouter& third_noc_router = noc_model.get_single_noc_router(third_noc_router_id); - if (!is_turn_legal({noc_router, second_noc_router, third_noc_router})) { + if (!is_turn_legal({noc_router, second_noc_router, third_noc_router}, noc_is_3d)) { illegal_turns.emplace_back(first_noc_link_id, second_noc_link_id); } } diff --git a/vpr/src/noc/turn_model_routing.h b/vpr/src/noc/turn_model_routing.h index 17ff14d17b8..d5216c7eb5c 100644 --- a/vpr/src/noc/turn_model_routing.h +++ b/vpr/src/noc/turn_model_routing.h @@ -261,9 +261,11 @@ class TurnModelRouting : public NocRouting { * 180-degree turns are also illegal. * * @param noc_routers Three NoC routers visited in a turn. + * @param noc_is_3d Specifies whether the NoC is 2D or 3D. * @return True if the turn is legal, otherwise false. */ - virtual bool is_turn_legal(const std::array, 3>& noc_routers) const = 0; + virtual bool is_turn_legal(const std::array, 3>& noc_routers, + bool noc_is_3d) const = 0; protected: // get_legal_directions() return a reference to this vector to avoid allocating a new vector diff --git a/vpr/src/noc/west_first_routing.cpp b/vpr/src/noc/west_first_routing.cpp index 971e4c93409..c13e91dbbca 100644 --- a/vpr/src/noc/west_first_routing.cpp +++ b/vpr/src/noc/west_first_routing.cpp @@ -24,35 +24,51 @@ const std::vector& WestFirstRouting::get_legal_dire * as the destination router. Otherwise, we can move south, north, * and east adaptively. */ + if (noc_model.is_noc_3d()) { + if (dst_router_pos.x < curr_router_pos.x) { + returned_legal_direction.push_back(TurnModelRouting::Direction::WEST); + } - if (dst_router_pos.x < curr_router_pos.x) { - returned_legal_direction.push_back(TurnModelRouting::Direction::WEST); - } + if (dst_router_pos.y < curr_router_pos.y) { + returned_legal_direction.push_back(TurnModelRouting::Direction::SOUTH); + } - if (dst_router_pos.y < curr_router_pos.y) { - returned_legal_direction.push_back(TurnModelRouting::Direction::SOUTH); - } + if (returned_legal_direction.empty()) { + if (dst_router_pos.x > curr_router_pos.x) { + returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); + } - if (returned_legal_direction.empty()) { - if (dst_router_pos.x > curr_router_pos.x) { - returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); - } + if (dst_router_pos.y > curr_router_pos.y) { + returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); + } - if (dst_router_pos.y > curr_router_pos.y) { - returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); + if (dst_router_pos.layer_num > curr_router_pos.layer_num) { + returned_legal_direction.push_back(TurnModelRouting::Direction::UP); + } else if (dst_router_pos.layer_num < curr_router_pos.layer_num) { + returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); + } } - - if (dst_router_pos.layer_num > curr_router_pos.layer_num) { - returned_legal_direction.push_back(TurnModelRouting::Direction::UP); - } else if (dst_router_pos.layer_num < curr_router_pos.layer_num) { - returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); + } else { // 2D NoC + if (dst_router_pos.x < curr_router_pos.x) { + returned_legal_direction.push_back(TurnModelRouting::Direction::WEST); + } else { // to the east or the same column + if (dst_router_pos.x > curr_router_pos.x) { // not the same column + returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); + } + + if (dst_router_pos.y > curr_router_pos.y) { + returned_legal_direction.push_back(TurnModelRouting::Direction::UP); + } else if (dst_router_pos.y < curr_router_pos.y) { + returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); + } } } return returned_legal_direction; } -bool WestFirstRouting::is_turn_legal(const std::array, 3>& noc_routers) const { +bool WestFirstRouting::is_turn_legal(const std::array, 3>& noc_routers, + bool noc_is_3d) const { const auto [x1, y1, z1] = noc_routers[0].get().get_router_physical_location(); const auto [x2, y2, z2] = noc_routers[1].get().get_router_physical_location(); const auto [x3, y3, z3] = noc_routers[2].get().get_router_physical_location(); @@ -66,15 +82,23 @@ bool WestFirstRouting::is_turn_legal(const std::array z1 && x3 < x2) || (z2 < z1 && x3 < x2) || (z2 > z1 && y3 < y2) || - (z2 < z1 && y3 < y2) || (y2 > y1 && x3 < x2) || (x2 > x1 && y3 > y2)) { - return false; + + if (noc_is_3d) { + if ((z2 > z1 && x3 < x2) || (z2 < z1 && x3 < x2) || (z2 > z1 && y3 < y2) || + (z2 < z1 && y3 < y2) || (y2 > y1 && x3 < x2) || (x2 > x1 && y3 > y2)) { + return false; + } + } else { // 2D NoC + /* In the west-first routing algorithm, once the traffic flow + * moved in a vertical direction, it is no longer allowed to move + * towards west. Therefore, if the first link was travelling in a + * vertical direction, the second link can't move towards left. + */ + if ((y2 > y1 && x3 < x2) || (y2 < y1 && x3 < x2)) { + return false; + } } + return true; } diff --git a/vpr/src/noc/west_first_routing.h b/vpr/src/noc/west_first_routing.h index 0e6c7a75c9e..9b76b10b2ab 100644 --- a/vpr/src/noc/west_first_routing.h +++ b/vpr/src/noc/west_first_routing.h @@ -41,7 +41,8 @@ class WestFirstRouting : public TurnModelRouting { TurnModelRouting::Direction prev_dir, const NocStorage& noc_model) override; - bool is_turn_legal(const std::array, 3>& noc_routers) const override; + bool is_turn_legal(const std::array, 3>& noc_routers, + bool noc_is_3d) const override; }; #endif //VTR_WEST_FIRST_ROUTING_H diff --git a/vpr/src/noc/xy_routing.cpp b/vpr/src/noc/xy_routing.cpp index 47813ec768d..5405c912040 100644 --- a/vpr/src/noc/xy_routing.cpp +++ b/vpr/src/noc/xy_routing.cpp @@ -56,7 +56,8 @@ TurnModelRouting::Direction XYRouting::select_next_direction(const std::vector, 3>& noc_routers) const { +bool XYRouting::is_turn_legal(const std::array, 3>& noc_routers, + bool /*noc_is_3d*/) const { const auto [x1, y1, z1] = noc_routers[0].get().get_router_physical_location(); const auto [x2, y2, z2] = noc_routers[1].get().get_router_physical_location(); const auto [x3, y3, z3] = noc_routers[2].get().get_router_physical_location(); diff --git a/vpr/src/noc/xy_routing.h b/vpr/src/noc/xy_routing.h index d9cd447c425..d8994689450 100644 --- a/vpr/src/noc/xy_routing.h +++ b/vpr/src/noc/xy_routing.h @@ -106,7 +106,8 @@ class XYRouting : public TurnModelRouting { NocTrafficFlowId traffic_flow_id, const NocStorage& noc_model) override; - bool is_turn_legal(const std::array, 3>& noc_routers) const override; + bool is_turn_legal(const std::array, 3>& noc_routers, + bool noc_is_3d) const override; private: const std::vector east_direction{TurnModelRouting::Direction::EAST}; From 18b9e7672cfc500db905f3ef5a547d1a045dc6aa Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Mon, 15 Jul 2024 11:22:15 -0400 Subject: [PATCH 19/39] add route_2d and route_3d methods --- vpr/src/noc/odd_even_routing.cpp | 225 +++++++++++++++++-------------- vpr/src/noc/odd_even_routing.h | 9 ++ 2 files changed, 134 insertions(+), 100 deletions(-) diff --git a/vpr/src/noc/odd_even_routing.cpp b/vpr/src/noc/odd_even_routing.cpp index c5efba6aff3..2480576f71e 100644 --- a/vpr/src/noc/odd_even_routing.cpp +++ b/vpr/src/noc/odd_even_routing.cpp @@ -8,7 +8,7 @@ OddEvenRouting::~OddEvenRouting() = default; const std::vector& OddEvenRouting::get_legal_directions(NocRouterId src_router_id, NocRouterId curr_router_id, NocRouterId dst_router_id, - TurnModelRouting::Direction /*prev_dir*/, + TurnModelRouting::Direction prev_dir, const NocStorage& noc_model) { // used to access NoC compressed grid auto& place_ctx = g_vpr_ctx.placement(); @@ -46,104 +46,10 @@ const std::vector& OddEvenRouting::get_legal_direct // clear returned legal directions from the previous call returned_legal_direction.clear(); - // calculate the distance between the current router and the destination - const int diff_x = compressed_dst_loc.x - compressed_curr_loc.x; - const int diff_y = compressed_dst_loc.y - compressed_curr_loc.y; - const int diff_z = compressed_dst_loc.layer_num - compressed_curr_loc.layer_num; - - if (diff_x > 0) { - if (is_even(compressed_curr_loc.x) || (diff_y == 0 && diff_z == 0)) { - returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); - } - } else if (diff_x < 0) { - if (is_even(compressed_curr_loc.x) || - (compressed_curr_loc.y == compressed_src_loc.y && compressed_curr_loc.layer_num == compressed_src_loc.layer_num)) { - returned_legal_direction.push_back(TurnModelRouting::Direction::WEST); - } - } - - - - if (diff_y == 0) { // the same column as the destination. Only north or south are allowed - if (diff_z > 0) { - returned_legal_direction.push_back(TurnModelRouting::Direction::UP); - } else { - returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); - } - } else if (diff_y > 0) { // eastbound message - if (diff_z == 0) { // already in the same row as the destination. Just move to the east - returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); - } else { - /* Since EN and ES turns are forbidden in even columns, we move along the vertical - * direction only in we are in an odd column. */ - if (is_odd(compressed_curr_loc.y) || compressed_curr_loc.y == compressed_src_loc.y) { - if (diff_z > 0) { - returned_legal_direction.push_back(TurnModelRouting::Direction::UP); - } else { - returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); - } - } - // the destination column is odd and there are more than 1 column left to destination - if (is_odd(compressed_dst_loc.y) || diff_y > 1) { - returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); - } - } - } else { // westbound message - returned_legal_direction.push_back(TurnModelRouting::Direction::SOUTH); - /* Since NW and SW turns are forbidden in odd columns, we allow - * moving along vertical axis only in even columns */ - if (is_even(compressed_curr_loc.y)) { - if (diff_z > 0) { - returned_legal_direction.push_back(TurnModelRouting::Direction::UP); - } else { - returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); - } - } - } - - /* The implementation below is a carbon copy of the Fig. 2 in the following paper - * Chiu GM. The odd-even turn model for adaptive routing. - * IEEE Transactions on parallel and distributed systems. 2000 Jul;11(7):729-38. - * In summary, the odd-even algorithm forbids NW and SW turns in odd columns, - * while EN and ES turns are forbidden in even columns. - */ - if (diff_x == 0) { // the same column as the destination. Only north or south are allowed - if (diff_y > 0) { - returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); - } else { - returned_legal_direction.push_back(TurnModelRouting::Direction::SOUTH); - } - } else { // currently in a different column than the destination - if (diff_x > 0) { // eastbound message - if (diff_y == 0) { // already in the same row as the destination. Just move to the east - returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); - } else { - /* Since EN and ES turns are forbidden in even columns, we move along the vertical - * direction only in we are in an odd column. */ - if (is_odd(compressed_curr_loc.x) || compressed_curr_loc.x == compressed_src_loc.x) { - if (diff_y > 0) { - returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); - } else { - returned_legal_direction.push_back(TurnModelRouting::Direction::SOUTH); - } - } - // the destination column is odd and there are more than 1 column left to destination - if (is_odd(compressed_dst_loc.x) || diff_x != 1) { - returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); - } - } - } else { // westbound message - returned_legal_direction.push_back(TurnModelRouting::Direction::WEST); - /* Since NW and SW turns are forbidden in odd columns, we allow - * moving along vertical axis only in even columns */ - if (is_even(compressed_curr_loc.x)) { - if (diff_y > 0) { - returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); - } else { - returned_legal_direction.push_back(TurnModelRouting::Direction::SOUTH); - } - } - } + if (noc_model.is_noc_3d()) { + route_3d(compressed_src_loc, compressed_curr_loc, compressed_dst_loc, prev_dir); + } else { // 2D NoC + route_2d(compressed_src_loc, compressed_curr_loc, compressed_dst_loc); } return returned_legal_direction; @@ -188,7 +94,6 @@ bool OddEvenRouting::is_turn_legal(const std::array 0) { + returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); + } else { + returned_legal_direction.push_back(TurnModelRouting::Direction::SOUTH); + } + } else { // currently in a different column than the destination + if (diff_x > 0) { // eastbound message + if (diff_y == 0) { // already in the same row as the destination. Just move to the east + returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); + } else { + /* Since EN and ES turns are forbidden in even columns, we move along the vertical + * direction only in we are in an odd column. */ + if (is_odd(comp_curr_loc.x) || comp_curr_loc.x == comp_src_loc.x) { + if (diff_y > 0) { + returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); + } else { + returned_legal_direction.push_back(TurnModelRouting::Direction::SOUTH); + } + } + // the destination column is odd and there are more than 1 column left to destination + if (is_odd(comp_dst_loc.x) || diff_x != 1) { + returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); + } + } + } else { // westbound message + returned_legal_direction.push_back(TurnModelRouting::Direction::WEST); + /* Since NW and SW turns are forbidden in odd columns, we allow + * moving along vertical axis only in even columns */ + if (is_even(comp_curr_loc.x)) { + if (diff_y > 0) { + returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); + } else { + returned_legal_direction.push_back(TurnModelRouting::Direction::SOUTH); + } + } + } + } + +} + +void OddEvenRouting::route_3d(t_physical_tile_loc comp_src_loc, + t_physical_tile_loc comp_curr_loc, + t_physical_tile_loc comp_dst_loc, + TurnModelRouting::Direction prev_dir) { + // calculate the distance between the current router and the destination + const int diff_x = comp_dst_loc.x - comp_curr_loc.x; + const int diff_y = comp_dst_loc.y - comp_curr_loc.y; + const int diff_z = comp_dst_loc.layer_num - comp_curr_loc.layer_num; + + if (diff_x > 0) { + + if (is_even(comp_dst_loc.x) && (diff_x == 1) && (diff_y != 0 || diff_z != 0)) { + goto route_in_yz_plane; + } + + if (is_even(comp_curr_loc.x) || (diff_y == 0 && diff_z == 0)) { + returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); + } + + } else if (diff_x < 0) { + + if (is_even(comp_curr_loc.x) || + (comp_curr_loc.y == comp_src_loc.y && comp_curr_loc.layer_num == comp_src_loc.layer_num)) { + returned_legal_direction.push_back(TurnModelRouting::Direction::WEST); + } + } + + + route_in_yz_plane : + + if (diff_y == 0) { // the same column as the destination. Only north or south are allowed + if (diff_z > 0) { + returned_legal_direction.push_back(TurnModelRouting::Direction::UP); + } else { + returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); + } + } else if (diff_y > 0) { // eastbound message + if (diff_z == 0) { // already in the same row as the destination. Just move to the east + returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); + } else { + /* Since EN and ES turns are forbidden in even columns, we move along the vertical + * direction only in we are in an odd column. */ + if (is_odd(comp_curr_loc.y) || comp_curr_loc.y == comp_src_loc.y) { + if (diff_z > 0) { + returned_legal_direction.push_back(TurnModelRouting::Direction::UP); + } else { + returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); + } + } + // the destination column is odd and there are more than 1 column left to destination + if (is_odd(comp_dst_loc.y) || diff_y > 1) { + returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); + } + } + } else { // westbound message + returned_legal_direction.push_back(TurnModelRouting::Direction::SOUTH); + /* Since NW and SW turns are forbidden in odd columns, we allow + * moving along vertical axis only in even columns */ + if (is_even(comp_curr_loc.y)) { + if (diff_z > 0) { + returned_legal_direction.push_back(TurnModelRouting::Direction::UP); + } else { + returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); + } + } + } +} diff --git a/vpr/src/noc/odd_even_routing.h b/vpr/src/noc/odd_even_routing.h index 42772a8fd0c..ebd62e7b7f7 100644 --- a/vpr/src/noc/odd_even_routing.h +++ b/vpr/src/noc/odd_even_routing.h @@ -33,6 +33,15 @@ class OddEvenRouting : public TurnModelRouting{ bool is_turn_legal(const std::array, 3>& noc_routers, bool noc_is_3d) const override; + inline void route_2d(t_physical_tile_loc comp_src_loc, + t_physical_tile_loc comp_curr_loc, + t_physical_tile_loc comp_dst_loc); + + inline void route_3d(t_physical_tile_loc comp_src_loc, + t_physical_tile_loc comp_curr_loc, + t_physical_tile_loc comp_dst_loc, + TurnModelRouting::Direction prev_dir); + /** * Checks whether the given umber is odd. * @param number An integer number From f464e5deaf60495e193e6e7657b11ef5f9e72ea1 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Mon, 15 Jul 2024 11:55:28 -0400 Subject: [PATCH 20/39] implemented OddEvenRouting::route_3d() method --- vpr/src/noc/odd_even_routing.cpp | 75 ++++++++++++++++++-------------- vpr/src/noc/odd_even_routing.h | 3 +- 2 files changed, 44 insertions(+), 34 deletions(-) diff --git a/vpr/src/noc/odd_even_routing.cpp b/vpr/src/noc/odd_even_routing.cpp index 2480576f71e..532b17fc731 100644 --- a/vpr/src/noc/odd_even_routing.cpp +++ b/vpr/src/noc/odd_even_routing.cpp @@ -144,7 +144,8 @@ bool OddEvenRouting::is_turn_legal(const std::array 0) { // eastbound message - if (diff_y == 0) { // already in the same row as the destination. Just move to the east - returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); - } else { - /* Since EN and ES turns are forbidden in even columns, we move along the vertical - * direction only in we are in an odd column. */ - if (is_odd(comp_curr_loc.x) || comp_curr_loc.x == comp_src_loc.x) { - if (diff_y > 0) { - returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); - } else { - returned_legal_direction.push_back(TurnModelRouting::Direction::SOUTH); - } - } - // the destination column is odd and there are more than 1 column left to destination - if (is_odd(comp_dst_loc.x) || diff_x != 1) { - returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); - } - } - } else { // westbound message - returned_legal_direction.push_back(TurnModelRouting::Direction::WEST); - /* Since NW and SW turns are forbidden in odd columns, we allow - * moving along vertical axis only in even columns */ - if (is_even(comp_curr_loc.x)) { + } else if (diff_x > 0) { // eastbound message + if (diff_y == 0) { // already in the same row as the destination. Just move to the east + returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); + } else { + /* Since EN and ES turns are forbidden in even columns, we move along the vertical + * direction only in we are in an odd column. */ + if (is_odd(comp_curr_loc.x) || comp_curr_loc.x == comp_src_loc.x || prev_dir != TurnModelRouting::Direction::EAST) { if (diff_y > 0) { returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); } else { returned_legal_direction.push_back(TurnModelRouting::Direction::SOUTH); } } + // the destination column is odd and there are more than 1 column left to destination + if (is_odd(comp_dst_loc.x) || diff_x != 1) { + returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); + } + } + } else { // westbound message + returned_legal_direction.push_back(TurnModelRouting::Direction::WEST); + /* Since NW and SW turns are forbidden in odd columns, we allow + * moving along vertical axis only in even columns */ + if (is_even(comp_curr_loc.x)) { + if (diff_y > 0) { + returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); + } else { + returned_legal_direction.push_back(TurnModelRouting::Direction::SOUTH); + } } } + } void OddEvenRouting::route_3d(t_physical_tile_loc comp_src_loc, @@ -205,19 +205,28 @@ void OddEvenRouting::route_3d(t_physical_tile_loc comp_src_loc, if (diff_x > 0) { - if (is_even(comp_dst_loc.x) && (diff_x == 1) && (diff_y != 0 || diff_z != 0)) { - goto route_in_yz_plane; + if (diff_y == 0 && diff_z == 0) { + returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); + return; } - if (is_even(comp_curr_loc.x) || (diff_y == 0 && diff_z == 0)) { + if (is_odd(comp_dst_loc.x) || diff_x > 1) { returned_legal_direction.push_back(TurnModelRouting::Direction::EAST); } + if (is_odd(comp_curr_loc.x) || comp_curr_loc.x == comp_src_loc.x || prev_dir != TurnModelRouting::Direction::EAST) { + goto route_in_yz_plane; + } else { + return; + } + } else if (diff_x < 0) { + returned_legal_direction.push_back(TurnModelRouting::Direction::WEST); - if (is_even(comp_curr_loc.x) || - (comp_curr_loc.y == comp_src_loc.y && comp_curr_loc.layer_num == comp_src_loc.layer_num)) { - returned_legal_direction.push_back(TurnModelRouting::Direction::WEST); + if (is_even(comp_curr_loc.x)) { + goto route_in_yz_plane; + } else { + return; } } @@ -231,12 +240,12 @@ void OddEvenRouting::route_3d(t_physical_tile_loc comp_src_loc, returned_legal_direction.push_back(TurnModelRouting::Direction::DOWN); } } else if (diff_y > 0) { // eastbound message - if (diff_z == 0) { // already in the same row as the destination. Just move to the east + if (diff_z == 0) { // already in the same row as the destination. Just move to the east returned_legal_direction.push_back(TurnModelRouting::Direction::NORTH); } else { /* Since EN and ES turns are forbidden in even columns, we move along the vertical * direction only in we are in an odd column. */ - if (is_odd(comp_curr_loc.y) || comp_curr_loc.y == comp_src_loc.y) { + if (is_odd(comp_curr_loc.y) || comp_curr_loc.y == comp_src_loc.y || prev_dir != TurnModelRouting::Direction::NORTH) { if (diff_z > 0) { returned_legal_direction.push_back(TurnModelRouting::Direction::UP); } else { diff --git a/vpr/src/noc/odd_even_routing.h b/vpr/src/noc/odd_even_routing.h index ebd62e7b7f7..ca3da0e4420 100644 --- a/vpr/src/noc/odd_even_routing.h +++ b/vpr/src/noc/odd_even_routing.h @@ -35,7 +35,8 @@ class OddEvenRouting : public TurnModelRouting{ inline void route_2d(t_physical_tile_loc comp_src_loc, t_physical_tile_loc comp_curr_loc, - t_physical_tile_loc comp_dst_loc); + t_physical_tile_loc comp_dst_loc, + TurnModelRouting::Direction prev_dir); inline void route_3d(t_physical_tile_loc comp_src_loc, t_physical_tile_loc comp_curr_loc, From a183c2cfd17bfe6475b57c83f1bfd0938e60cb2e Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Mon, 15 Jul 2024 15:40:38 -0400 Subject: [PATCH 21/39] avoid using global state in OddEvenRouting --- vpr/src/base/vpr_api.cpp | 5 +- vpr/src/noc/negative_first_routing.cpp | 4 +- vpr/src/noc/negative_first_routing.h | 2 +- vpr/src/noc/noc_routing_algorithm_creator.cpp | 5 +- vpr/src/noc/noc_routing_algorithm_creator.h | 3 +- vpr/src/noc/noc_storage.cpp | 8 +- vpr/src/noc/north_last_routing.cpp | 4 +- vpr/src/noc/north_last_routing.h | 2 +- vpr/src/noc/odd_even_routing.cpp | 96 ++++++++++--------- vpr/src/noc/odd_even_routing.h | 9 +- vpr/src/noc/turn_model_routing.cpp | 8 +- vpr/src/noc/turn_model_routing.h | 2 +- vpr/src/noc/west_first_routing.cpp | 4 +- vpr/src/noc/west_first_routing.h | 2 +- vpr/src/noc/xy_routing.cpp | 2 +- vpr/src/noc/xy_routing.h | 2 +- vpr/src/place/noc_place_utils.cpp | 3 +- vpr/test/test_xy_routing.cpp | 6 ++ 18 files changed, 91 insertions(+), 76 deletions(-) diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index fac75c5fbb3..faa24f753be 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -568,11 +568,12 @@ void vpr_setup_noc(const t_vpr_setup& vpr_setup, const t_arch& arch) { * NoC routing algorithm */ void vpr_setup_noc_routing_algorithm(const std::string& noc_routing_algorithm_name) { - // Need to be abke to modify the NoC context, since we will be adding the + // Need to be able to modify the NoC context, since we will be adding the // newly created routing algorithm to it auto& noc_ctx = g_vpr_ctx.mutable_noc(); - noc_ctx.noc_flows_router = NocRoutingAlgorithmCreator::create_routing_algorithm(noc_routing_algorithm_name); + noc_ctx.noc_flows_router = NocRoutingAlgorithmCreator::create_routing_algorithm(noc_routing_algorithm_name, + noc_ctx.noc_model); } bool vpr_pack_flow(t_vpr_setup& vpr_setup, const t_arch& arch) { diff --git a/vpr/src/noc/negative_first_routing.cpp b/vpr/src/noc/negative_first_routing.cpp index 0413d2746d4..e45df009122 100644 --- a/vpr/src/noc/negative_first_routing.cpp +++ b/vpr/src/noc/negative_first_routing.cpp @@ -73,7 +73,7 @@ const std::vector& NegativeFirstRouting::get_legal_ } bool NegativeFirstRouting::is_turn_legal(const std::array, 3>& noc_routers, - bool noc_is_3d) const { + const NocStorage& noc_model) const { const auto[x1, y1, z1] = noc_routers[0].get().get_router_physical_location(); const auto[x2, y2, z2] = noc_routers[1].get().get_router_physical_location(); const auto[x3, y3, z3] = noc_routers[2].get().get_router_physical_location(); @@ -88,7 +88,7 @@ bool NegativeFirstRouting::is_turn_legal(const std::array x1 && y3 < y2) || (y2 > y1 && x3 < x2) || (z2 > z1 && x3 < x2) || (x2 > x1 && z3 < z2) || (z2 > z1 && y3 < y2) || (y2 > y1 && z3 < z2)) { return false; diff --git a/vpr/src/noc/negative_first_routing.h b/vpr/src/noc/negative_first_routing.h index 2d165329e74..74bd38e2ba9 100644 --- a/vpr/src/noc/negative_first_routing.h +++ b/vpr/src/noc/negative_first_routing.h @@ -42,7 +42,7 @@ class NegativeFirstRouting : public TurnModelRouting { const NocStorage& noc_model) override; bool is_turn_legal(const std::array, 3>& noc_routers, - bool noc_is_3d) const override; + const NocStorage& noc_model) const override; }; #endif //VTR_NEGATIVE_FIRST_ROUTING_H diff --git a/vpr/src/noc/noc_routing_algorithm_creator.cpp b/vpr/src/noc/noc_routing_algorithm_creator.cpp index b7125be1339..e52be823ae3 100644 --- a/vpr/src/noc/noc_routing_algorithm_creator.cpp +++ b/vpr/src/noc/noc_routing_algorithm_creator.cpp @@ -9,7 +9,8 @@ #include "vpr_error.h" -std::unique_ptr NocRoutingAlgorithmCreator::create_routing_algorithm(const std::string& routing_algorithm_name) { +std::unique_ptr NocRoutingAlgorithmCreator::create_routing_algorithm(const std::string& routing_algorithm_name, + const NocStorage& noc_model) { std::unique_ptr noc_routing_algorithm; if (routing_algorithm_name == "xy_routing") { @@ -23,7 +24,7 @@ std::unique_ptr NocRoutingAlgorithmCreator::create_routing_algorithm } else if (routing_algorithm_name == "negative_first_routing") { noc_routing_algorithm = std::make_unique(); } else if (routing_algorithm_name == "odd_even_routing") { - noc_routing_algorithm = std::make_unique(); + noc_routing_algorithm = std::make_unique(noc_model); } else { VPR_FATAL_ERROR(VPR_ERROR_OTHER, "The provided NoC routing algorithm '%s' is not supported.", routing_algorithm_name.c_str()); } diff --git a/vpr/src/noc/noc_routing_algorithm_creator.h b/vpr/src/noc/noc_routing_algorithm_creator.h index cecd7ba39f6..8cb9b777949 100644 --- a/vpr/src/noc/noc_routing_algorithm_creator.h +++ b/vpr/src/noc/noc_routing_algorithm_creator.h @@ -38,7 +38,8 @@ class NocRoutingAlgorithmCreator { * NoC routing algorithm * @return std::unique_ptr A reference to the created NoC routing algorithm */ - static std::unique_ptr create_routing_algorithm(const std::string& routing_algorithm_name); + static std::unique_ptr create_routing_algorithm(const std::string& routing_algorithm_name, + const NocStorage& noc_model); }; #endif diff --git a/vpr/src/noc/noc_storage.cpp b/vpr/src/noc/noc_storage.cpp index 55d4e58ff3e..cbf32c802c9 100644 --- a/vpr/src/noc/noc_storage.cpp +++ b/vpr/src/noc/noc_storage.cpp @@ -64,7 +64,7 @@ NocRouter& NocStorage::get_single_mutable_noc_router(NocRouterId id) { } // get link properties - const NocLink& NocStorage::get_single_noc_link(NocLinkId id) const { +const NocLink& NocStorage::get_single_noc_link(NocLinkId id) const { return link_storage[id]; } @@ -234,19 +234,19 @@ void NocStorage::finished_building_noc() { */ auto router_latency_it = std::adjacent_find(router_storage.begin(), router_storage.end(), - [](const NocRouter& a, const NocRouter& b) { + [](const NocRouter& a, const NocRouter& b) -> bool { return a.get_latency() != b.get_latency(); }); detailed_router_latency_ = (router_latency_it != router_storage.end()); auto link_latency_it = std::adjacent_find(link_storage.begin(), link_storage.end(), - [](const NocLink& a, const NocLink& b) { + [](const NocLink& a, const NocLink& b) -> bool { return a.get_latency() != b.get_latency(); }); detailed_link_latency_ = (link_latency_it != link_storage.end()); auto router_layer_it = std::adjacent_find(router_storage.begin(), router_storage.end(), - [](const NocRouter& a, const NocRouter& b) { + [](const NocRouter& a, const NocRouter& b) -> bool { return a.get_router_layer_position() != b.get_router_layer_position(); }); diff --git a/vpr/src/noc/north_last_routing.cpp b/vpr/src/noc/north_last_routing.cpp index 0010601e8f7..fd3c1183201 100644 --- a/vpr/src/noc/north_last_routing.cpp +++ b/vpr/src/noc/north_last_routing.cpp @@ -63,7 +63,7 @@ const std::vector& NorthLastRouting::get_legal_dire } bool NorthLastRouting::is_turn_legal(const std::array, 3>& noc_routers, - bool noc_is_3d) const { + const NocStorage& noc_model) const { const auto [x1, y1, z1] = noc_routers[0].get().get_router_physical_location(); const auto [x2, y2, z2] = noc_routers[1].get().get_router_physical_location(); const auto [x3, y3, z3] = noc_routers[2].get().get_router_physical_location(); @@ -79,7 +79,7 @@ bool NorthLastRouting::is_turn_legal(const std::array z1 && x3 < x2) || (z2 > z1 && x3 > x2) || (z2 > z1 && y3 < y2) || (y2 > y1 && z3 < z2) || (y2 > y1 && x3 < x2) || (y2 > y1 && x3 > x2)) { return false; diff --git a/vpr/src/noc/north_last_routing.h b/vpr/src/noc/north_last_routing.h index 806e7bdb472..3d755d67624 100644 --- a/vpr/src/noc/north_last_routing.h +++ b/vpr/src/noc/north_last_routing.h @@ -43,7 +43,7 @@ class NorthLastRouting : public TurnModelRouting { const NocStorage& noc_model) override; bool is_turn_legal(const std::array, 3>& noc_routers, - bool noc_is_3d) const override; + const NocStorage& noc_model) const override; }; #endif //VTR_NORTH_LAST_ROUTING_H diff --git a/vpr/src/noc/odd_even_routing.cpp b/vpr/src/noc/odd_even_routing.cpp index 532b17fc731..3cdaca127b0 100644 --- a/vpr/src/noc/odd_even_routing.cpp +++ b/vpr/src/noc/odd_even_routing.cpp @@ -1,8 +1,48 @@ #include "odd_even_routing.h" -#include "globals.h" + #include "move_utils.h" +#include +#include + +OddEvenRouting::OddEvenRouting(const NocStorage& noc_model) { + std::set unique_x, unique_y, unique_z; + + for (const NocRouter& router : noc_model.get_noc_routers()) { + t_physical_tile_loc loc = router.get_router_physical_location(); + unique_x.insert(loc.x); + unique_y.insert(loc.y); + unique_z.insert(loc.layer_num); + } + + auto create_compressed_map = [](const std::set unique_vals) -> std::map { + std::map compressed_map; + int compressed_val = 0; + for (int val : unique_vals) { + compressed_map[val] = compressed_val++; + } + + return compressed_map; + }; + + std::map compressed_x_map = create_compressed_map(unique_x); + std::map compressed_y_map = create_compressed_map(unique_y); + std::map compressed_z_map = create_compressed_map(unique_z); + + compressed_noc_locs_.resize(noc_model.get_number_of_noc_routers()); + + for (const auto& [id, router] : noc_model.get_noc_routers().pairs()) { + t_physical_tile_loc loc = router.get_router_physical_location(); + + t_physical_tile_loc compressed_loc{compressed_x_map[loc.x], + compressed_x_map[loc.y], + compressed_x_map[loc.layer_num]}; + + compressed_noc_locs_[id] = compressed_loc; + } +} + OddEvenRouting::~OddEvenRouting() = default; const std::vector& OddEvenRouting::get_legal_directions(NocRouterId src_router_id, @@ -10,38 +50,13 @@ const std::vector& OddEvenRouting::get_legal_direct NocRouterId dst_router_id, TurnModelRouting::Direction prev_dir, const NocStorage& noc_model) { - // used to access NoC compressed grid - auto& place_ctx = g_vpr_ctx.placement(); - // used to get NoC logical block type - auto& cluster_ctx = g_vpr_ctx.clustering(); - // used to get the clustered block ID of a NoC router - auto& noc_ctx = g_vpr_ctx.noc(); - // get number of layers - const int num_layers = g_vpr_ctx.device().grid.get_num_layers(); - - // Get the logical block type for router - const auto router_block_type = cluster_ctx.clb_nlist.block_type(noc_ctx.noc_traffic_flows_storage.get_router_clusters_in_netlist()[0]); - - // Get the compressed grid for NoC - const auto& compressed_noc_grid = place_ctx.compressed_block_grids[router_block_type->index]; - - // get source, current, and destination NoC routers - const auto& src_router = noc_model.get_single_noc_router(src_router_id); - const auto& curr_router = noc_model.get_single_noc_router(curr_router_id); - const auto& dst_router = noc_model.get_single_noc_router(dst_router_id); - - // get the position of source, current, and destination NoC routers - const auto src_router_pos = src_router.get_router_physical_location(); - const auto curr_router_pos = curr_router.get_router_physical_location(); - const auto dst_router_pos = dst_router.get_router_physical_location(); - /* get the compressed location for source, current, and destination NoC routers * Odd-even routing algorithm restricts turn based on whether the current NoC router * in an odd or even NoC column. This information can be extracted from the NoC compressed grid. */ - auto compressed_src_loc = get_compressed_loc_approx(compressed_noc_grid, t_pl_loc{src_router_pos, 0}, num_layers)[src_router_pos.layer_num]; - auto compressed_curr_loc = get_compressed_loc_approx(compressed_noc_grid, t_pl_loc{curr_router_pos, 0}, num_layers)[curr_router_pos.layer_num]; - auto compressed_dst_loc = get_compressed_loc_approx(compressed_noc_grid, t_pl_loc{dst_router_pos, 0}, num_layers)[dst_router_pos.layer_num]; + auto compressed_src_loc = compressed_noc_locs_[src_router_id]; + auto compressed_curr_loc = compressed_noc_locs_[curr_router_id]; + auto compressed_dst_loc = compressed_noc_locs_[dst_router_id]; // clear returned legal directions from the previous call returned_legal_direction.clear(); @@ -49,7 +64,7 @@ const std::vector& OddEvenRouting::get_legal_direct if (noc_model.is_noc_3d()) { route_3d(compressed_src_loc, compressed_curr_loc, compressed_dst_loc, prev_dir); } else { // 2D NoC - route_2d(compressed_src_loc, compressed_curr_loc, compressed_dst_loc); + route_2d(compressed_src_loc, compressed_curr_loc, compressed_dst_loc, prev_dir); } return returned_legal_direction; @@ -64,7 +79,7 @@ bool OddEvenRouting::is_even(int number) { } bool OddEvenRouting::is_turn_legal(const std::array, 3>& noc_routers, - bool noc_is_3d) const { + const NocStorage& noc_model) const { const auto [x1, y1, z1] = noc_routers[0].get().get_router_physical_location(); const auto [x2, y2, z2] = noc_routers[1].get().get_router_physical_location(); const auto [x3, y3, z3] = noc_routers[2].get().get_router_physical_location(); @@ -73,33 +88,20 @@ bool OddEvenRouting::is_turn_legal(const std::arrayindex]; + NocRouterId router2_id = noc_model.get_router_at_grid_location({router2_pos, 0}); // get the compressed location of the second NoC router - auto compressed_2_loc = get_compressed_loc(compressed_noc_grid, t_pl_loc{router2_pos, 0}, num_layers)[router2_pos.layer_num]; + auto compressed_2_loc = compressed_noc_locs_[router2_id]; // going back to the first router is not allowed (180-degree turns) if (x1 == x3 && y1 == y3 && z1 == z3) { return false; } - if (noc_is_3d) { + if (noc_model.is_noc_3d()) { /* A packet is not allowed to take any of the X+ --> YZ turns at a router * located in an even yz-place. */ if (is_even(compressed_2_loc.x)) { diff --git a/vpr/src/noc/odd_even_routing.h b/vpr/src/noc/odd_even_routing.h index ca3da0e4420..39974379f61 100644 --- a/vpr/src/noc/odd_even_routing.h +++ b/vpr/src/noc/odd_even_routing.h @@ -18,8 +18,10 @@ * in odd columns, while EN and ES turns are not allowed in even columns. */ -class OddEvenRouting : public TurnModelRouting{ +class OddEvenRouting : public TurnModelRouting { public: + OddEvenRouting(const NocStorage& noc_model); + ~OddEvenRouting() override; private: @@ -31,7 +33,7 @@ class OddEvenRouting : public TurnModelRouting{ const NocStorage& noc_model) override; bool is_turn_legal(const std::array, 3>& noc_routers, - bool noc_is_3d) const override; + const NocStorage& noc_model) const override; inline void route_2d(t_physical_tile_loc comp_src_loc, t_physical_tile_loc comp_curr_loc, @@ -56,6 +58,9 @@ class OddEvenRouting : public TurnModelRouting{ * @return True if the passed number of even, otherwise false. */ static inline bool is_even(int number); + + private: + vtr::vector compressed_noc_locs_; }; #endif //VTR_ODD_EVEN_ROUTING_H diff --git a/vpr/src/noc/turn_model_routing.cpp b/vpr/src/noc/turn_model_routing.cpp index a25208a00ef..d9b169a0896 100644 --- a/vpr/src/noc/turn_model_routing.cpp +++ b/vpr/src/noc/turn_model_routing.cpp @@ -56,10 +56,10 @@ void TurnModelRouting::route_flow(NocRouterId src_router_id, // The route is terminated when we reach at the destination router while (curr_router_id != dst_router_id) { // get the current router (the last one added to the route) - const auto& curr_router = noc_model.get_single_noc_router(curr_router_id); + const NocRouter& curr_router = noc_model.get_single_noc_router(curr_router_id); // get the physical location of the current router - auto curr_router_pos = curr_router.get_router_physical_location(); + t_physical_tile_loc curr_router_pos = curr_router.get_router_physical_location(); // get all directions that moves us closer to the destination router const auto& legal_directions = get_legal_directions(src_router_id, curr_router_id, dst_router_id, prev_dir, noc_model); @@ -263,8 +263,6 @@ TurnModelRouting::Direction TurnModelRouting::select_direction_other_than(const std::vector> TurnModelRouting::get_all_illegal_turns(const NocStorage& noc_model) const { std::vector> illegal_turns; - const bool noc_is_3d = noc_model.is_noc_3d(); - /* Iterate over all sets of three routers that can be traversed in sequence. * Check if traversing these three routes involves any turns, and if so, * check if the resulting turn is illegal under the restrictions of a turn model @@ -287,7 +285,7 @@ std::vector> TurnModelRouting::get_all_illegal_t const NocLink& second_noc_link = noc_model.get_single_noc_link(second_noc_link_id); const NocRouterId third_noc_router_id = second_noc_link.get_sink_router(); const NocRouter& third_noc_router = noc_model.get_single_noc_router(third_noc_router_id); - if (!is_turn_legal({noc_router, second_noc_router, third_noc_router}, noc_is_3d)) { + if (!is_turn_legal({noc_router, second_noc_router, third_noc_router}, noc_model)) { illegal_turns.emplace_back(first_noc_link_id, second_noc_link_id); } } diff --git a/vpr/src/noc/turn_model_routing.h b/vpr/src/noc/turn_model_routing.h index d5216c7eb5c..41a1fd1f694 100644 --- a/vpr/src/noc/turn_model_routing.h +++ b/vpr/src/noc/turn_model_routing.h @@ -265,7 +265,7 @@ class TurnModelRouting : public NocRouting { * @return True if the turn is legal, otherwise false. */ virtual bool is_turn_legal(const std::array, 3>& noc_routers, - bool noc_is_3d) const = 0; + const NocStorage& noc_model) const = 0; protected: // get_legal_directions() return a reference to this vector to avoid allocating a new vector diff --git a/vpr/src/noc/west_first_routing.cpp b/vpr/src/noc/west_first_routing.cpp index c13e91dbbca..252b201555b 100644 --- a/vpr/src/noc/west_first_routing.cpp +++ b/vpr/src/noc/west_first_routing.cpp @@ -68,7 +68,7 @@ const std::vector& WestFirstRouting::get_legal_dire } bool WestFirstRouting::is_turn_legal(const std::array, 3>& noc_routers, - bool noc_is_3d) const { + const NocStorage& noc_model) const { const auto [x1, y1, z1] = noc_routers[0].get().get_router_physical_location(); const auto [x2, y2, z2] = noc_routers[1].get().get_router_physical_location(); const auto [x3, y3, z3] = noc_routers[2].get().get_router_physical_location(); @@ -83,7 +83,7 @@ bool WestFirstRouting::is_turn_legal(const std::array z1 && x3 < x2) || (z2 < z1 && x3 < x2) || (z2 > z1 && y3 < y2) || (z2 < z1 && y3 < y2) || (y2 > y1 && x3 < x2) || (x2 > x1 && y3 > y2)) { return false; diff --git a/vpr/src/noc/west_first_routing.h b/vpr/src/noc/west_first_routing.h index 9b76b10b2ab..e9acb7588c0 100644 --- a/vpr/src/noc/west_first_routing.h +++ b/vpr/src/noc/west_first_routing.h @@ -42,7 +42,7 @@ class WestFirstRouting : public TurnModelRouting { const NocStorage& noc_model) override; bool is_turn_legal(const std::array, 3>& noc_routers, - bool noc_is_3d) const override; + const NocStorage& noc_model) const override; }; #endif //VTR_WEST_FIRST_ROUTING_H diff --git a/vpr/src/noc/xy_routing.cpp b/vpr/src/noc/xy_routing.cpp index 5405c912040..0d04959c2e2 100644 --- a/vpr/src/noc/xy_routing.cpp +++ b/vpr/src/noc/xy_routing.cpp @@ -57,7 +57,7 @@ TurnModelRouting::Direction XYRouting::select_next_direction(const std::vector, 3>& noc_routers, - bool /*noc_is_3d*/) const { + const NocStorage& /*noc_model*/) const { const auto [x1, y1, z1] = noc_routers[0].get().get_router_physical_location(); const auto [x2, y2, z2] = noc_routers[1].get().get_router_physical_location(); const auto [x3, y3, z3] = noc_routers[2].get().get_router_physical_location(); diff --git a/vpr/src/noc/xy_routing.h b/vpr/src/noc/xy_routing.h index d8994689450..97fba4d899e 100644 --- a/vpr/src/noc/xy_routing.h +++ b/vpr/src/noc/xy_routing.h @@ -107,7 +107,7 @@ class XYRouting : public TurnModelRouting { const NocStorage& noc_model) override; bool is_turn_legal(const std::array, 3>& noc_routers, - bool noc_is_3d) const override; + const NocStorage& noc_model) const override; private: const std::vector east_direction{TurnModelRouting::Direction::EAST}; diff --git a/vpr/src/place/noc_place_utils.cpp b/vpr/src/place/noc_place_utils.cpp index 0b9e274b85b..5ce7f765dc2 100644 --- a/vpr/src/place/noc_place_utils.cpp +++ b/vpr/src/place/noc_place_utils.cpp @@ -470,7 +470,8 @@ int check_noc_placement_costs(const t_placer_costs& costs, double error_toleranc std::for_each(temp_noc_link_storage.begin(), temp_noc_link_storage.end(), [](NocLink& link) { link.set_bandwidth_usage(0.0); }); // need to create a temporary noc routing algorithm - std::unique_ptr temp_noc_routing_algorithm = NocRoutingAlgorithmCreator::create_routing_algorithm(noc_opts.noc_routing_algorithm); + std::unique_ptr temp_noc_routing_algorithm = NocRoutingAlgorithmCreator::create_routing_algorithm(noc_opts.noc_routing_algorithm, + noc_model); // stores a temporarily found route for a traffic flow std::vector temp_found_noc_route; diff --git a/vpr/test/test_xy_routing.cpp b/vpr/test/test_xy_routing.cpp index 789fb754bf5..dfaa0ba2599 100644 --- a/vpr/test/test_xy_routing.cpp +++ b/vpr/test/test_xy_routing.cpp @@ -84,6 +84,8 @@ TEST_CASE("test_route_flow", "[vpr_noc_xy_routing]") { } } + noc_model.finished_building_noc(); + // creating the XY routing object XYRouting routing_algorithm; @@ -274,6 +276,8 @@ TEST_CASE("test_route_flow when it fails in a mesh topology.", "[vpr_noc_xy_rout } } + noc_model.finished_building_noc(); + // creating the XY routing object XYRouting routing_algorithm; @@ -368,6 +372,8 @@ TEST_CASE("test_route_flow when it fails in a non mesh topology.", "[vpr_noc_xy_ noc_model.add_link((NocRouterId)3, (NocRouterId)0, DUMMY_BANDWIDTH, DUMMY_LATENCY); noc_model.add_link((NocRouterId)2, (NocRouterId)1, DUMMY_BANDWIDTH, DUMMY_LATENCY); + noc_model.finished_building_noc(); + // now create the start and the destination routers of the route we want to test auto start_router_id = NocRouterId(3); auto sink_router_id = NocRouterId(1); From f087f41fcb71a33767dd17473ebe74986a1716ff Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Mon, 15 Jul 2024 15:57:39 -0400 Subject: [PATCH 22/39] add simple tests for odd-even routing --- vpr/test/test_odd_even_routing.cpp | 206 +++++++++++++++++++++++++++++ vpr/test/test_xy_routing.cpp | 2 +- 2 files changed, 207 insertions(+), 1 deletion(-) create mode 100644 vpr/test/test_odd_even_routing.cpp diff --git a/vpr/test/test_odd_even_routing.cpp b/vpr/test/test_odd_even_routing.cpp new file mode 100644 index 00000000000..db0c4473f85 --- /dev/null +++ b/vpr/test/test_odd_even_routing.cpp @@ -0,0 +1,206 @@ +#include "catch2/catch_test_macros.hpp" +#include "catch2/matchers/catch_matchers_all.hpp" + +#include "odd_even_routing.h" + + +namespace { + +constexpr double DUMMY_LATENCY = 1e-9; +constexpr double DUMMY_BANDWIDTH = 1e12; + +/** + * @brief Compares two vectors of NocLinks. These vectors represent + * two routes between a start and destination routers. This function + * verifies whether the two routers are the exact same or not. + * + */ +void compare_routes(const std::vector& golden_path, + const std::vector& found_path, + const NocStorage& noc_model) { + // make sure that size of the found route and golden route match + REQUIRE(found_path.size() == golden_path.size()); + + // now go through the two routes and make sure that the links in the route match between both routes + int route_size = golden_path.size(); + + for (int link_index = 0; link_index < route_size; link_index++) { + // get the current link we need to verify from the found route + const NocLink& found_link = noc_model.get_single_noc_link(found_path[link_index]); + + // now compare the found link to the equivalent link in the golden route. + // We are just comparing the source and destination routers of the links. We want them to be the same. + REQUIRE(found_link.get_source_router() == golden_path[link_index].get_source_router()); + REQUIRE(found_link.get_sink_router() == golden_path[link_index].get_sink_router()); + } +} + +TEST_CASE("test_route_flow", "[vpr_noc_odd_even_routing]") { + /* Creating a test FPGA device below. The NoC itself will be a 10x10 mesh where + * they will span over a grid size of 10x10. So this FPGA will only consist of NoC routers */ + + // Create the NoC storage + NocStorage noc_model; + + // store the reference to device grid with + // this will be set to the device grid width + noc_model.set_device_grid_width((int)10); + + // add all the routers + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + noc_model.add_router((i * 10) + j, j, i, 0, DUMMY_LATENCY); + } + } + + noc_model.make_room_for_noc_router_link_list(); + + // add all the links + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + // add a link to the left of the router if there exists another router there + if ((j - 1) >= 0) { + noc_model.add_link((NocRouterId)((i * 10) + j), (NocRouterId)(((i * 10) + j) - 1), DUMMY_BANDWIDTH, DUMMY_LATENCY); + } + // add a link to the top of the router if there exists another router there + if ((i + 1) <= 9) { + noc_model.add_link((NocRouterId)((i * 10) + j), (NocRouterId)(((i * 10) + j) + 10), DUMMY_BANDWIDTH, DUMMY_LATENCY); + } + // add a link to the right of the router if there exists another router there + if ((j + 1) <= 9) { + noc_model.add_link((NocRouterId)((i * 10) + j), (NocRouterId)(((i * 10) + j) + 1), DUMMY_BANDWIDTH, DUMMY_LATENCY); + } + // add a link to the bottom of the router if there exists another router there + if ((i - 1) >= 0) { + noc_model.add_link((NocRouterId)((i * 10) + j), (NocRouterId)(((i * 10) + j) - 10), DUMMY_BANDWIDTH, DUMMY_LATENCY); + } + } + } + + noc_model.finished_building_noc(); + + // creating the Odd-even routing object + OddEvenRouting routing_algorithm(noc_model); + + SECTION("Test case where the destination router and the starting routers are the same") { + // choosing the start and end routers as router 17 + auto start_router_id = NocRouterId(17); + auto sink_router_id = NocRouterId(17); + auto traffic_flow_id = NocTrafficFlowId(33); + + // store the route found by the algorithm + std::vector found_path; + + // make sure that a legal route was found (no error should be thrown) + REQUIRE_NOTHROW(routing_algorithm.route_flow(start_router_id, sink_router_id, traffic_flow_id, found_path, noc_model)); + + // now make sure that the found route is empty, we shouldn't be moving anywhere as the start and end routers are the same + REQUIRE(found_path.empty() == true); + } + + SECTION("Test case where the destination router and the starting routers are located on the same row, and the route is westward.") { + // choose start router as 19, and choose the destination router as 12 + auto start_router_id = NocRouterId(19); + auto sink_router_id = NocRouterId(12); + auto traffic_flow_id = NocTrafficFlowId(34); + + // build the golden route that we expect the algorithm to produce + // the expectation is a number of links that path horizontally from router 7 to router 4 + std::vector golden_path; + + for (int current_router = 19; current_router != 12; current_router--) { + NocLinkId link_id = noc_model.get_single_noc_link_id(NocRouterId(current_router), NocRouterId(current_router - 1)); + const NocLink& link = noc_model.get_single_noc_link(link_id); + golden_path.push_back(link); + } + + // store the route found by the algorithm + std::vector found_path; + + // now run the algorithm to find a route, once again we expect no errors and a legal path to be found + REQUIRE_NOTHROW(routing_algorithm.route_flow(start_router_id, sink_router_id, traffic_flow_id, found_path, noc_model)); + + // make sure that size of the found route and golden route match + compare_routes(golden_path, found_path, noc_model); + } + + SECTION("Test case where the destination router and the starting routers are located on the same row, and the route is eastward.") { + // choose start router as 19, and choose the destination router as 12 + auto start_router_id = NocRouterId(41); + auto sink_router_id = NocRouterId(47); + auto traffic_flow_id = NocTrafficFlowId(76); + + // build the golden route that we expect the algorithm to produce + // the expectation is a number of links that path horizontally from router 7 to router 4 + std::vector golden_path; + + for (int current_router = 41; current_router != 47; current_router++) { + NocLinkId link_id = noc_model.get_single_noc_link_id(NocRouterId(current_router), NocRouterId(current_router + 1)); + const NocLink& link = noc_model.get_single_noc_link(link_id); + golden_path.push_back(link); + } + + // store the route found by the algorithm + std::vector found_path; + + // now run the algorithm to find a route, once again we expect no errors and a legal path to be found + REQUIRE_NOTHROW(routing_algorithm.route_flow(start_router_id, sink_router_id, traffic_flow_id, found_path, noc_model)); + + // make sure that size of the found route and golden route match + compare_routes(golden_path, found_path, noc_model); + } + + SECTION("Test case where the destination router and the starting routers are located on the same column within the FPGA device, and the route is northward") { + // choose start router as 15, and choose the destination router as 75 + auto start_router_id = NocRouterId(15); + auto sink_router_id = NocRouterId(75); + auto traffic_flow_id = NocTrafficFlowId(35); + + // build the golden route that we expect the algorithm to produce + // the expectation is a number of links that path vertically from router 15 to router 75 + std::vector golden_path; + + for (int current_row = 1; current_row < 7; current_row++) { + NocLinkId link_id = noc_model.get_single_noc_link_id(NocRouterId(current_row * 10 + 5), NocRouterId((current_row + 1) * 10 + 5)); + const NocLink& link = noc_model.get_single_noc_link(link_id); + golden_path.push_back(link); + } + + // store the route found by the algorithm + std::vector found_path; + + // now run the algorithm to find a route, once again we expect no errors and a legal path to be found + REQUIRE_NOTHROW(routing_algorithm.route_flow(start_router_id, sink_router_id, traffic_flow_id, found_path, noc_model)); + + // make sure that size of the found route and golden route match + compare_routes(golden_path, found_path, noc_model); + } + + SECTION("Test case where the destination router and the starting routers are located on the same column within the FPGA device, and the route is southward") { + // choose start router as 82, and choose the destination router as 22 + auto start_router_id = NocRouterId(82); + auto sink_router_id = NocRouterId(22); + auto traffic_flow_id = NocTrafficFlowId(9); + + // build the golden route that we expect the algorithm to produce + // the expectation is a number of links that path vertically from router 15 to router 75 + std::vector golden_path; + + for (int current_row = 8; current_row > 2; current_row--) { + NocLinkId link_id = noc_model.get_single_noc_link_id(NocRouterId(current_row * 10 + 2), NocRouterId((current_row - 1) * 10 + 2)); + const NocLink& link = noc_model.get_single_noc_link(link_id); + golden_path.push_back(link); + } + + // store the route found by the algorithm + std::vector found_path; + + // now run the algorithm to find a route, once again we expect no errors and a legal path to be found + REQUIRE_NOTHROW(routing_algorithm.route_flow(start_router_id, sink_router_id, traffic_flow_id, found_path, noc_model)); + + // make sure that size of the found route and golden route match + compare_routes(golden_path, found_path, noc_model); + } +} + +} \ No newline at end of file diff --git a/vpr/test/test_xy_routing.cpp b/vpr/test/test_xy_routing.cpp index dfaa0ba2599..18f45f1231c 100644 --- a/vpr/test/test_xy_routing.cpp +++ b/vpr/test/test_xy_routing.cpp @@ -342,7 +342,7 @@ TEST_CASE("test_route_flow when it fails in a non mesh topology.", "[vpr_noc_xy_ * For example, looking at the example below, suppose we are trying to route between routers 3 and 1. The XY routing algorithm will first traverse to router 0 as it is towards the direction of router 1. * But then at router 0 the algorithm will go towards router 3 as its now * in the direction of router 1. But then the algorithm will infinitely - * just pinpong between routers 0 and 3. + * just ping-pong between routers 0 and 3. * * The purpose of this test case is to make sure that this situation is * appropriately handled through an error. From ae709925d3c96457ccb131448516886bf75d09bf Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Mon, 15 Jul 2024 17:11:54 -0400 Subject: [PATCH 23/39] test source-destination pair that are arbitrary rows and columns --- vpr/src/noc/noc_traffic_flows.cpp | 8 +++++- vpr/src/noc/noc_traffic_flows.h | 2 ++ vpr/test/test_odd_even_routing.cpp | 44 ++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/vpr/src/noc/noc_traffic_flows.cpp b/vpr/src/noc/noc_traffic_flows.cpp index 795a0316cb6..dbfd20134b5 100644 --- a/vpr/src/noc/noc_traffic_flows.cpp +++ b/vpr/src/noc/noc_traffic_flows.cpp @@ -57,6 +57,11 @@ const std::vector& NocTrafficFlows::get_all_traffic_flow_id() return noc_traffic_flows_ids; } +const vtr::vector& NocTrafficFlows::get_all_traffic_flows() const { + return noc_traffic_flows; +} + + // setters for the traffic flows void NocTrafficFlows::create_noc_traffic_flow(const std::string& source_router_module_name, @@ -200,4 +205,5 @@ void NocTrafficFlows::echo_noc_traffic_flows(char* file_name) { } vtr::fclose(fp); -} \ No newline at end of file +} + diff --git a/vpr/src/noc/noc_traffic_flows.h b/vpr/src/noc/noc_traffic_flows.h index 7db9041a05d..9f36ffe9c35 100644 --- a/vpr/src/noc/noc_traffic_flows.h +++ b/vpr/src/noc/noc_traffic_flows.h @@ -237,6 +237,8 @@ class NocTrafficFlows { */ const std::vector& get_all_traffic_flow_id() const; + const vtr::vector& get_all_traffic_flows() const; + // setters /** diff --git a/vpr/test/test_odd_even_routing.cpp b/vpr/test/test_odd_even_routing.cpp index db0c4473f85..0e52476c601 100644 --- a/vpr/test/test_odd_even_routing.cpp +++ b/vpr/test/test_odd_even_routing.cpp @@ -2,7 +2,9 @@ #include "catch2/matchers/catch_matchers_all.hpp" #include "odd_even_routing.h" +#include "channel_dependency_graph.h" +#include namespace { @@ -42,6 +44,8 @@ TEST_CASE("test_route_flow", "[vpr_noc_odd_even_routing]") { // Create the NoC storage NocStorage noc_model; + vtr::vector_map block_locs; + // store the reference to device grid with // this will be set to the device grid width noc_model.set_device_grid_width((int)10); @@ -50,6 +54,7 @@ TEST_CASE("test_route_flow", "[vpr_noc_odd_even_routing]") { for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { noc_model.add_router((i * 10) + j, j, i, 0, DUMMY_LATENCY); + block_locs.insert((ClusterBlockId)((i * 10) + j), t_block_loc{{j, i, 0, 0}, false}); } } @@ -201,6 +206,45 @@ TEST_CASE("test_route_flow", "[vpr_noc_odd_even_routing]") { // make sure that size of the found route and golden route match compare_routes(golden_path, found_path, noc_model); } + + SECTION("To be named ") { + std::random_device device; + std::mt19937 rand_num_gen(device()); + std::uniform_int_distribution dist(0, 99); + + NocTrafficFlows traffic_flow_storage; + + for (int i = 0; i < 100; i++) { + auto src_blk_id = (ClusterBlockId)dist(rand_num_gen); + + ClusterBlockId dst_blk_id; + do { + dst_blk_id = (ClusterBlockId)dist(rand_num_gen); + } while (src_blk_id == dst_blk_id); + + traffic_flow_storage.create_noc_traffic_flow("dummy_name_1", "dummy_name_2", src_blk_id, dst_blk_id, 1, 1, 1); + } + + traffic_flow_storage.finished_noc_traffic_flows_setup(); + + vtr::vector> traffic_flow_routes(traffic_flow_storage.get_number_of_traffic_flows()); + + for (const auto& [id, traffic_flow] : traffic_flow_storage.get_all_traffic_flows().pairs()) { + + NocRouterId src_router_id = noc_model.get_router_at_grid_location(block_locs[traffic_flow.source_router_cluster_id].loc); + NocRouterId dst_router_id = noc_model.get_router_at_grid_location(block_locs[traffic_flow.sink_router_cluster_id].loc); + + REQUIRE_NOTHROW(routing_algorithm.route_flow(src_router_id, dst_router_id, + id, traffic_flow_routes[id], noc_model)); + } + + ChannelDependencyGraph cdg(noc_model, traffic_flow_storage, traffic_flow_routes, block_locs); + + REQUIRE(cdg.has_cycles() == false); + + } + + } } \ No newline at end of file From 8e2283e736ba7dc9fc373e5cb75ed73960bf8bac Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Mon, 15 Jul 2024 18:11:36 -0400 Subject: [PATCH 24/39] check turn legality in odd-even routing unit test --- vpr/src/noc/turn_model_routing.h | 26 +++++++++++++------------- vpr/test/test_odd_even_routing.cpp | 23 ++++++++++++++++++++--- 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/vpr/src/noc/turn_model_routing.h b/vpr/src/noc/turn_model_routing.h index 41a1fd1f694..ce061a56eed 100644 --- a/vpr/src/noc/turn_model_routing.h +++ b/vpr/src/noc/turn_model_routing.h @@ -102,6 +102,19 @@ class TurnModelRouting : public NocRouting { */ std::vector> get_all_illegal_turns(const NocStorage& noc_model) const; + /** + * @brief Determines whether a turn specified by 3 NoC routers visited in the turn + * is legal. Turn model routing algorithms forbid specific turns in the mesh topology + * to guarantee deadlock-freedom. In addition to turns forbidden by the turn model algorithm, + * 180-degree turns are also illegal. + * + * @param noc_routers Three NoC routers visited in a turn. + * @param noc_is_3d Specifies whether the NoC is 2D or 3D. + * @return True if the turn is legal, otherwise false. + */ + virtual bool is_turn_legal(const std::array, 3>& noc_routers, + const NocStorage& noc_model) const = 0; + protected: /** * @brief This enum describes the all the possible @@ -254,19 +267,6 @@ class TurnModelRouting : public NocRouting { NocTrafficFlowId traffic_flow_id, const NocStorage& noc_model); - /** - * @brief Determines whether a turn specified by 3 NoC routers visited in the turn - * is legal. Turn model routing algorithms forbid specific turns in the mesh topology - * to guarantee deadlock-freedom. In addition to turns forbidden by the turn model algorithm, - * 180-degree turns are also illegal. - * - * @param noc_routers Three NoC routers visited in a turn. - * @param noc_is_3d Specifies whether the NoC is 2D or 3D. - * @return True if the turn is legal, otherwise false. - */ - virtual bool is_turn_legal(const std::array, 3>& noc_routers, - const NocStorage& noc_model) const = 0; - protected: // get_legal_directions() return a reference to this vector to avoid allocating a new vector // each time it is called diff --git a/vpr/test/test_odd_even_routing.cpp b/vpr/test/test_odd_even_routing.cpp index 0e52476c601..e642518076b 100644 --- a/vpr/test/test_odd_even_routing.cpp +++ b/vpr/test/test_odd_even_routing.cpp @@ -37,6 +37,24 @@ void compare_routes(const std::vector& golden_path, } } + +void check_turn_legality(const vtr::vector>& traffic_flow_routes, + const NocStorage& noc_model, + const TurnModelRouting& routing_algorithm) { + + for (const auto& traffic_flow_route : traffic_flow_routes) { + for (size_t i = 0; i < traffic_flow_route.size() - 1; i++) { + const NocLink& noc_link1 = noc_model.get_single_noc_link(traffic_flow_route[i]); + const NocLink& noc_link2 = noc_model.get_single_noc_link(traffic_flow_route[i + 1]); + REQUIRE(noc_link1.get_sink_router() == noc_link2.get_source_router()); + const NocRouter& router_1 = noc_model.get_single_noc_router(noc_link1.get_source_router()); + const NocRouter& router_2 = noc_model.get_single_noc_router(noc_link1.get_sink_router()); + const NocRouter& router_3 = noc_model.get_single_noc_router(noc_link2.get_sink_router()); + REQUIRE(routing_algorithm.is_turn_legal({router_1, router_2, router_3}, noc_model) == true); + } + } +} + TEST_CASE("test_route_flow", "[vpr_noc_odd_even_routing]") { /* Creating a test FPGA device below. The NoC itself will be a 10x10 mesh where * they will span over a grid size of 10x10. So this FPGA will only consist of NoC routers */ @@ -207,7 +225,7 @@ TEST_CASE("test_route_flow", "[vpr_noc_odd_even_routing]") { compare_routes(golden_path, found_path, noc_model); } - SECTION("To be named ") { + SECTION("Test case where multiple traffic flows are router, and routes are checked for turn legality and deadlock freedom.") { std::random_device device; std::mt19937 rand_num_gen(device()); std::uniform_int_distribution dist(0, 99); @@ -242,9 +260,8 @@ TEST_CASE("test_route_flow", "[vpr_noc_odd_even_routing]") { REQUIRE(cdg.has_cycles() == false); + check_turn_legality(traffic_flow_routes, noc_model, routing_algorithm); } - - } } \ No newline at end of file From 75228d4769ecb253b0915ac83eb5e838b53323e0 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Tue, 16 Jul 2024 18:06:17 -0400 Subject: [PATCH 25/39] add a 3d noc arch file --- ..._inter_die_3dnoc_stratixiv_arch.timing.xml | 48627 ++++++++++++++++ 1 file changed, 48627 insertions(+) create mode 100644 vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml diff --git a/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml b/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml new file mode 100644 index 00000000000..a730e583cdf --- /dev/null +++ b/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml @@ -0,0 +1,48627 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + io.core_out[0:19] + io.core_in[0:24] io.clk[0:2] + io.core_out[20:39] + io.core_in[24:49] io.clk[3:4] + io.core_out[0:19] + io.core_in[0:24] io.clk[0:2] + io.core_out[20:39] + io.core_in[24:49] io.clk[3:4] + + + + + + + + + + + + + + + PLL.out_clock PLL.out_signal + PLL.in_signal PLL.in_clock + PLL.out_clock PLL.out_signal + PLL.in_signal PLL.in_clock + PLL.out_clock PLL.out_signal + PLL.in_signal PLL.in_clock + PLL.out_clock PLL.out_signal + PLL.in_signal PLL.in_clock + + + + + + + + + + + + + + + + + + + + + + + + + + + LAB.data_out[0:19] + LAB.data_in[0:39] LAB.control_in[0:3] LAB.clk[0] + LAB.data_out[20:39] + LAB.data_in[40:79] LAB.control_in[4:6] LAB.clk[1] + LAB.data_out + LAB.data_in LAB.control_in LAB.clk LAB.cin LAB.sharein + LAB.cout LAB.shareout + + + + + + + + + + + + + + + + + + + + + + + + + + + DSP.data_out_top[17:0] DSP.scan_a_out[1:0] + DSP.data_in[35:0] DSP.control_in[2:0] DSP.scan_a_in[1:0] DSP.clk[0] + DSP.data_out_top[35:18] DSP.scan_a_out[3:2] DSP.signal_out[0:0] + DSP.data_in[71:36] DSP.control_in[4:3] DSP.scan_a_in[4:2] + DSP.data_out_top[53:36] DSP.scan_a_out[5:4] DSP.signal_out[1:1] + DSP.data_in[107:72] DSP.control_in[6:5] DSP.scan_a_in[6:5] DSP.clk[1] + DSP.data_out_top[71:54] DSP.scan_a_out[7:6] DSP.signal_out[2:2] + DSP.data_in[144:108] DSP.control_in[8:6] DSP.scan_a_in[8:7] + DSP.data_out_top[35:0] DSP.scan_a_out[3:0] DSP.signal_out[0:0] + DSP.data_in[143:72] DSP.control_in[3:0] DSP.scan_a_in[3:0] DSP.clk[0] DSP.chain_in + DSP.data_out_top[71:36] DSP.scan_a_out[9:4] DSP.signal_out[2:1] + DSP.data_in[71:0] DSP.control_in[8:4] DSP.scan_a_in[8:4] DSP.clk[1] + + + + DSP.data_out_bot[17:0] DSP.scan_a_out[9:8] + DSP.data_in[179:145] DSP.control_in[11:9] DSP.scan_a_in[10:9] DSP.clk[2] + DSP.data_out_bot[35:18] DSP.scan_a_out[11:10] DSP.signal_out[3:3] + DSP.data_in[215:180] DSP.control_in[13:12] DSP.scan_a_in[12:11] + DSP.data_out_bot[53:36] DSP.scan_a_out[13:12] DSP.signal_out[4:4] + DSP.data_in[251:216] DSP.control_in[15:14] DSP.scan_a_in[14:13] + DSP.data_out_bot[71:54] DSP.scan_a_out[15:14] DSP.signal_out[5:5] + DSP.data_in[287:252] DSP.control_in[20:16] DSP.scan_a_in[17:15] DSP.clk[3] + DSP.data_out_bot[35:0] DSP.scan_a_out[12:10] DSP.signal_out[3:3] + DSP.data_in[287:215] DSP.control_in[13:9] DSP.scan_a_in[13:9] DSP.clk[2] + DSP.data_out_bot[71:36] DSP.scan_a_out[17:13] DSP.signal_out[5:4] + DSP.data_in[214:144] DSP.control_in[20:16] DSP.scan_a_in[17:14] DSP.clk[3] + + DSP.chain_out + + + + + + + + + + + + + + + + + + M9K.data_out[17:0] M9K.control_out[1:0] + M9K.data_addr_control_in[51:0] M9K.clk_in[0] + M9K.data_out[35:18] M9K.control_out[2:2] + M9K.data_addr_control_in[103:52] M9K.clk_in[1] + M9K.data_out M9K.control_out + M9K.data_addr_control_in M9K.clk_in + + + + + + + + + + + + + + + + + + + M144K.data_out[7:0] + M144K.data_addr_control_in[24:0] + M144K.data_out[15:8] + M144K.data_addr_control_in[50:25] + M144K.data_out[22:16] + M144K.data_addr_control_in[76:51] + M144K.data_out[29:23] + M144K.data_addr_control_in[102:77] + M144K.data_out[36:30] M144K.control_out[0] + M144K.data_addr_control_in[128:103] M144K.clk_in[0] + M144K.data_out[43:37] M144K.control_out[1] + M144K.data_addr_control_in[154:129] + M144K.data_out[51:44] + M144K.data_addr_control_in[180:155] + M144K.data_out[59:52] + M144K.data_addr_control_in[206:181] + M144K.data_out[67:60] + M144K.data_addr_control_in[232:207] + M144K.data_out[75:68] + M144K.data_addr_control_in[258:233] + M144K.data_out[82:76] + M144K.data_addr_control_in[284:259] + M144K.data_out[89:83] M144K.control_out[2] + M144K.data_addr_control_in[310:285] + M144K.data_out[96:90] + M144K.data_addr_control_in[336:311] M144K.clk_in[1] + M144K.data_out[103:97] + M144K.data_addr_control_in[362:337] + M144K.data_out[111:104] + M144K.data_addr_control_in[388:363] + M144K.data_out[119:112] + M144K.data_addr_control_in[415:389] + M144K.data_out[14:0] + M144K.data_addr_control_in[51:0] + M144K.data_out[29:15] + M144K.data_addr_control_in[103:52] + M144K.data_out[44:30] M144K.control_out[0] + M144K.data_addr_control_in[155:104] + M144K.data_out[59:45] M144K.control_out[1] + M144K.data_addr_control_in[207:156] M144K.clk_in[0] + M144K.data_addr_control_in[259:208] M144K.clk_in[1] + M144K.data_out[74:60] M144K.control_out[2] + M144K.data_out[89:75] + M144K.data_addr_control_in[311:260] + M144K.data_out[104:90] + M144K.data_addr_control_in[363:312] + M144K.data_out[119:105] + M144K.data_addr_control_in[415:364] + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + noc_router_adapter.master_tready noc_router_adapter.master_tvalid noc_router_adapter.master_tdata[31:0] noc_router_adapter.clk noc_router_adapter.reset + noc_router_adapter.master_tstrb[3:0] noc_router_adapter.master_tkeep[3:0] noc_router_adapter.master_tid[7:0] noc_router_adapter.master_tdest[7:0] noc_router_adapter.master_tuser[7:0] noc_router_adapter.master_tlast + noc_router_adapter.slave_tready noc_router_adapter.slave_tvalid noc_router_adapter.slave_tdata[31:0] + noc_router_adapter.slave_tstrb[3:0] noc_router_adapter.slave_tkeep[3:0] noc_router_adapter.slave_tid[7:0] noc_router_adapter.slave_tdest[7:0] noc_router_adapter.slave_tuser[7:0] noc_router_adapter.slave_tlast + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 1 1 1 1 + 1 1 1 1 + + + + + + + 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 + + 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 261e-12 + 261e-12 + 261e-12 + 261e-12 + 261e-12 + 261e-12 + + + 193e-12 + 193e-12 + 193e-12 + 193e-12 + 193e-12 + 193e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 55787af4640539376700c0f7a95ad4a8fdca5368 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Tue, 16 Jul 2024 18:15:29 -0400 Subject: [PATCH 26/39] resize the fixed layout --- ...3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml b/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml index a730e583cdf..cca1ffbbae8 100644 --- a/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml +++ b/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml @@ -5014,7 +5014,7 @@ - + - + - + - + From 638fce2dbc996c569382de8a15fd49946e49ed7d Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Tue, 16 Jul 2024 18:22:41 -0400 Subject: [PATCH 27/39] update config files to add 3d noc arch file --- .../vpr_3d_noc_clique_topology/config/config.txt | 1 + .../vpr_3d_noc_nearest_neighbor_topology/config/config.txt | 1 + .../vpr_3d_noc_star_topology/config/config.txt | 1 + 3 files changed, 3 insertions(+) diff --git a/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_clique_topology/config/config.txt b/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_clique_topology/config/config.txt index 1755640e53e..1f24273e949 100644 --- a/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_clique_topology/config/config.txt +++ b/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_clique_topology/config/config.txt @@ -16,6 +16,7 @@ circuit_list_add=complex_64_noc_clique.blif # Add architectures to list to sweep arch_list_add=3d_10x10_noc_base_stratixiv_up.xml +arch_list_add=3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing # Add NoC Traffic Patterns to list to sweep noc_traffic_list_add=complex_64_noc_clique.flows diff --git a/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_nearest_neighbor_topology/config/config.txt b/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_nearest_neighbor_topology/config/config.txt index 84c43939404..5623c1080b3 100644 --- a/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_nearest_neighbor_topology/config/config.txt +++ b/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_nearest_neighbor_topology/config/config.txt @@ -16,6 +16,7 @@ circuit_list_add=complex_64_noc_nearest_neighbor.blif # Add architectures to list to sweep arch_list_add=3d_10x10_noc_base_stratixiv_up.xml +arch_list_add=3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing # Add NoC Traffic Patterns to list to sweep noc_traffic_list_add=complex_64_noc_nearest_neighbor.flows diff --git a/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_star_topology/config/config.txt b/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_star_topology/config/config.txt index a11fbebb22f..2c5abef1d44 100644 --- a/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_star_topology/config/config.txt +++ b/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_star_topology/config/config.txt @@ -17,6 +17,7 @@ circuit_list_add=complex_64_noc_star.blif # Add architectures to list to sweep arch_list_add=3d_10x10_noc_base_stratixiv_up.xml +arch_list_add=3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing # Add NoC Traffic Patterns to list to sweep noc_traffic_list_add=complex_64_noc_star_no_constraints.flows From 5a9df1fe1fc0a360f071ca55e0adf1933e43a253 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Tue, 16 Jul 2024 18:38:40 -0400 Subject: [PATCH 28/39] fix arch file name in config files --- .../vpr_3d_noc_clique_topology/config/config.txt | 2 +- .../vpr_3d_noc_nearest_neighbor_topology/config/config.txt | 2 +- .../vpr_3d_noc_star_topology/config/config.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_clique_topology/config/config.txt b/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_clique_topology/config/config.txt index 1f24273e949..71f9073e8bc 100644 --- a/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_clique_topology/config/config.txt +++ b/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_clique_topology/config/config.txt @@ -16,7 +16,7 @@ circuit_list_add=complex_64_noc_clique.blif # Add architectures to list to sweep arch_list_add=3d_10x10_noc_base_stratixiv_up.xml -arch_list_add=3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing +arch_list_add=3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml # Add NoC Traffic Patterns to list to sweep noc_traffic_list_add=complex_64_noc_clique.flows diff --git a/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_nearest_neighbor_topology/config/config.txt b/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_nearest_neighbor_topology/config/config.txt index 5623c1080b3..1e206608c23 100644 --- a/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_nearest_neighbor_topology/config/config.txt +++ b/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_nearest_neighbor_topology/config/config.txt @@ -16,7 +16,7 @@ circuit_list_add=complex_64_noc_nearest_neighbor.blif # Add architectures to list to sweep arch_list_add=3d_10x10_noc_base_stratixiv_up.xml -arch_list_add=3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing +arch_list_add=3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml # Add NoC Traffic Patterns to list to sweep noc_traffic_list_add=complex_64_noc_nearest_neighbor.flows diff --git a/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_star_topology/config/config.txt b/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_star_topology/config/config.txt index 2c5abef1d44..bd6c4cb1e5c 100644 --- a/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_star_topology/config/config.txt +++ b/vtr_flow/tasks/regression_tests/vtr_reg_nightly_test5/vpr_3d_noc_star_topology/config/config.txt @@ -17,7 +17,7 @@ circuit_list_add=complex_64_noc_star.blif # Add architectures to list to sweep arch_list_add=3d_10x10_noc_base_stratixiv_up.xml -arch_list_add=3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing +arch_list_add=3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml # Add NoC Traffic Patterns to list to sweep noc_traffic_list_add=complex_64_noc_star_no_constraints.flows From 639ee62deff1d05917b1f3f7ac77b5e39ee759df Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Tue, 16 Jul 2024 18:49:48 -0400 Subject: [PATCH 29/39] add missing expected tags --- libs/libarchfpga/src/read_xml_arch_file_noc_tag.cpp | 2 +- .../3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/libs/libarchfpga/src/read_xml_arch_file_noc_tag.cpp b/libs/libarchfpga/src/read_xml_arch_file_noc_tag.cpp index 1dc995f3f31..65f0d867698 100644 --- a/libs/libarchfpga/src/read_xml_arch_file_noc_tag.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file_noc_tag.cpp @@ -228,7 +228,7 @@ static void process_mesh_topology(pugi::xml_node mesh_topology_tag, constexpr int ATTRIBUTE_CONVERSION_FAILURE = -1; // a list of attributes that should be found for the mesh tag - std::vector expected_router_attributes = {"startx", "endx", "starty", "endy", "size"}; + std::vector expected_router_attributes = {"startx", "endx", "starty", "endy", "startlayer", "endlayer", "size"}; // verify that only the acceptable attributes were supplied pugiutil::expect_only_attributes(mesh_topology_tag, expected_router_attributes, loc_data); diff --git a/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml b/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml index cca1ffbbae8..95cac668b50 100644 --- a/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml +++ b/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml @@ -4810,7 +4810,6 @@ - From 76a41316ca4ad46686ff657156d1fdcc573cebe5 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Wed, 17 Jul 2024 17:07:10 -0400 Subject: [PATCH 30/39] fix typos --- vpr/src/base/read_options.cpp | 2 +- vpr/src/route/router_lookahead_map_utils.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index f14bb940b28..eb0d202d864 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -2661,7 +2661,7 @@ argparse::ArgumentParser create_arg_parser(const std::string& prog_name, t_optio .show_in(argparse::ShowIn::HELP_ONLY); route_timing_grp.add_argument(args.router_first_iteration_timing_report_file, "--router_first_iter_timing_report") - .help("Name of the post first routing iteration timing report file (not generated if unspecfied)") + .help("Name of the post first routing iteration timing report file (not generated if unspecified)") .default_value("") .show_in(argparse::ShowIn::HELP_ONLY); diff --git a/vpr/src/route/router_lookahead_map_utils.cpp b/vpr/src/route/router_lookahead_map_utils.cpp index c48ee90e073..3f2102e72a2 100644 --- a/vpr/src/route/router_lookahead_map_utils.cpp +++ b/vpr/src/route/router_lookahead_map_utils.cpp @@ -409,7 +409,7 @@ t_src_opin_delays compute_router_src_opin_lookahead(bool is_flat) { if (sample_loc.x == OPEN && sample_loc.y == OPEN && sample_loc.layer_num == OPEN) { //No untried instances of the current tile type left - VTR_LOG_WARN("Found no %sample locations for %s in %s\n", + VTR_LOG_WARN("Found no %ssample locations for %s in %s\n", (num_sampled_locs == 0) ? "" : "more ", rr_node_typename[rr_type], device_ctx.physical_tile_types[itile].name); From 89dfb32bb5ffb14fe086b5a7885e3772dfce47b7 Mon Sep 17 00:00:00 2001 From: soheilshahrouz Date: Wed, 17 Jul 2024 17:48:30 -0400 Subject: [PATCH 31/39] spread noc pins across two layers --- ...N_inter_die_3dnoc_stratixiv_arch.timing.xml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml b/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml index 95cac668b50..53c10637709 100644 --- a/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml +++ b/vtr_flow/arch/multi_die/stratixiv_3d/3d_full_OPIN_inter_die_3dnoc_stratixiv_arch.timing.xml @@ -4870,10 +4870,14 @@ - noc_router_adapter.master_tready noc_router_adapter.master_tvalid noc_router_adapter.master_tdata[31:0] noc_router_adapter.clk noc_router_adapter.reset - noc_router_adapter.master_tstrb[3:0] noc_router_adapter.master_tkeep[3:0] noc_router_adapter.master_tid[7:0] noc_router_adapter.master_tdest[7:0] noc_router_adapter.master_tuser[7:0] noc_router_adapter.master_tlast - noc_router_adapter.slave_tready noc_router_adapter.slave_tvalid noc_router_adapter.slave_tdata[31:0] - noc_router_adapter.slave_tstrb[3:0] noc_router_adapter.slave_tkeep[3:0] noc_router_adapter.slave_tid[7:0] noc_router_adapter.slave_tdest[7:0] noc_router_adapter.slave_tuser[7:0] noc_router_adapter.slave_tlast + noc_router_adapter.master_tready noc_router_adapter.master_tdata[31:16] noc_router_adapter.reset + noc_router_adapter.master_tvalid noc_router_adapter.master_tdata[15:0] noc_router_adapter.clk + noc_router_adapter.master_tstrb[3:0] noc_router_adapter.master_tid[7:0] noc_router_adapter.master_tuser[7:0] + noc_router_adapter.master_tkeep[3:0] noc_router_adapter.master_tdest[7:0] noc_router_adapter.master_tlast + noc_router_adapter.slave_tready noc_router_adapter.slave_tdata[31:16] + noc_router_adapter.slave_tvalid noc_router_adapter.slave_tdata[15:0] + noc_router_adapter.slave_tstrb[3:0] noc_router_adapter.slave_tid[7:0] noc_router_adapter.slave_tlast + noc_router_adapter.slave_tkeep[3:0] noc_router_adapter.slave_tdest[7:0] noc_router_adapter.slave_tuser[7:0] @@ -5013,7 +5017,7 @@ - + - + - +