From ad67564356e41d2e2c25f70ffb2cbfbc8733247e Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 1 Nov 2021 12:53:21 -0400 Subject: [PATCH 001/128] adding support to be able to process architecture descriptions that include a Network on chip --- libs/libarchfpga/src/arch_util.cpp | 4 + libs/libarchfpga/src/physical_types.h | 25 +++ libs/libarchfpga/src/read_xml_arch_file.cpp | 205 ++++++++++++++++++++ 3 files changed, 234 insertions(+) diff --git a/libs/libarchfpga/src/arch_util.cpp b/libs/libarchfpga/src/arch_util.cpp index de804a63b66..d5bf7ef218e 100644 --- a/libs/libarchfpga/src/arch_util.cpp +++ b/libs/libarchfpga/src/arch_util.cpp @@ -204,6 +204,10 @@ void free_arch(t_arch* arch) { if (arch->clocks) { vtr::free(arch->clocks->clock_inf); } + + if (arch->noc) { + vtr::free(arch->noc); + } } //Frees all models in the linked list diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index 8eeb821a5de..c744a1c3f61 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -1771,6 +1771,28 @@ struct t_lut_element { bool operator==(const t_lut_element& other) const { return site_type == other.site_type && width == other.width && lut_bels == other.lut_bels; } + +}; + +/* Network-on-chip(NoC) Router data type used to identify +connections regarding individual routers in the network. */ +struct t_router { + int id = -1; + + int device_x_position = -1; + int device_y_position = -1; + + std::vector connection_list; +}; + +/* Network-on-chip(NoC) data type used to store the network +properties and used when builidng a dedicated on-chip network*/ +struct t_noc_inf { + int link_bandwidth; // in Gbps + int link_latency; // in nanoseconds + int router_latency; // in nanoseconds + + std::vector router_list; }; /* Detailed routing architecture */ @@ -1833,6 +1855,9 @@ struct t_arch { std::vector grid_layouts; //Set of potential device layouts t_clock_arch_spec clock_arch; // Clock related data types + + // if we have an embedded NoC in the architecture, then we store it here + t_noc_inf* noc = nullptr; }; #endif diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index b59aa86b93e..b0a3460f79d 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -251,6 +251,12 @@ static void ProcessPower(pugi::xml_node parent, static void ProcessClocks(pugi::xml_node Parent, t_clock_arch* clocks, const pugiutil::loc_data& loc_data); +static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc_data& loc_data); + +static void processTopology(pugi::xml_node topology_tag, t_arch* arch, const pugiutil::loc_data& loc_data); + +static void processRouter(pugi::xml_node router_tag, t_arch* arch, const pugiutil::loc_data& loc_data); + static void ProcessPb_TypePowerEstMethod(pugi::xml_node Parent, t_pb_type* pb_type, const pugiutil::loc_data& loc_data); static void ProcessPb_TypePort_Power(pugi::xml_node Parent, t_port* port, e_power_estimation_method power_method, const pugiutil::loc_data& loc_data); @@ -266,6 +272,8 @@ e_side string_to_side(std::string side_str); template static T* get_type_by_name(const char* type_name, std::vector& types); +static bool parse_noc_router_connection_list(std::vector* connection_list, std::string connection_list_attribute_value); + /* * * @@ -4512,6 +4520,158 @@ static void ProcessClocks(pugi::xml_node Parent, t_clock_arch* clocks, const pug /* get the next clock item */ Node = Node.next_sibling(Node.name()); } + + +} + +static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc_data& loc_data) +{ + // a vector representing all the possible attributes within the noc tag + std::vector expected_noc_attributes = {"link_bandwidth", "link_latency", "router_latency"}; + + std::vector expected_noc_children_tags = {"topology"}; + + pugi::xml_node noc_topology; + + // if we are here, then the user has a NoC in their architecture, so need to add it + arch->noc = (t_noc_inf*)vtr::malloc(sizeof(t_noc_inf)); + t_noc_inf* noc_ref = arch->noc; + + /* process the noc attributes first */ + + // quick error check to make sure that we dont have unexpected attributes + pugiutil::expect_only_attributes(noc_tag, expected_noc_attributes, loc_data); + + // now go through and parse the required attributes for noc tag + noc_ref->link_bandwidth = pugiutil::get_attribute(noc_tag, "link_bandwidth", loc_data, pugiutil::REQUIRED).as_int(); + + noc_ref->link_latency = pugiutil::get_attribute(noc_tag, "link_latency", loc_data, pugiutil::REQUIRED).as_int(); + + noc_ref->router_latency = pugiutil::get_attribute(noc_tag, "router_latency", loc_data, pugiutil::REQUIRED).as_int(); + + // the noc parameters can only be non-zero positive values + if ((noc_ref->link_bandwidth <= 0) || (noc_ref->link_latency <= 0) || (noc_ref->router_latency <= 0)) + { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(noc_tag), + "The link bandwidth, link latency and router latency for the NoC must be a positive non-zero value."); + } + + /* We processed the NoC node, so now process the topology*/ + + // make sure that only the topology tag is found under NoC + pugiutil::expect_only_children(noc_tag, expected_noc_children_tags, loc_data); + + noc_topology = pugiutil::get_single_child(noc_tag, "topology", loc_data, pugiutil::REQUIRED); + + processTopology(noc_topology, arch, loc_data); + + + + + + + + + + + + + + + + return; +} + +static void processTopology(pugi::xml_node topology_tag, t_arch* arch, const pugiutil::loc_data& loc_data) +{ + // The topology tag should have no attributes, check that + pugiutil::expect_only_attributes(topology_tag, {}, loc_data); + + /* a tracker that stores all the routers (using id) that should + be within the noc (based on connections). And keeps a record + of whether the router was included within the topology description. + */ + std::unordered_map router_list; + + /* Now go through the children tags of topology, which is basically + each router found within the NoC + */ + for (pugi::xml_node router : topology_tag.children()) { + // we can only have router tags within the topology + if (router.name() != std::string("router")) { + bad_tag(router, loc_data, topology_tag, {"router"}); + } + else { + // curent tag is a valid router, so process it + processRouter(router, arch, loc_data); + } + } + + return; +} + +static void processRouter(pugi::xml_node router_tag, t_arch* arch, const pugiutil::loc_data& loc_data) +{ + // identifier that lets us know when we could not properly convert an attribute value to a integer + int attribute_conversion_failure = -1; + + // an accepted list of attributes for the router tag + std::vector expected_router_attributes = {"id", "positionx", "positiony", "connections"}; + + // variable to store current router info + t_router router_info; + + // router connection list attribute information + std::string router_connection_list_attribute_value; + + // lets us know if there was an error processing the router connection list + bool router_connection_list_result = true; + + // check that only the accepted router attributes are found in the tag + pugiutil::expect_only_attributes(router_tag, expected_router_attributes, loc_data); + + // store the router information from the attributes + router_info.id = pugiutil::get_attribute(router_tag, "id", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); + + router_info.device_x_position = pugiutil::get_attribute(router_tag, "positionx", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); + + router_info.device_y_position = pugiutil::get_attribute(router_tag, "positiony", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); + + // verify whether the attribute information was legal + if ((router_info.id == attribute_conversion_failure) || (router_info.device_x_position == attribute_conversion_failure) || (router_info.device_y_position == attribute_conversion_failure)) { + + archfpga_throw(loc_data.filename_c_str(), loc_data.line(router_tag), + "The router id, and position (x & y) for the router must be a positive number."); + } + + // get the current router connection list as a string + router_connection_list_attribute_value.assign(pugiutil::get_attribute(router_tag, "connections", loc_data, pugiutil::REQUIRED).as_string()); + + // if the connections attrbiute was not provided or it was empty, then we don't process it and throw a warning + + if (router_connection_list_attribute_value.compare("") != 0) + { + // process the router connection list + router_connection_list_result = parse_noc_router_connection_list(&(router_info.connection_list), router_connection_list_attribute_value); + + // check if the user provided a legal router connection list + if (!router_connection_list_result) + { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(router_tag), + "The connections attribute for the router must be a space seperated list of integers, where each integer represents a router id that the current router is connected to"); + } + + } + else + { + VTR_LOGF_WARN(loc_data.filename_c_str(), loc_data.line(router_tag), + "The router with id:%d either has an empty 'connections' attrtibute or does not have any associated connections to other routers in the NoC.", router_info.id); + } + + // at this point the current router information was completely legal, so we store the newly created router within the noc + arch->noc->router_list.push_back(router_info); + + return; } std::string inst_port_to_port_name(std::string inst_port) { @@ -4577,3 +4737,48 @@ static T* get_type_by_name(const char* type_name, std::vector& types) { archfpga_throw(__FILE__, __LINE__, "Could not find type: %s\n", type_name); } + +static bool parse_noc_router_connection_list(std::vector* connection_list, std::string connection_list_attribute_value) +{ + // we wil be modifying the string so store it in a temporary variable + // additinally, we peocess substrings seperated by spaces, so we add a space at the end of the string to be able to process the last sub-string + std::string modified_attribute_value= connection_list_attribute_value + " "; + std::string delimiter = " "; + std::stringstream single_connection; + int converted_connection; + + size_t position = 0; + + bool result = true; + + // find the position of the first space in the connection list string + while ((position = modified_attribute_value.find(delimiter)) != std::string::npos) + { + // the string upto the space represent a single connection, so grab the substring + single_connection << modified_attribute_value.substr(0, position); + + // convert the connection to an integer + single_connection >> converted_connection; + + /* we expect the connection list to be a string of integers seperated by spaces, where each integer represents a router id that the current router is connected to. So we make sure that the router id was an integer. + */ + if (single_connection.fail()) + { + // if we are here, then an integer was not supplied + result = false; + break; + } + + // if we are here then a legal router id was supplied, so store it + connection_list->push_back(converted_connection); + + // before we process the next router connection, we need to delete the substring (current router connection) + modified_attribute_value.erase(0 + position + delimiter.length()); + + // clear the buffer that stores the router connection in a string format for the next iteration + single_connection.clear(); + } + + return result; + +} From 66b81f12fc2425cfe3f7aa0a3a1281d58be27594 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 12 Nov 2021 11:34:40 -0500 Subject: [PATCH 002/128] changed function prototypes to improve readibility --- libs/libarchfpga/src/read_xml_arch_file.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index b0a3460f79d..8a86f76da16 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -272,7 +272,7 @@ e_side string_to_side(std::string side_str); template static T* get_type_by_name(const char* type_name, std::vector& types); -static bool parse_noc_router_connection_list(std::vector* connection_list, std::string connection_list_attribute_value); +static bool parse_noc_router_connection_list(std::vector& connection_list, std::string connection_list_attribute_value); /* * @@ -4644,7 +4644,7 @@ static void processRouter(pugi::xml_node router_tag, t_arch* arch, const pugiuti "The router id, and position (x & y) for the router must be a positive number."); } - // get the current router connection list as a string + // get the current router connection list router_connection_list_attribute_value.assign(pugiutil::get_attribute(router_tag, "connections", loc_data, pugiutil::REQUIRED).as_string()); // if the connections attrbiute was not provided or it was empty, then we don't process it and throw a warning @@ -4652,7 +4652,7 @@ static void processRouter(pugi::xml_node router_tag, t_arch* arch, const pugiuti if (router_connection_list_attribute_value.compare("") != 0) { // process the router connection list - router_connection_list_result = parse_noc_router_connection_list(&(router_info.connection_list), router_connection_list_attribute_value); + router_connection_list_result = parse_noc_router_connection_list(router_info.connection_list, router_connection_list_attribute_value); // check if the user provided a legal router connection list if (!router_connection_list_result) @@ -4738,7 +4738,7 @@ static T* get_type_by_name(const char* type_name, std::vector& types) { "Could not find type: %s\n", type_name); } -static bool parse_noc_router_connection_list(std::vector* connection_list, std::string connection_list_attribute_value) +static bool parse_noc_router_connection_list(std::vector& connection_list, std::string connection_list_attribute_value) { // we wil be modifying the string so store it in a temporary variable // additinally, we peocess substrings seperated by spaces, so we add a space at the end of the string to be able to process the last sub-string @@ -4770,7 +4770,7 @@ static bool parse_noc_router_connection_list(std::vector* connection_list, } // if we are here then a legal router id was supplied, so store it - connection_list->push_back(converted_connection); + connection_list.push_back(converted_connection); // before we process the next router connection, we need to delete the substring (current router connection) modified_attribute_value.erase(0 + position + delimiter.length()); From 97861ba6f65633e3573f41ca5378c8b97f2cce0f Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 19 Nov 2021 22:41:09 -0500 Subject: [PATCH 003/128] fixed a vector initialization bug, a bug related to parsing an attribute and modified some function prototypes --- libs/libarchfpga/src/arch_util.cpp | 2 +- libs/libarchfpga/src/read_xml_arch_file.cpp | 60 +++++++++++++-------- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/libs/libarchfpga/src/arch_util.cpp b/libs/libarchfpga/src/arch_util.cpp index d5bf7ef218e..b8b22d2f90e 100644 --- a/libs/libarchfpga/src/arch_util.cpp +++ b/libs/libarchfpga/src/arch_util.cpp @@ -206,7 +206,7 @@ void free_arch(t_arch* arch) { } if (arch->noc) { - vtr::free(arch->noc); + delete (arch->noc); } } diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index 8a86f76da16..32703c391a7 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -253,9 +253,9 @@ static void ProcessClocks(pugi::xml_node Parent, t_clock_arch* clocks, const pug static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc_data& loc_data); -static void processTopology(pugi::xml_node topology_tag, t_arch* arch, const pugiutil::loc_data& loc_data); +static void processTopology(pugi::xml_node topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref); -static void processRouter(pugi::xml_node router_tag, t_arch* arch, const pugiutil::loc_data& loc_data); +static void processRouter(pugi::xml_node router_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref); static void ProcessPb_TypePowerEstMethod(pugi::xml_node Parent, t_pb_type* pb_type, const pugiutil::loc_data& loc_data); static void ProcessPb_TypePort_Power(pugi::xml_node Parent, t_port* port, e_power_estimation_method power_method, const pugiutil::loc_data& loc_data); @@ -436,6 +436,14 @@ void XmlReadArch(const char* ArchFile, free(clocks_fake); } } + + // process NoC (optional) + Next = get_single_child(architecture, "noc", loc_data, pugiutil::OPTIONAL); + + if (Next){ + ProcessNoc(Next, arch, loc_data); + } + SyncModelsPbTypes(arch, LogicalBlockTypes); check_models(arch); @@ -4533,8 +4541,11 @@ static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc pugi::xml_node noc_topology; + // identifier that lets us know when we could not properly convert an attribute value to a integer + int attribute_conversion_failure = -1; + // if we are here, then the user has a NoC in their architecture, so need to add it - arch->noc = (t_noc_inf*)vtr::malloc(sizeof(t_noc_inf)); + arch->noc = new t_noc_inf; t_noc_inf* noc_ref = arch->noc; /* process the noc attributes first */ @@ -4543,17 +4554,17 @@ static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc pugiutil::expect_only_attributes(noc_tag, expected_noc_attributes, loc_data); // now go through and parse the required attributes for noc tag - noc_ref->link_bandwidth = pugiutil::get_attribute(noc_tag, "link_bandwidth", loc_data, pugiutil::REQUIRED).as_int(); + noc_ref->link_bandwidth = pugiutil::get_attribute(noc_tag, "link_bandwidth", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); - noc_ref->link_latency = pugiutil::get_attribute(noc_tag, "link_latency", loc_data, pugiutil::REQUIRED).as_int(); + noc_ref->link_latency = pugiutil::get_attribute(noc_tag, "link_latency", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); - noc_ref->router_latency = pugiutil::get_attribute(noc_tag, "router_latency", loc_data, pugiutil::REQUIRED).as_int(); + noc_ref->router_latency = pugiutil::get_attribute(noc_tag, "router_latency", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); // the noc parameters can only be non-zero positive values - if ((noc_ref->link_bandwidth <= 0) || (noc_ref->link_latency <= 0) || (noc_ref->router_latency <= 0)) + if ((noc_ref->link_bandwidth < 0) || (noc_ref->link_latency < 0) || (noc_ref->router_latency < 0)) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(noc_tag), - "The link bandwidth, link latency and router latency for the NoC must be a positive non-zero value."); + "The link bandwidth, link latency and router latency for the NoC must be a positive non-zero integer."); } /* We processed the NoC node, so now process the topology*/ @@ -4563,7 +4574,7 @@ static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc noc_topology = pugiutil::get_single_child(noc_tag, "topology", loc_data, pugiutil::REQUIRED); - processTopology(noc_topology, arch, loc_data); + processTopology(noc_topology, loc_data, noc_ref); @@ -4582,17 +4593,11 @@ static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc return; } -static void processTopology(pugi::xml_node topology_tag, t_arch* arch, const pugiutil::loc_data& loc_data) +static void processTopology(pugi::xml_node topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref) { // The topology tag should have no attributes, check that pugiutil::expect_only_attributes(topology_tag, {}, loc_data); - /* a tracker that stores all the routers (using id) that should - be within the noc (based on connections). And keeps a record - of whether the router was included within the topology description. - */ - std::unordered_map router_list; - /* Now go through the children tags of topology, which is basically each router found within the NoC */ @@ -4603,14 +4608,23 @@ static void processTopology(pugi::xml_node topology_tag, t_arch* arch, const pug } else { // curent tag is a valid router, so process it - processRouter(router, arch, loc_data); + processRouter(router, loc_data, noc_ref); } } + // check whether any routers were supplied + if (noc_ref->router_list.size() == 0) + { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(topology_tag), + "No routers were supplied for the NoC."); + } + + std::cout << noc_ref->router_list.size() << "\n"; + return; } -static void processRouter(pugi::xml_node router_tag, t_arch* arch, const pugiutil::loc_data& loc_data) +static void processRouter(pugi::xml_node router_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref) { // identifier that lets us know when we could not properly convert an attribute value to a integer int attribute_conversion_failure = -1; @@ -4638,7 +4652,7 @@ static void processRouter(pugi::xml_node router_tag, t_arch* arch, const pugiuti router_info.device_y_position = pugiutil::get_attribute(router_tag, "positiony", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); // verify whether the attribute information was legal - if ((router_info.id == attribute_conversion_failure) || (router_info.device_x_position == attribute_conversion_failure) || (router_info.device_y_position == attribute_conversion_failure)) { + if ((router_info.id < 0) || (router_info.device_x_position < 0) || (router_info.device_y_position < 0)) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(router_tag), "The router id, and position (x & y) for the router must be a positive number."); @@ -4658,18 +4672,18 @@ static void processRouter(pugi::xml_node router_tag, t_arch* arch, const pugiuti if (!router_connection_list_result) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(router_tag), - "The connections attribute for the router must be a space seperated list of integers, where each integer represents a router id that the current router is connected to"); + "The 'connections' attribute for the router must be a list of integers seperated by spaces, where each integer represents a router id that the current router is connected to."); } } else { VTR_LOGF_WARN(loc_data.filename_c_str(), loc_data.line(router_tag), - "The router with id:%d either has an empty 'connections' attrtibute or does not have any associated connections to other routers in the NoC.", router_info.id); + "The router with id:%d either has an empty 'connections' attrtibute or does not have any associated connections to other routers in the NoC.\n", router_info.id); } // at this point the current router information was completely legal, so we store the newly created router within the noc - arch->noc->router_list.push_back(router_info); + noc_ref->router_list.push_back(router_info); return; } @@ -4773,7 +4787,7 @@ static bool parse_noc_router_connection_list(std::vector& connection_list, connection_list.push_back(converted_connection); // before we process the next router connection, we need to delete the substring (current router connection) - modified_attribute_value.erase(0 + position + delimiter.length()); + modified_attribute_value.erase(0, position + delimiter.length()); // clear the buffer that stores the router connection in a string format for the next iteration single_connection.clear(); From e66973cb64572c2dac0caf1d8b966ca9836df823 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 22 Nov 2021 23:26:40 -0500 Subject: [PATCH 004/128] added support to verify a provided noc topology within the architecture file --- libs/libarchfpga/src/read_xml_arch_file.cpp | 106 ++++++++++++++++++-- 1 file changed, 99 insertions(+), 7 deletions(-) diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index 32703c391a7..9b9075ffeaa 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -255,7 +255,7 @@ static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc static void processTopology(pugi::xml_node topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref); -static void processRouter(pugi::xml_node router_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref); +static void processRouter(pugi::xml_node router_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, std::map>&routers_info_in_arch); static void ProcessPb_TypePowerEstMethod(pugi::xml_node Parent, t_pb_type* pb_type, const pugiutil::loc_data& loc_data); static void ProcessPb_TypePort_Power(pugi::xml_node Parent, t_port* port, e_power_estimation_method power_method, const pugiutil::loc_data& loc_data); @@ -272,7 +272,11 @@ e_side string_to_side(std::string side_str); template static T* get_type_by_name(const char* type_name, std::vector& types); -static bool parse_noc_router_connection_list(std::vector& connection_list, std::string connection_list_attribute_value); +static bool parse_noc_router_connection_list(std::vector& connection_list, std::string connection_list_attribute_value, std::map>&routers_in_arch_info); + +static void update_router_info_in_arch(int router_id, bool router_updated_as_a_connection, std::map>&routers_in_arch_info); + +static void verify_noc_topology(std::map>&routers_in_arch_info); /* * @@ -4598,6 +4602,10 @@ static void processTopology(pugi::xml_node topology_tag, const pugiutil::loc_dat // The topology tag should have no attributes, check that pugiutil::expect_only_attributes(topology_tag, {}, loc_data); + // stores router information that includes the number of connections a router has within a given topology and also the number of times a router was declared in the arch file using the tag + // in the datastructure below, the router id is the key and stored data is a pair, where the first element is describes the number router declarations and the second element describes the numbe router connections + std::map> routers_in_arch_info; + /* Now go through the children tags of topology, which is basically each router found within the NoC */ @@ -4608,7 +4616,8 @@ static void processTopology(pugi::xml_node topology_tag, const pugiutil::loc_dat } else { // curent tag is a valid router, so process it - processRouter(router, loc_data, noc_ref); + processRouter(router, loc_data, noc_ref, routers_in_arch_info); + } } @@ -4619,12 +4628,13 @@ static void processTopology(pugi::xml_node topology_tag, const pugiutil::loc_dat "No routers were supplied for the NoC."); } - std::cout << noc_ref->router_list.size() << "\n"; + // check that the topology of the noc was correctly described in the arch file + verify_noc_topology(routers_in_arch_info); return; } -static void processRouter(pugi::xml_node router_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref) +static void processRouter(pugi::xml_node router_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, std::map>&routers_in_arch_info) { // identifier that lets us know when we could not properly convert an attribute value to a integer int attribute_conversion_failure = -1; @@ -4666,7 +4676,7 @@ static void processRouter(pugi::xml_node router_tag, const pugiutil::loc_data& l if (router_connection_list_attribute_value.compare("") != 0) { // process the router connection list - router_connection_list_result = parse_noc_router_connection_list(router_info.connection_list, router_connection_list_attribute_value); + router_connection_list_result = parse_noc_router_connection_list(router_info.connection_list, router_connection_list_attribute_value, routers_in_arch_info); // check if the user provided a legal router connection list if (!router_connection_list_result) @@ -4685,6 +4695,9 @@ static void processRouter(pugi::xml_node router_tag, const pugiutil::loc_data& l // at this point the current router information was completely legal, so we store the newly created router within the noc noc_ref->router_list.push_back(router_info); + // update the number of declarations info for the current router (since we just finished processing one tag) + update_router_info_in_arch(router_info.id, false, routers_in_arch_info); + return; } @@ -4752,7 +4765,7 @@ static T* get_type_by_name(const char* type_name, std::vector& types) { "Could not find type: %s\n", type_name); } -static bool parse_noc_router_connection_list(std::vector& connection_list, std::string connection_list_attribute_value) +static bool parse_noc_router_connection_list(std::vector& connection_list, std::string connection_list_attribute_value, std::map>&routers_in_arch_info) { // we wil be modifying the string so store it in a temporary variable // additinally, we peocess substrings seperated by spaces, so we add a space at the end of the string to be able to process the last sub-string @@ -4786,6 +4799,9 @@ static bool parse_noc_router_connection_list(std::vector& connection_list, // if we are here then a legal router id was supplied, so store it connection_list.push_back(converted_connection); + // update the connection information for the current router in the connection list + update_router_info_in_arch(converted_connection, true, routers_in_arch_info); + // before we process the next router connection, we need to delete the substring (current router connection) modified_attribute_value.erase(0, position + delimiter.length()); @@ -4796,3 +4812,79 @@ static bool parse_noc_router_connection_list(std::vector& connection_list, return result; } + +/* Each router needs a sperate tag in the architecture description + to declare it. The number of declarations for each router in the + architecture file is updated here. + + Additionally, for any given topology, a router can connect to other routers. + THe number of connections for each router is also updated here. + +*/ +static void update_router_info_in_arch(int router_id, bool router_updated_as_a_connection, std::map>&routers_in_arch_info) { + + // get the corresponding router info for the given router id + std::map>::iterator curr_router_info = routers_in_arch_info.find(router_id); + + // check if the router previously existed in the router indo database + if (curr_router_info == routers_in_arch_info.end()) { + + // case where the router did not exist previosuly, so we add it here and also get a reference to it + // initially a router has no declarations or connections + curr_router_info = routers_in_arch_info.insert(std::pair>(router_id, std::pair(0, 0))).first; + + } + + // case where the current router was provided while parsing the connections of another router + if (router_updated_as_a_connection) { + + // since we are within the case where the current router is being processed as a connection to another router we just increment its number of connections + (curr_router_info->second.second)++; + + } + else { + + // since we are within the case where the current router is processed from a tag, we just increment its number of declarations + (curr_router_info->second.first)++; + + } + + return; + +} + +/* + Verify each router in the noc by checking whether they satisfy the following conditions: + - The router has only one declaration in the arch file + - The router has atleast one connection to another router + If any of the conditions above are not met, then an error is thrown. +*/ +static void verify_noc_topology(std::map>&routers_in_arch_info) +{ + + for (auto router_info = routers_in_arch_info.begin(); router_info != routers_in_arch_info.end(); router_info++) + { + // case where the router was included in the architecture and had no connections to other routers + if ((router_info->second.first == 1) && (router_info->second.second == 0)) { + + archfpga_throw("",-1, + "The router with id:'%d' is not connected to any other router inb the NoC.", router_info->first); + + } // case where a router was found to be connected to another router but not declared using the tag in the arch file (ie. missing) + else if ((router_info->second.first == 0) && (router_info->second.second > 0)){ + + archfpga_throw("",-1, + "The router with id:'%d' was found to be connected to another router but missing in the architecture file. Add the router using the tag.", router_info->first); + + } // case where the router was delcared multiple times in the architecture file (multiple tags for the same router) + else if (router_info->second.first > 1){ + + archfpga_throw("",-1, + "The router with id:'%d' was included more than once in the architecture file. Routers should only be declared once.", router_info->first); + + } + } + + return; + +} From 4c6e038dca3adae96e2ab038960a2c711d0c83b0 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 23 Nov 2021 14:00:52 -0500 Subject: [PATCH 005/128] added unit tests to the libarchfpga build condifuration --- libs/libarchfpga/CMakeLists.txt | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libs/libarchfpga/CMakeLists.txt b/libs/libarchfpga/CMakeLists.txt index 74523097ef9..0bebf65d883 100644 --- a/libs/libarchfpga/CMakeLists.txt +++ b/libs/libarchfpga/CMakeLists.txt @@ -34,6 +34,15 @@ target_compile_definitions(libarchfpga PUBLIC ${INTERCHANGE_SCHEMA_HEADERS}) add_executable(read_arch ${EXEC_SOURCES}) target_link_libraries(read_arch libarchfpga) +# +# Unit Tests +# +file(GLOB_RECURSE TEST_SOURCES test/*.cpp) +add_executable(test_libarchfpga ${TEST_SOURCES}) +target_link_libraries(test_libarchfpga + libarchfpga + Catch2::Catch2WithMain) + #Supress IPO link warnings if IPO is enabled get_target_property(READ_ARCH_USES_IPO read_arch INTERPROCEDURAL_OPTIMIZATION) if (READ_ARCH_USES_IPO) From ae3fc05c0d52364759073df20c4207c5d3ef75f3 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 7 Dec 2021 15:47:28 -0500 Subject: [PATCH 006/128] added functionality to the architecture file format to support standard topologies such as 'mesh' --- libs/libarchfpga/src/read_xml_arch_file.cpp | 152 +++++++++++++++++++- 1 file changed, 146 insertions(+), 6 deletions(-) diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index 9b9075ffeaa..4e28c266d98 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -255,6 +255,8 @@ static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc static void processTopology(pugi::xml_node topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref); +static void processMeshTopology(pugi::xml_node mesh_topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref); + static void processRouter(pugi::xml_node router_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, std::map>&routers_info_in_arch); static void ProcessPb_TypePowerEstMethod(pugi::xml_node Parent, t_pb_type* pb_type, const pugiutil::loc_data& loc_data); @@ -272,6 +274,8 @@ e_side string_to_side(std::string side_str); template static T* get_type_by_name(const char* type_name, std::vector& types); +static void generate_noc_mesh(pugi::xml_node mesh_topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, int mesh_region_start_x, int mesh_region_end_x, int mesh_region_start_y, int mesh_region_end_y, int mesh_size); + static bool parse_noc_router_connection_list(std::vector& connection_list, std::string connection_list_attribute_value, std::map>&routers_in_arch_info); static void update_router_info_in_arch(int router_id, bool router_updated_as_a_connection, std::map>&routers_in_arch_info); @@ -4541,9 +4545,10 @@ static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc // a vector representing all the possible attributes within the noc tag std::vector expected_noc_attributes = {"link_bandwidth", "link_latency", "router_latency"}; - std::vector expected_noc_children_tags = {"topology"}; + std::vector expected_noc_children_tags = {"mesh","topology"}; pugi::xml_node noc_topology; + pugi::xml_node noc_mesh_topology; // identifier that lets us know when we could not properly convert an attribute value to a integer int attribute_conversion_failure = -1; @@ -4576,25 +4581,80 @@ static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc // make sure that only the topology tag is found under NoC pugiutil::expect_only_children(noc_tag, expected_noc_children_tags, loc_data); - noc_topology = pugiutil::get_single_child(noc_tag, "topology", loc_data, pugiutil::REQUIRED); + noc_mesh_topology = pugiutil::get_single_child(noc_tag, "mesh", loc_data, pugiutil::OPTIONAL); - processTopology(noc_topology, loc_data, noc_ref); + // we cannot check for errors related to number of routers and as well as whether a router is out of bounds (this will be done later) + // the chip still needs to be sized + if (noc_mesh_topology) + { + processMeshTopology(noc_mesh_topology, loc_data, noc_ref); + for (auto i = noc_ref->router_list.begin(); i != noc_ref->router_list.end(); i++) + { + std::cout << "router " << i->id << ": "; + for (auto j = i->connection_list.begin(); j != i->connection_list.end(); j++) + { + std::cout << *j << ","; + } - + std::cout << "\n"; + } + } + else + { + noc_topology = pugiutil::get_single_child(noc_tag, "topology", loc_data, pugiutil::REQUIRED); - + processTopology(noc_topology, loc_data, noc_ref); + } + return; +} +static void processMeshTopology(pugi::xml_node mesh_topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref) +{ + // noc mesh topology properties + int mesh_region_start_x = 0; + int mesh_region_end_x = 0; + int mesh_region_start_y = 0; + int mesh_region_end_y = 0; + int mesh_size = 0; + // identifier that lets us know when we could not properly convert an attribute value to a integer + int attribute_conversion_failure = -1; + + // a list of attrbutes that should be found for the mesh tag + std::vector expected_router_attributes = {"startx", "endx", "starty", "endy", "size"}; + + // verify that only the acceptable attributes were supplied + pugiutil::expect_only_attributes(mesh_topology_tag, expected_router_attributes, loc_data); + + // go through the attributes and store their values + mesh_region_start_x = pugiutil::get_attribute(mesh_topology_tag, "startx", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); + mesh_region_end_x = pugiutil::get_attribute(mesh_topology_tag, "endx", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); + mesh_region_start_y = pugiutil::get_attribute(mesh_topology_tag, "starty", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); + mesh_region_end_y = pugiutil::get_attribute(mesh_topology_tag, "endy", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); + + mesh_size = pugiutil::get_attribute(mesh_topology_tag, "size", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); + + // verify that the attrbiutes provided were legal + if (( mesh_region_start_x < 0) || (mesh_region_end_x < 0) || (mesh_region_start_y < 0) || (mesh_region_end_y < 0) || (mesh_size < 0)) + { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(mesh_topology_tag), + "The parameters for the mesh topology have to be positive integers."); + } + + // now create the mesh topology for the noc + // create routers, make connections and detertmine positions + generate_noc_mesh(mesh_topology_tag, loc_data, noc_ref, mesh_region_start_x, mesh_region_end_x, mesh_region_start_y, mesh_region_end_y, mesh_size); return; + } static void processTopology(pugi::xml_node topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref) @@ -4765,6 +4825,86 @@ static T* get_type_by_name(const char* type_name, std::vector& types) { "Could not find type: %s\n", type_name); } +static void generate_noc_mesh(pugi::xml_node mesh_topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, int mesh_region_start_x, int mesh_region_end_x, int mesh_region_start_y, int mesh_region_end_y, int mesh_size) +{ + + // check that the mesh size of the router is not 0 + if (mesh_size == 0) + { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(mesh_topology_tag), + "The NoC mesh size cannot be 0."); + } + + + // calculating the vertical horizontal distances between routers in the supplied region + // we don't want to use decimals + int vertical_router_seperation = (mesh_region_end_y - mesh_region_start_y)/mesh_size; + int horizontal_router_seperation = (mesh_region_end_x - mesh_region_start_x)/mesh_size; + + t_router temp_router; + + // improper region check + if ( (vertical_router_seperation <= 0) || (horizontal_router_seperation <= 0)) + { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(mesh_topology_tag), + "The NoC region is invalid."); + } + + // create routers and their connections + // start with router id 0 (bottom left of the chip) to the maximum router id (top right of the chip) + for (int i = 0; i < mesh_size; i++) + { + for (int j = 0; j < mesh_size; j++) + { + // assign router id + temp_router.id = (mesh_size * j) + i; + + // calculate router position + temp_router.device_x_position = (i + 1)* horizontal_router_seperation; + temp_router.device_y_position = (j + 1) * vertical_router_seperation; + + // assign connections + // check if there is a router to the left + if ((i - 1) >= 0) + { + // add the left router as a connection + temp_router.connection_list.push_back((mesh_size * j) + i - 1); + } + + // check if there is a router to the top + if ((j + 1) <= (mesh_size - 1)) + { + // add the top router as a connection + temp_router.connection_list.push_back((mesh_size * (j + 1)) + i); + } + + // check if there is a router to the right + if ((i + 1) <= (mesh_size - 1)) + { + // add the router located to the right + temp_router.connection_list.push_back((mesh_size * j) + i + 1); + } + + // check of there is a router below + if ((j - 1) >= (0)) + { + // add the bottom router as a connection + temp_router.connection_list.push_back((mesh_size * (j - 1)) + i); + } + + // add the router to the list + noc_ref->router_list.push_back(temp_router); + + // clear the current router information for the next router + temp_router.connection_list.clear(); + + } + } + + return; + +} + static bool parse_noc_router_connection_list(std::vector& connection_list, std::string connection_list_attribute_value, std::map>&routers_in_arch_info) { // we wil be modifying the string so store it in a temporary variable @@ -4868,7 +5008,7 @@ static void verify_noc_topology(std::map>&routers_in_ar if ((router_info->second.first == 1) && (router_info->second.second == 0)) { archfpga_throw("",-1, - "The router with id:'%d' is not connected to any other router inb the NoC.", router_info->first); + "The router with id:'%d' is not connected to any other router in the NoC.", router_info->first); } // case where a router was found to be connected to another router but not declared using the tag in the arch file (ie. missing) else if ((router_info->second.first == 0) && (router_info->second.second > 0)){ From aaa4687d9997652c6de615676e86a82b9bde176a Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 7 Dec 2021 16:00:03 -0500 Subject: [PATCH 007/128] added unit tests to verify the new features that support nocs in the architectyre file --- libs/libarchfpga/CMakeLists.txt | 16 +- libs/libarchfpga/test/main.cpp | 2 + .../test/test_read_xml_arch_file.cpp | 154 ++++++++++++++++++ 3 files changed, 163 insertions(+), 9 deletions(-) create mode 100644 libs/libarchfpga/test/main.cpp create mode 100644 libs/libarchfpga/test/test_read_xml_arch_file.cpp diff --git a/libs/libarchfpga/CMakeLists.txt b/libs/libarchfpga/CMakeLists.txt index 0bebf65d883..3901c8025eb 100644 --- a/libs/libarchfpga/CMakeLists.txt +++ b/libs/libarchfpga/CMakeLists.txt @@ -34,15 +34,6 @@ target_compile_definitions(libarchfpga PUBLIC ${INTERCHANGE_SCHEMA_HEADERS}) add_executable(read_arch ${EXEC_SOURCES}) target_link_libraries(read_arch libarchfpga) -# -# Unit Tests -# -file(GLOB_RECURSE TEST_SOURCES test/*.cpp) -add_executable(test_libarchfpga ${TEST_SOURCES}) -target_link_libraries(test_libarchfpga - libarchfpga - Catch2::Catch2WithMain) - #Supress IPO link warnings if IPO is enabled get_target_property(READ_ARCH_USES_IPO read_arch INTERPROCEDURAL_OPTIMIZATION) if (READ_ARCH_USES_IPO) @@ -50,3 +41,10 @@ if (READ_ARCH_USES_IPO) endif() install(TARGETS libarchfpga read_arch DESTINATION bin) + +# +# Unit Tests +# +file(GLOB_RECURSE TEST_SOURCES test/*.cpp) +add_executable(test_archfpga ${TEST_SOURCES}) +target_link_libraries(test_archfpga Catch2::Catch2WithMain libarchfpga) diff --git a/libs/libarchfpga/test/main.cpp b/libs/libarchfpga/test/main.cpp new file mode 100644 index 00000000000..7d78b55d895 --- /dev/null +++ b/libs/libarchfpga/test/main.cpp @@ -0,0 +1,2 @@ +#define CATCH_CONFIG_MAIN +//#include "catch2/catch_test_macros.hpp" \ No newline at end of file diff --git a/libs/libarchfpga/test/test_read_xml_arch_file.cpp b/libs/libarchfpga/test/test_read_xml_arch_file.cpp new file mode 100644 index 00000000000..a90b02edfe6 --- /dev/null +++ b/libs/libarchfpga/test/test_read_xml_arch_file.cpp @@ -0,0 +1,154 @@ +// test framework +#include "catch2/catch_test_macros.hpp" +#include "catch2/matchers/catch_matchers_all.hpp" + +// testting statuc functions so include whole source file it is in +#include "read_xml_arch_file.cpp" + +TEST_CASE( "Updating router info in arch", "[NoC Arch Tests]" ) { + + std::map> test_router_list; + + std::map>::iterator it; + + // initial conditions + int router_id = 1; + bool router_is_from_connection_list = false; + + // we initially need the map to be empty + REQUIRE(test_router_list.size() == 0); + + SECTION( "Update the number of declarations for a router for the first time " ) { + + update_router_info_in_arch(router_id, router_is_from_connection_list, test_router_list); + + it = test_router_list.find(router_id); + + // check first that the router was newly added to the router databse + REQUIRE(it != test_router_list.end()); + + // no verify the components of the router parameter + REQUIRE(it->second.first == 1); + REQUIRE(it->second.second == 0); + + } + SECTION( "Update the number of connections for a router for the first time" ) { + + router_is_from_connection_list = true; + + update_router_info_in_arch(router_id, router_is_from_connection_list, test_router_list); + + it = test_router_list.find(router_id); + + // check first that the router was newly added to the router databse + REQUIRE(it != test_router_list.end()); + + // no verify the components of the router parameter + REQUIRE(it->second.first == 0); + REQUIRE(it->second.second == 1); + + } + SECTION( "Update the number of declarations for a router when it already exists" ) { + + update_router_info_in_arch(router_id, router_is_from_connection_list, test_router_list); + + // verify that a router was added + REQUIRE(test_router_list.size() != 0); + + update_router_info_in_arch(router_id, router_is_from_connection_list, test_router_list); + + it = test_router_list.find(router_id); + + // check first that the router was newly added to the router databse + REQUIRE(it != test_router_list.end()); + + // no verify the components of the router parameter + REQUIRE(it->second.first == 2); + REQUIRE(it->second.second == 0); + + } + SECTION( "Update the number of connections for a router when it already exists" ) { + + router_is_from_connection_list = true; + + update_router_info_in_arch(router_id, router_is_from_connection_list, test_router_list); + + // verify that a router was added + REQUIRE(test_router_list.size() != 0); + + update_router_info_in_arch(router_id, router_is_from_connection_list, test_router_list); + + it = test_router_list.find(router_id); + + // check first that the router was newly added to the router databse + REQUIRE(it != test_router_list.end()); + + // no verify the components of the router parameter + REQUIRE(it->second.first == 0); + REQUIRE(it->second.second == 2); + + } + +} + +TEST_CASE( "Verifying a parsed NoC topology", "[NoC Arch Tests]" ) { + + std::map> test_router_list; + + REQUIRE(test_router_list.size() == 0); + + SECTION( "Check the error where a router in the NoC is not connected to other routers." ) { + + // error router + test_router_list.insert(std::pair>(1, std::pair(1,0))); + + // sonme normal routers + test_router_list.insert(std::pair>(2, std::pair(1,5))); + + test_router_list.insert(std::pair>(3, std::pair(1,6))); + + REQUIRE(test_router_list.size() == 3); + + REQUIRE_THROWS_WITH(verify_noc_topology(test_router_list), "The router with id:'1' is not connected to any other router in the NoC."); + + } + SECTION( "Check the error where a router in the NoC is connected to other routers but missing a declaration in the arch file." ) { + + // normal routers + test_router_list.insert(std::pair>(1, std::pair(1,5))); + + test_router_list.insert(std::pair>(2, std::pair(1,3))); + + // error router + test_router_list.insert(std::pair>(3, std::pair(0,5))); + + test_router_list.insert(std::pair>(4, std::pair(1,10))); + + REQUIRE(test_router_list.size() == 4); + + REQUIRE_THROWS_WITH(verify_noc_topology(test_router_list), "The router with id:'3' was found to be connected to another router but missing in the architecture file. Add the router using the tag."); + + } + SECTION( "Check the error where the router is included more than once in the architecture file." ) { + + // normal routers + test_router_list.insert(std::pair>(1, std::pair(1,5))); + + test_router_list.insert(std::pair>(2, std::pair(1,3))); + + test_router_list.insert(std::pair>(3, std::pair(1,10))); + + // error routers + test_router_list.insert(std::pair>(4, std::pair(2,10))); + + // normal routers + test_router_list.insert(std::pair>(5, std::pair(1,3))); + + test_router_list.insert(std::pair>(6, std::pair(1,10))); + + REQUIRE(test_router_list.size() == 6); + + REQUIRE_THROWS_WITH(verify_noc_topology(test_router_list), "The router with id:'4' was included more than once in the architecture file. Routers should only be declared once."); + + } +} \ No newline at end of file From 5b088b630ba3bcadd942b4d80c84a075327eb743 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 14 Dec 2021 20:33:22 -0500 Subject: [PATCH 008/128] added new context variable to represent the NoC --- vpr/src/base/vpr_context.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/vpr/src/base/vpr_context.h b/vpr/src/base/vpr_context.h index d4f5a3a221e..c49da23b7ac 100644 --- a/vpr/src/base/vpr_context.h +++ b/vpr/src/base/vpr_context.h @@ -381,6 +381,16 @@ struct FloorplanningContext : public Context { std::vector overfull_regions; }; +/** + * @brief State of the Network on Chip (NoC) + * + * This should only contain data structures related to descrbing the + * NoC within the device. + */ +struct NocContext : public Context { + +}; + /** * @brief This object encapsulates VPR's state. * @@ -455,6 +465,9 @@ class VprContext : public Context { const FloorplanningContext& floorplanning() const { return constraints_; } FloorplanningContext& mutable_floorplanning() { return constraints_; } + const NocContext& noc() const { return noc_; } + NocContext& mutable_noc() { return noc_; } + private: DeviceContext device_; @@ -467,6 +480,7 @@ class VprContext : public Context { PlacementContext placement_; RoutingContext routing_; FloorplanningContext constraints_; + NocContext noc_; }; #endif From 6fcb368f97271a9e0ca02285aac3c22cbe004461 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 14 Dec 2021 20:44:20 -0500 Subject: [PATCH 009/128] added a new step in the vpr flow to setup noc model if provided as an input. Also added a function that isolates noc router tiles from the device grid. --- vpr/src/base/setup_noc.cpp | 89 ++++++++++++++++++++++++++++++++++++++ vpr/src/base/setup_noc.h | 42 ++++++++++++++++++ vpr/src/base/vpr_api.cpp | 20 +++++++++ vpr/src/base/vpr_api.h | 2 + vpr/src/base/vpr_types.h | 2 + 5 files changed, 155 insertions(+) create mode 100644 vpr/src/base/setup_noc.cpp create mode 100644 vpr/src/base/setup_noc.h diff --git a/vpr/src/base/setup_noc.cpp b/vpr/src/base/setup_noc.cpp new file mode 100644 index 00000000000..8d9f95a7b43 --- /dev/null +++ b/vpr/src/base/setup_noc.cpp @@ -0,0 +1,89 @@ + +#include "setup_noc.h" + +#include "vtr_assert.h" +#include "vpr_error.h" + + +void setup_noc(const t_arch& arch, std::string noc_router_tile_name) +{ + + // variable to store all the noc router tiles within the FPGA device + std::vector list_of_noc_router_tiles; + + // get references to global variables + auto& device_ctx = g_vpr_ctx.device(); + auto& noc_ctx = g_vpr_ctx.mutable_noc(); + + // go through the FPGA grid and find the noc router tiles + // then store the position + identify_and_store_noc_router_tile_positions(device_ctx.grid,list_of_noc_router_tiles, noc_router_tile_name); + + // check whether the noc topology information provided uses more than the number of available routers in the FPGA + if (list_of_noc_router_tiles.size() > arch.noc->router_list.size()) + { + VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Provided NoC topology information in the architecture file has more routers that what is available in the FPGA."); + } + + // check whether the noc topology information provided is using all the routers in the FPGA + if (list_of_noc_router_tiles.size() < arch.noc->router_list.size()) + { + VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Provided NoC topology information in the architecture file has more routers that what is available in the FPGA."); + } + + // generate noc model + generate_noc(arch, noc_ctx); + + + + + + + return; + +} + +void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, std::vector& list_of_noc_router_tiles, std::string noc_router_tile_name) +{ + int grid_width = device_grid.width(); + int grid_height = device_grid.height(); + + int curr_tile_width_offset; + int curr_tile_height_offset; + std::string curr_tile_name; + + // go through the device + for(int i = 0; i < grid_width; i++) + { + + for (int j = 0; j < grid_height; j++) + { + // get some information from the current tile + curr_tile_name.assign(device_grid[i][j].type->name); + curr_tile_width_offset = device_grid[i][j].width_offset; + curr_tile_height_offset = device_grid[i][j].height_offset; + + /* + Only store the tile position if it is a noc router. + Additionally, since a router tile can span multiple grid locations, we only add the tile if the height and width offset are zero (this prevents the router from being added multiple times for each grid location it spans). + */ + if (!((noc_router_tile_name.compare(curr_tile_name)) && curr_tile_width_offset && curr_tile_width_offset)) + { + list_of_noc_router_tiles.push_back({i,j}); + } + + } + } + + return; + +} + +void generate_noc(const t_arch& arch, NocContext& noc_ctx) +{ + + return; + +} + + diff --git a/vpr/src/base/setup_noc.h b/vpr/src/base/setup_noc.h new file mode 100644 index 00000000000..af25ee1e65e --- /dev/null +++ b/vpr/src/base/setup_noc.h @@ -0,0 +1,42 @@ +#ifndef SETUP_NOC +#define SETUP_NOC + +#include +#include +#include + + +#include "physical_types.h" +#include "device_grid.h" +#include "globals.h" + + + +// a data structure to store the position information of a noc router in the FPGA device +struct t_noc_router_tile_position { + + int grid_width_position; + int grid_height_position; + +}; + + +void setup_noc(const t_arch& arch, std::string noc_router_tile_name); + +void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, std::vector& list_of_noc_router_tiles, std::string noc_router_tile_name); + +void generate_noc(const t_arch& arch, NocContext& noc_ctx); + + + + + + + + + + + + + +#endif \ No newline at end of file diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index f4d759a862e..c1927bec0e9 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -38,6 +38,7 @@ #include "place.h" #include "SetupGrid.h" #include "setup_clocks.h" +#include "setup_noc.h" #include "stats.h" #include "read_options.h" #include "echo_files.h" @@ -425,6 +426,16 @@ void vpr_create_device_grid(const t_vpr_setup& vpr_setup, const t_arch& Arch) { float target_device_utilization = vpr_setup.PackerOpts.target_device_utilization; device_ctx.grid = create_device_grid(vpr_setup.device_layout, Arch.grid_layouts, num_type_instances, target_device_utilization); + for(int i = 0; i < device_ctx.grid.width(); i++) + { + for (int j = 0; j < device_ctx.grid.height(); j++) + { + t_grid_tile test = device_ctx.grid[i][j]; + + std::cout << test.height_offset << std::endl; + } + } + /* *Report on the device */ @@ -487,6 +498,15 @@ void vpr_setup_clock_networks(t_vpr_setup& vpr_setup, const t_arch& Arch) { } } +void vpr_setup_noc(const t_vpr_setup& vpr_setup, const t_arch& arch) +{ + // check if the user provided the option to model the noc + if (vpr_setup.include_noc == true) + { + setup_noc(arch, vpr_setup.noc_router_tile_name); + } +} + bool vpr_pack_flow(t_vpr_setup& vpr_setup, const t_arch& arch) { auto& packer_opts = vpr_setup.PackerOpts; diff --git a/vpr/src/base/vpr_api.h b/vpr/src/base/vpr_api.h index d5cc9cb195a..102058bbec0 100644 --- a/vpr/src/base/vpr_api.h +++ b/vpr/src/base/vpr_api.h @@ -126,6 +126,8 @@ void vpr_init_graphics(const t_vpr_setup& vpr_setup, const t_arch& arch); void vpr_close_graphics(const t_vpr_setup& vpr_setup); void vpr_setup_clock_networks(t_vpr_setup& vpr_setup, const t_arch& Arch); +// @brief Create the NoC +void vpr_setup_noc(const t_vpr_setup& vpr_setup, const t_arch& arch); void vpr_free_vpr_data_structures(t_arch& Arch, t_vpr_setup& vpr_setup); void vpr_free_all(t_arch& Arch, t_vpr_setup& vpr_setup); diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index f469e76dbc4..e80118eafb9 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -1631,6 +1631,8 @@ struct t_vpr_setup { e_clock_modeling clock_modeling; /// Date: Wed, 15 Dec 2021 21:16:01 -0500 Subject: [PATCH 010/128] removed unnecessary code used to test some data structures --- vpr/src/base/vpr_api.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index c1927bec0e9..49547b87847 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -426,16 +426,6 @@ void vpr_create_device_grid(const t_vpr_setup& vpr_setup, const t_arch& Arch) { float target_device_utilization = vpr_setup.PackerOpts.target_device_utilization; device_ctx.grid = create_device_grid(vpr_setup.device_layout, Arch.grid_layouts, num_type_instances, target_device_utilization); - for(int i = 0; i < device_ctx.grid.width(); i++) - { - for (int j = 0; j < device_ctx.grid.height(); j++) - { - t_grid_tile test = device_ctx.grid[i][j]; - - std::cout << test.height_offset << std::endl; - } - } - /* *Report on the device */ From b966d70232c266187713ad9752ee28e04e91efb1 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Thu, 6 Jan 2022 23:01:51 -0500 Subject: [PATCH 011/128] created a noc router object --- vpr/src/base/router.cpp | 35 +++++++++++++++++++++++++++++++++++ vpr/src/base/router.h | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) create mode 100644 vpr/src/base/router.cpp create mode 100644 vpr/src/base/router.h diff --git a/vpr/src/base/router.cpp b/vpr/src/base/router.cpp new file mode 100644 index 00000000000..3e60b062805 --- /dev/null +++ b/vpr/src/base/router.cpp @@ -0,0 +1,35 @@ +#include "router.h" + + +Router::Router(int id, int grid_position_x, int grid_position_y):router_id(id), router_grid_position_x(grid_position_x), router_grid_position_y(grid_position_y) +{ +} + +// getters +int Router::get_router_id(void) +{ + return router_id; +} + +int Router::get_router_grid_position_x(void) +{ + return router_grid_position_x; +} + +int Router::get_router_grid_position_y(void) +{ + return router_grid_position_y; +} + +std::string Router::get_router_design_module_name(void) +{ + return router_design_module_name; +} + +// setters +void Router::set_router_design_module_name(std::string design_module_name) +{ + router_design_module_name.assign(design_module_name); + + return; +} \ No newline at end of file diff --git a/vpr/src/base/router.h b/vpr/src/base/router.h new file mode 100644 index 00000000000..fdbb3980d30 --- /dev/null +++ b/vpr/src/base/router.h @@ -0,0 +1,40 @@ +#ifndef ROUTER_H +#define ROUTER_H + +#include +#include + +class Router { + + private: + int router_id; + int router_grid_position_x; + int router_grid_position_y; + + std::string router_design_module_name; + + public: + Router(int id, int grid_position_x, int grid_position_y); + + int get_router_id(void); + int get_router_grid_position_x(void); + int get_router_grid_position_y(void); + + std::string get_router_design_module_name(void); + + // setters + void set_router_design_module_name(std::string design_module_name); + + + +}; + + + + + + + + + +#endif \ No newline at end of file From db4c1f3e3d5d9126493717c5a54a4756bf1cc24d Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 7 Jan 2022 14:42:34 -0500 Subject: [PATCH 012/128] added a noc link object --- vpr/src/base/link.cpp | 3 +++ vpr/src/base/link.h | 43 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 46 insertions(+) create mode 100644 vpr/src/base/link.cpp create mode 100644 vpr/src/base/link.h diff --git a/vpr/src/base/link.cpp b/vpr/src/base/link.cpp new file mode 100644 index 00000000000..349b7f0b546 --- /dev/null +++ b/vpr/src/base/link.cpp @@ -0,0 +1,3 @@ +#include "link.h" + + diff --git a/vpr/src/base/link.h b/vpr/src/base/link.h new file mode 100644 index 00000000000..c5eb1a2fd66 --- /dev/null +++ b/vpr/src/base/link.h @@ -0,0 +1,43 @@ +#ifndef LINK_H +#define LINK_H + +#include +#include "router.h" + + +class link +{ + private: + Router* source_router; + Router* sink_router; + + double bandwidth_usage; + + // represents the number of routed communication paths between routers that use + // this link. Congestion is proportional to this variable. + double number_of_connections; + + public: + link(Router* source_router, Router* sink_router); + ~link(); + + // getters + Router* get_source_router(void); + Router* get_sink_router(void); + double get_bandwidth_usage(void); + double get_number_of_connections(void); + + // setters + void set_bandwidth_usage(double bandwidth_usage); + void set_number_of_connections(double number_of_connections); + +}; + + + + + + + + +#endif \ No newline at end of file From d57ad16f51f937198801377590680eb9a0cbe692 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 10 Jan 2022 23:25:38 -0500 Subject: [PATCH 013/128] changed link and router objects to noc_link and noc_router. Also added the object definition for a noc_link. --- vpr/src/base/link.cpp | 3 -- vpr/src/base/noc_link.cpp | 45 +++++++++++++++++++++++++ vpr/src/base/{link.h => noc_link.h} | 22 ++++++------ vpr/src/base/noc_router.cpp | 35 +++++++++++++++++++ vpr/src/base/{router.h => noc_router.h} | 16 ++++++--- vpr/src/base/router.cpp | 35 ------------------- 6 files changed, 104 insertions(+), 52 deletions(-) delete mode 100644 vpr/src/base/link.cpp create mode 100644 vpr/src/base/noc_link.cpp rename vpr/src/base/{link.h => noc_link.h} (59%) create mode 100644 vpr/src/base/noc_router.cpp rename vpr/src/base/{router.h => noc_router.h} (51%) delete mode 100644 vpr/src/base/router.cpp diff --git a/vpr/src/base/link.cpp b/vpr/src/base/link.cpp deleted file mode 100644 index 349b7f0b546..00000000000 --- a/vpr/src/base/link.cpp +++ /dev/null @@ -1,3 +0,0 @@ -#include "link.h" - - diff --git a/vpr/src/base/noc_link.cpp b/vpr/src/base/noc_link.cpp new file mode 100644 index 00000000000..b4ce80f64bd --- /dev/null +++ b/vpr/src/base/noc_link.cpp @@ -0,0 +1,45 @@ +#include "noc_link.h" + + +// this represents a link in the NoC +NocLink::NocLink(NocRouter* source, NocRouter* sink):source_router(source), sink_router(sink) +{ + +} + +NocLink::~NocLink() +{ + +} + +// getters +NocRouter* NocLink::get_source_router(void) +{ + return source_router; +} + +NocRouter* NocLink::get_sink_router(void) +{ + return sink_router; +} + +double NocLink::get_bandwidth_usage(void) +{ + return bandwidth_usage; +} + +double NocLink::get_number_of_connections(void) +{ + return number_of_connections; +} + +//setters +void NocLink::set_bandwidth_usage(double bandwidth_usage) +{ + this->bandwidth_usage = bandwidth_usage; +} + +void NocLink::set_number_of_connections(double number_of_connections) +{ + this->number_of_connections = number_of_connections; +} \ No newline at end of file diff --git a/vpr/src/base/link.h b/vpr/src/base/noc_link.h similarity index 59% rename from vpr/src/base/link.h rename to vpr/src/base/noc_link.h index c5eb1a2fd66..85df69e86e1 100644 --- a/vpr/src/base/link.h +++ b/vpr/src/base/noc_link.h @@ -1,15 +1,17 @@ -#ifndef LINK_H -#define LINK_H +#ifndef NOC_LINK_H +#define NOC_LINK_H #include -#include "router.h" +#include "noc_router.h" -class link +class NocLink { private: - Router* source_router; - Router* sink_router; + // better to change these to ids + // instead of references + NocRouter* source_router; + NocRouter* sink_router; double bandwidth_usage; @@ -18,12 +20,12 @@ class link double number_of_connections; public: - link(Router* source_router, Router* sink_router); - ~link(); + NocLink(NocRouter* source_router, NocRouter* sink_router); + ~NocLink(); // getters - Router* get_source_router(void); - Router* get_sink_router(void); + NocRouter* get_source_router(void); + NocRouter* get_sink_router(void); double get_bandwidth_usage(void); double get_number_of_connections(void); diff --git a/vpr/src/base/noc_router.cpp b/vpr/src/base/noc_router.cpp new file mode 100644 index 00000000000..e4dd04cc12f --- /dev/null +++ b/vpr/src/base/noc_router.cpp @@ -0,0 +1,35 @@ +#include "noc_router.h" + + +NocRouter::NocRouter(int id, int grid_position_x, int grid_position_y):router_id(id), router_grid_position_x(grid_position_x), router_grid_position_y(grid_position_y) +{ +} + +// getters +int NocRouter::get_router_id(void) +{ + return router_id; +} + +int NocRouter::get_router_grid_position_x(void) +{ + return router_grid_position_x; +} + +int NocRouter::get_router_grid_position_y(void) +{ + return router_grid_position_y; +} + +std::string NocRouter::get_router_design_module_name(void) +{ + return router_design_module_name; +} + +// setters +void NocRouter::set_router_design_module_name(std::string design_module_name) +{ + router_design_module_name.assign(design_module_name); + + return; +} \ No newline at end of file diff --git a/vpr/src/base/router.h b/vpr/src/base/noc_router.h similarity index 51% rename from vpr/src/base/router.h rename to vpr/src/base/noc_router.h index fdbb3980d30..5f925bf122a 100644 --- a/vpr/src/base/router.h +++ b/vpr/src/base/noc_router.h @@ -1,20 +1,28 @@ -#ifndef ROUTER_H -#define ROUTER_H +#ifndef NOC_ROUTER_H +#define NOC_ROUTER_H #include #include -class Router { +// this represents a physical router on the chip + +class NocRouter { private: int router_id; int router_grid_position_x; int router_grid_position_y; + // atom id and clustering block id can be used to identigy which router moduleswe are using + // atom id is faster than string std::string router_design_module_name; + // traffic flow information will be providedin an input file through + // module names and how the trffic flows between them + public: - Router(int id, int grid_position_x, int grid_position_y); + NocRouter(int id, int grid_position_x, int grid_position_y); + ~NocRouter(); int get_router_id(void); int get_router_grid_position_x(void); diff --git a/vpr/src/base/router.cpp b/vpr/src/base/router.cpp deleted file mode 100644 index 3e60b062805..00000000000 --- a/vpr/src/base/router.cpp +++ /dev/null @@ -1,35 +0,0 @@ -#include "router.h" - - -Router::Router(int id, int grid_position_x, int grid_position_y):router_id(id), router_grid_position_x(grid_position_x), router_grid_position_y(grid_position_y) -{ -} - -// getters -int Router::get_router_id(void) -{ - return router_id; -} - -int Router::get_router_grid_position_x(void) -{ - return router_grid_position_x; -} - -int Router::get_router_grid_position_y(void) -{ - return router_grid_position_y; -} - -std::string Router::get_router_design_module_name(void) -{ - return router_design_module_name; -} - -// setters -void Router::set_router_design_module_name(std::string design_module_name) -{ - router_design_module_name.assign(design_module_name); - - return; -} \ No newline at end of file From 790e660d6ee9da13e07b2ba58df5be36577617ac Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Thu, 20 Jan 2022 21:35:56 -0500 Subject: [PATCH 014/128] Created a datastructure to represent the entire NoC --- vpr/src/base/noc_data_types.h | 16 +++++ vpr/src/base/noc_link.cpp | 21 +++--- vpr/src/base/noc_link.h | 22 +++--- vpr/src/base/noc_router.cpp | 20 +++--- vpr/src/base/noc_router.h | 16 +++-- vpr/src/base/noc_storage.cpp | 124 ++++++++++++++++++++++++++++++++++ vpr/src/base/noc_storage.h | 72 ++++++++++++++++++++ 7 files changed, 251 insertions(+), 40 deletions(-) create mode 100644 vpr/src/base/noc_data_types.h create mode 100644 vpr/src/base/noc_storage.cpp create mode 100644 vpr/src/base/noc_storage.h diff --git a/vpr/src/base/noc_data_types.h b/vpr/src/base/noc_data_types.h new file mode 100644 index 00000000000..0f0a9e29ba9 --- /dev/null +++ b/vpr/src/base/noc_data_types.h @@ -0,0 +1,16 @@ +#ifndef NOC_DATA_TYPES_H +#define NOC_DATA_TYPES_H + + +#include "vtr_strong_id.h" + + +// definitins data types used to index the routers and links within the noc + +struct noc_router_id_tag; +struct noc_link_id_tag; + +typedef vtr::StrongId NocRouterId; +typedef vtr::StrongId NocLinkId; + +#endif \ No newline at end of file diff --git a/vpr/src/base/noc_link.cpp b/vpr/src/base/noc_link.cpp index b4ce80f64bd..c8d09c1984f 100644 --- a/vpr/src/base/noc_link.cpp +++ b/vpr/src/base/noc_link.cpp @@ -2,9 +2,12 @@ // this represents a link in the NoC -NocLink::NocLink(NocRouter* source, NocRouter* sink):source_router(source), sink_router(sink) +NocLink::NocLink(NocRouterId source, NocRouterId sink):source_router(source), sink_router(sink) { - + // initialize variables + bandwidth_usage = 0.0; + number_of_connections = 0; + } NocLink::~NocLink() @@ -13,23 +16,19 @@ NocLink::~NocLink() } // getters -NocRouter* NocLink::get_source_router(void) -{ +NocRouterId NocLink::get_source_router(void) const{ return source_router; } -NocRouter* NocLink::get_sink_router(void) -{ +NocRouterId NocLink::get_sink_router(void) const{ return sink_router; } -double NocLink::get_bandwidth_usage(void) -{ +double NocLink::get_bandwidth_usage(void) const{ return bandwidth_usage; } -double NocLink::get_number_of_connections(void) -{ +int NocLink::get_number_of_connections(void) const{ return number_of_connections; } @@ -39,7 +38,7 @@ void NocLink::set_bandwidth_usage(double bandwidth_usage) this->bandwidth_usage = bandwidth_usage; } -void NocLink::set_number_of_connections(double number_of_connections) +void NocLink::set_number_of_connections(int number_of_connections) { this->number_of_connections = number_of_connections; } \ No newline at end of file diff --git a/vpr/src/base/noc_link.h b/vpr/src/base/noc_link.h index 85df69e86e1..7897e172cc5 100644 --- a/vpr/src/base/noc_link.h +++ b/vpr/src/base/noc_link.h @@ -3,35 +3,35 @@ #include #include "noc_router.h" +#include "noc_data_types.h" class NocLink { private: - // better to change these to ids - // instead of references - NocRouter* source_router; - NocRouter* sink_router; + // the two routers that are connected by this link + NocRouterId source_router; + NocRouterId sink_router; double bandwidth_usage; // represents the number of routed communication paths between routers that use // this link. Congestion is proportional to this variable. - double number_of_connections; + int number_of_connections; public: - NocLink(NocRouter* source_router, NocRouter* sink_router); + NocLink(NocRouterId source_router, NocRouterId sink_router); ~NocLink(); // getters - NocRouter* get_source_router(void); - NocRouter* get_sink_router(void); - double get_bandwidth_usage(void); - double get_number_of_connections(void); + NocRouterId get_source_router(void) const; + NocRouterId get_sink_router(void) const; + double get_bandwidth_usage(void) const; + int get_number_of_connections(void) const; // setters void set_bandwidth_usage(double bandwidth_usage); - void set_number_of_connections(double number_of_connections); + void set_number_of_connections(int number_of_connections); }; diff --git a/vpr/src/base/noc_router.cpp b/vpr/src/base/noc_router.cpp index e4dd04cc12f..922bc72547f 100644 --- a/vpr/src/base/noc_router.cpp +++ b/vpr/src/base/noc_router.cpp @@ -3,33 +3,31 @@ NocRouter::NocRouter(int id, int grid_position_x, int grid_position_y):router_id(id), router_grid_position_x(grid_position_x), router_grid_position_y(grid_position_y) { + // initialize variables + router_design_module_ref = ""; } // getters -int NocRouter::get_router_id(void) -{ +int NocRouter::get_router_id(void) const{ return router_id; } -int NocRouter::get_router_grid_position_x(void) -{ +int NocRouter::get_router_grid_position_x(void) const{ return router_grid_position_x; } -int NocRouter::get_router_grid_position_y(void) -{ +int NocRouter::get_router_grid_position_y(void) const{ return router_grid_position_y; } -std::string NocRouter::get_router_design_module_name(void) -{ - return router_design_module_name; +std::string NocRouter::get_router_design_module_ref(void) const{ + return router_design_module_ref; } // setters -void NocRouter::set_router_design_module_name(std::string design_module_name) +void NocRouter::set_router_design_module_ref(std::string design_module_ref) { - router_design_module_name.assign(design_module_name); + router_design_module_ref.assign(design_module_ref); return; } \ No newline at end of file diff --git a/vpr/src/base/noc_router.h b/vpr/src/base/noc_router.h index 5f925bf122a..4ae72e1ea25 100644 --- a/vpr/src/base/noc_router.h +++ b/vpr/src/base/noc_router.h @@ -9,13 +9,15 @@ class NocRouter { private: - int router_id; + // this represents the id provided by the user when describing + // the NoC in the architecture description file + int router_id; int router_grid_position_x; int router_grid_position_y; // atom id and clustering block id can be used to identigy which router moduleswe are using // atom id is faster than string - std::string router_design_module_name; + std::string router_design_module_ref; // traffic flow information will be providedin an input file through // module names and how the trffic flows between them @@ -24,14 +26,14 @@ class NocRouter { NocRouter(int id, int grid_position_x, int grid_position_y); ~NocRouter(); - int get_router_id(void); - int get_router_grid_position_x(void); - int get_router_grid_position_y(void); + int get_router_id(void) const; + int get_router_grid_position_x(void) const; + int get_router_grid_position_y(void) const; - std::string get_router_design_module_name(void); + std::string get_router_design_module_ref(void) const; // setters - void set_router_design_module_name(std::string design_module_name); + void set_router_design_module_ref(std::string design_module_ref); diff --git a/vpr/src/base/noc_storage.cpp b/vpr/src/base/noc_storage.cpp new file mode 100644 index 00000000000..78d5719b4f6 --- /dev/null +++ b/vpr/src/base/noc_storage.cpp @@ -0,0 +1,124 @@ +#include "noc_storage.h" + +// clear all the graph data structures +NocStorage::NocStorage() { + + clear_noc(); +} + +// destructor +NocStorage::~NocStorage(){ +} + +// getters for the NoC + +// get the outgoing links for a router in the NoC +const std::vector& NocStorage::get_noc_router_connections(NocRouterId id) const{ + + return router_link_list[id]; +} + +int NocStorage::get_noc_router_grid_position_x(NocRouterId id) const{ + + return router_storage[id].get_router_grid_position_x(); +} + +int NocStorage::get_noc_router_grid_position_y(NocRouterId id) const{ + + return router_storage[id].get_router_grid_position_y(); +} + +int NocStorage::get_noc_router_id(NocRouterId id) const{ + + return router_storage[id].get_router_id(); +} + +std::string NocStorage::get_noc_router_design_module_ref(NocRouterId id) const{ + + return router_storage[id].get_router_design_module_ref(); +} + +NocRouterId NocStorage::get_noc_link_source_router(NocLinkId id) const{ + + return link_storage[id].get_source_router(); +} + +NocRouterId NocStorage::get_noc_link_sink_router(NocLinkId id) const{ + + return link_storage[id].get_sink_router(); +} + +double NocStorage::get_noc_link_bandwidth_usage(NocLinkId id) const{ + + return link_storage[id].get_bandwidth_usage(); +} + +int NocStorage::get_noc_link_number_of_connections(NocLinkId id) const{ + + return link_storage[id].get_number_of_connections(); +} + +void NocStorage::add_router(int id, int grid_position_x, int grid_posistion_y){ + + VTR_ASSERT(!built_noc); + router_storage.emplace_back(id, grid_position_x, grid_posistion_y); + + return; +} + +void NocStorage::add_link(NocRouterId source, NocRouterId sink){ + + VTR_ASSERT(!built_noc); + link_storage.emplace_back(source, sink); + + return; +} + +void NocStorage::add_noc_router_link(NocRouterId router_id, NocLinkId link_id){ + + VTR_ASSERT(!built_noc); + router_link_list[router_id].push_back(link_id); + + return; +} + +void NocStorage::set_noc_router_design_module_ref(NocRouterId id, std::string design_module_ref){ + + router_storage[id].set_router_design_module_ref(design_module_ref); + + return; +} + +void NocStorage::set_noc_link_bandwidth_usage(NocLinkId id, double bandwidth_usage){ + + link_storage[id].set_bandwidth_usage(bandwidth_usage); + + return; +} + +void NocStorage::set_noc_link_number_of_connections(NocLinkId id, int number_of_connections){ + + link_storage[id].set_number_of_connections(number_of_connections); + + return; +} + +void NocStorage::finished_building_noc(void){ + + VTR_ASSERT(!built_noc); + built_noc = true; + + return; +} + +void NocStorage::clear_noc(void){ + + router_storage.clear(); + link_storage.clear(); + router_link_list.clear(); + + built_noc = false; + + return; +} + diff --git a/vpr/src/base/noc_storage.h b/vpr/src/base/noc_storage.h new file mode 100644 index 00000000000..efe5c90891f --- /dev/null +++ b/vpr/src/base/noc_storage.h @@ -0,0 +1,72 @@ +#ifndef NOC_STORAGE_H +#define NOC_STORAGE_H + + +#include +#include +#include +#include "noc_data_types.h" +#include "vtr_vector.h" +#include "noc_router.h" +#include "noc_link.h" +#include "vtr_assert.h" + +class NocStorage +{ + private: + + // list of routers in the noc + vtr::vector router_storage; + + // list of outgoing links for each router + vtr::vector> router_link_list; + + // list of links in the noc + vtr::vector link_storage; + + // flags to keep track of the status + bool built_noc; + public: + + // default contructor (cleare all the elements in the vectors) + NocStorage(); + // default destructor (dont have to do anything here) + ~NocStorage(); + + // getters for the NoC + const std::vector& get_noc_router_connections(NocRouterId id) const; + + // getters for routers + int get_noc_router_grid_position_x(NocRouterId id) const; + int get_noc_router_grid_position_y(NocRouterId id) const; + int get_noc_router_id(NocRouterId id) const; + std::string get_noc_router_design_module_ref(NocRouterId id) const; + + + // getters for links + NocRouterId get_noc_link_source_router(NocLinkId id)const; + NocRouterId get_noc_link_sink_router(NocLinkId id) const; + double get_noc_link_bandwidth_usage(NocLinkId id) const; + int get_noc_link_number_of_connections(NocLinkId id) const; + + // setters for the NoC + void add_router(int id, int grid_position_x, int grid_position_y); + void add_link(NocRouterId source, NocRouterId sink); + void add_noc_router_link(NocRouterId router_id, NocLinkId link_id); + + // setters for the noc router + void set_noc_router_design_module_ref(NocRouterId id, std::string design_module_ref); + + // setters for the noc link + void set_noc_link_bandwidth_usage(NocLinkId id, double bandwidth_usage); + void set_noc_link_number_of_connections(NocLinkId id, int number_of_connections); + + // general utiliy functions + void finished_building_noc(); + void clear_noc(); + +}; + + + +#endif \ No newline at end of file From 1401585fc3b8b73692447ab7d380369e5a0cf4fb Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 21 Jan 2022 01:07:57 -0500 Subject: [PATCH 015/128] added functionality to the NoC datastructure to map the user provided router ids to the id system used for routers in the NoC --- vpr/src/base/noc_storage.cpp | 22 ++++++++++++++++++++++ vpr/src/base/noc_storage.h | 11 +++++++++++ 2 files changed, 33 insertions(+) diff --git a/vpr/src/base/noc_storage.cpp b/vpr/src/base/noc_storage.cpp index 78d5719b4f6..f8848383810 100644 --- a/vpr/src/base/noc_storage.cpp +++ b/vpr/src/base/noc_storage.cpp @@ -16,6 +16,7 @@ NocStorage::~NocStorage(){ const std::vector& NocStorage::get_noc_router_connections(NocRouterId id) const{ return router_link_list[id]; + } int NocStorage::get_noc_router_grid_position_x(NocRouterId id) const{ @@ -61,8 +62,16 @@ int NocStorage::get_noc_link_number_of_connections(NocLinkId id) const{ void NocStorage::add_router(int id, int grid_position_x, int grid_posistion_y){ VTR_ASSERT(!built_noc); + router_storage.emplace_back(id, grid_position_x, grid_posistion_y); + // get the corresponding NocRouterId for the newly added router and + // add it to the conversion table. + // We build the conversion table here as it gurantees only unique routers + // in the NoC are added. + NocRouterId converted_id((int)(router_storage.size() - 1)); + router_id_conversion_table.emplace(id, converted_id); + return; } @@ -122,3 +131,16 @@ void NocStorage::clear_noc(void){ return; } +NocRouterId NocStorage::convert_router_id(int id) const{ + + std::unordered_map::const_iterator result = router_id_conversion_table.find(id); + + if (result == router_id_conversion_table.end()) + { + VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Cannot convert router with id:%d. The router was not found within the NoC.", id); + } + + return result->second; + +} + diff --git a/vpr/src/base/noc_storage.h b/vpr/src/base/noc_storage.h index efe5c90891f..2d641d07e5f 100644 --- a/vpr/src/base/noc_storage.h +++ b/vpr/src/base/noc_storage.h @@ -5,11 +5,14 @@ #include #include #include +#include #include "noc_data_types.h" #include "vtr_vector.h" #include "noc_router.h" #include "noc_link.h" #include "vtr_assert.h" +#include "vpr_error.h" + class NocStorage { @@ -24,6 +27,13 @@ class NocStorage // list of links in the noc vtr::vector link_storage; + // The user provides an id for routers when describing the noc in the architecture file. + // This id system will be different than than the NocRouterIds assigned to each router + // when creating the NoC datastructre. + // A conversion table is created below that maps the user provided router ids to the corresponding + // NocRouterId. + std::unordered_map router_id_conversion_table; + // flags to keep track of the status bool built_noc; public: @@ -64,6 +74,7 @@ class NocStorage // general utiliy functions void finished_building_noc(); void clear_noc(); + NocRouterId convert_router_id(int id) const; }; From e3a04002041b6f64cb85ab0616f4ab12cabf5abe Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 21 Jan 2022 01:19:11 -0500 Subject: [PATCH 016/128] added messages to assertions --- vpr/src/base/noc_storage.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vpr/src/base/noc_storage.cpp b/vpr/src/base/noc_storage.cpp index f8848383810..84b3971c9e1 100644 --- a/vpr/src/base/noc_storage.cpp +++ b/vpr/src/base/noc_storage.cpp @@ -61,7 +61,7 @@ int NocStorage::get_noc_link_number_of_connections(NocLinkId id) const{ void NocStorage::add_router(int id, int grid_position_x, int grid_posistion_y){ - VTR_ASSERT(!built_noc); + VTR_ASSERT_MSG(!built_noc, "NoC already built, cannot modify further."); router_storage.emplace_back(id, grid_position_x, grid_posistion_y); @@ -77,7 +77,7 @@ void NocStorage::add_router(int id, int grid_position_x, int grid_posistion_y){ void NocStorage::add_link(NocRouterId source, NocRouterId sink){ - VTR_ASSERT(!built_noc); + VTR_ASSERT_MSG(!built_noc, "NoC already built, cannot modify further."); link_storage.emplace_back(source, sink); return; @@ -85,7 +85,7 @@ void NocStorage::add_link(NocRouterId source, NocRouterId sink){ void NocStorage::add_noc_router_link(NocRouterId router_id, NocLinkId link_id){ - VTR_ASSERT(!built_noc); + VTR_ASSERT_MSG(!built_noc, "NoC already built, cannot modify further."); router_link_list[router_id].push_back(link_id); return; @@ -114,7 +114,7 @@ void NocStorage::set_noc_link_number_of_connections(NocLinkId id, int number_of_ void NocStorage::finished_building_noc(void){ - VTR_ASSERT(!built_noc); + VTR_ASSERT_MSG(!built_noc, "NoC already built, cannot modify further."); built_noc = true; return; From dfa7742fd14158c89ee06df35333db7a82c605ce Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 21 Jan 2022 01:20:15 -0500 Subject: [PATCH 017/128] ensured that the the NoC datastructure cannot be copied --- vpr/src/base/noc_storage.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/vpr/src/base/noc_storage.h b/vpr/src/base/noc_storage.h index 2d641d07e5f..fdda3f1e893 100644 --- a/vpr/src/base/noc_storage.h +++ b/vpr/src/base/noc_storage.h @@ -36,6 +36,10 @@ class NocStorage // flags to keep track of the status bool built_noc; + + // preventy "pass by value" of this object + NocStorage(const NocStorage&) = delete; + void operator=(const NocStorage&) = delete; public: // default contructor (cleare all the elements in the vectors) From dd51424f16b0a098ccfbc4bbbf656b180a59724d Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 31 Jan 2022 14:42:22 -0500 Subject: [PATCH 018/128] Added a check box in the graphics to control the display of the NoC --- vpr/src/base/noc_storage.h | 2 +- vpr/src/draw/buttons.cpp | 19 +++++++++++++++++++ vpr/src/draw/buttons.h | 1 + vpr/src/draw/draw.cpp | 2 ++ 4 files changed, 23 insertions(+), 1 deletion(-) diff --git a/vpr/src/base/noc_storage.h b/vpr/src/base/noc_storage.h index fdda3f1e893..be77eaece16 100644 --- a/vpr/src/base/noc_storage.h +++ b/vpr/src/base/noc_storage.h @@ -37,7 +37,7 @@ class NocStorage // flags to keep track of the status bool built_noc; - // preventy "pass by value" of this object + // prevent "copying" of this object NocStorage(const NocStorage&) = delete; void operator=(const NocStorage&) = delete; public: diff --git a/vpr/src/draw/buttons.cpp b/vpr/src/draw/buttons.cpp index 9773463b420..ea3488e039b 100644 --- a/vpr/src/draw/buttons.cpp +++ b/vpr/src/draw/buttons.cpp @@ -244,6 +244,25 @@ void button_for_toggle_crit_path() { toggle_crit_path_widget); } +void button_for_displaying_noc() { + GObject* main_window = application.get_object(application.get_main_window_id().c_str()); + GObject* main_window_grid = application.get_object("InnerGrid"); + + GtkWidget* display_noc_widget = gtk_check_button_new_with_label("Display NoC"); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(display_noc_widget), false); + gtk_widget_set_name(display_noc_widget, "display_noc"); + + //attach to the grid + gtk_grid_attach((GtkGrid*)main_window_grid, display_noc_widget, label_left_start_col, button_row++, box_width, box_height); + + // show the newy added check box + gtk_widget_show_all((GtkWidget*)main_window); + + // future signal connection + +} + + void button_for_toggle_rr() { GObject* main_window = application.get_object(application.get_main_window_id().c_str()); GObject* main_window_grid = application.get_object("InnerGrid"); diff --git a/vpr/src/draw/buttons.h b/vpr/src/draw/buttons.h index 0b43f2b911d..5b60d606043 100644 --- a/vpr/src/draw/buttons.h +++ b/vpr/src/draw/buttons.h @@ -16,6 +16,7 @@ void button_for_toggle_placement_macros(); void button_for_toggle_crit_path(); void button_for_net_max_fanout(); void button_for_net_alpha(); +void button_for_displaying_noc(); void button_for_toggle_rr(); void button_for_toggle_congestion(); diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 1890e46fecd..34900a8af1f 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -367,6 +367,7 @@ static void initial_setup_NO_PICTURE_to_PLACEMENT(ezgl::application* app, button_for_toggle_blk_internal(); button_for_toggle_block_pin_util(); button_for_toggle_placement_macros(); + button_for_displaying_noc(); } /* function below intializes the interface window with a set of buttons and links @@ -455,6 +456,7 @@ static void initial_setup_NO_PICTURE_to_ROUTING(ezgl::application* app, button_for_toggle_routing_bounding_box(); button_for_toggle_routing_util(); button_for_toggle_router_expansion_costs(); + button_for_displaying_noc(); } /* function below intializes the interface window with a set of buttons and links From 887af9905a5d55a790cc7ce5a299e389b60742d4 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 2 Feb 2022 01:00:56 -0500 Subject: [PATCH 019/128] verified that connections in the NoC were not included more than once in the arch description file --- libs/libarchfpga/src/read_xml_arch_file.cpp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index 4e28c266d98..b110e786b3d 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -4936,6 +4936,13 @@ static bool parse_noc_router_connection_list(std::vector& connection_list, break; } + // check the case where a duplicate connection was provided + if (std::find(connection_list.begin(), connection_list.end(), converted_connection) != connection_list.end()) + { + archfpga_throw("",-1, + "The router with id:'%d' was included multiple times in the connection list for another router.", converted_connection); + } + // if we are here then a legal router id was supplied, so store it connection_list.push_back(converted_connection); From 0577a29083f6ded72eb7b711b927242f5995dae3 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 2 Feb 2022 01:02:12 -0500 Subject: [PATCH 020/128] added support to fully build the NoC model from the arch file description --- vpr/src/base/noc_link.cpp | 8 +- vpr/src/base/noc_link.h | 4 +- vpr/src/base/noc_router.cpp | 5 + vpr/src/base/noc_storage.cpp | 13 ++- vpr/src/base/noc_storage.h | 4 +- vpr/src/base/setup_noc.cpp | 184 +++++++++++++++++++++++++++++++++-- vpr/src/base/setup_noc.h | 11 ++- vpr/src/base/vpr_context.h | 27 +++++ 8 files changed, 231 insertions(+), 25 deletions(-) diff --git a/vpr/src/base/noc_link.cpp b/vpr/src/base/noc_link.cpp index c8d09c1984f..24475e5fcee 100644 --- a/vpr/src/base/noc_link.cpp +++ b/vpr/src/base/noc_link.cpp @@ -33,12 +33,12 @@ int NocLink::get_number_of_connections(void) const{ } //setters -void NocLink::set_bandwidth_usage(double bandwidth_usage) +void NocLink::set_bandwidth_usage(double new_bandwidth_usage) { - this->bandwidth_usage = bandwidth_usage; + bandwidth_usage = new_bandwidth_usage; } -void NocLink::set_number_of_connections(int number_of_connections) +void NocLink::set_number_of_connections(int new_number_of_connections) { - this->number_of_connections = number_of_connections; + number_of_connections = new_number_of_connections; } \ No newline at end of file diff --git a/vpr/src/base/noc_link.h b/vpr/src/base/noc_link.h index 7897e172cc5..76f54fe7aa0 100644 --- a/vpr/src/base/noc_link.h +++ b/vpr/src/base/noc_link.h @@ -30,8 +30,8 @@ class NocLink int get_number_of_connections(void) const; // setters - void set_bandwidth_usage(double bandwidth_usage); - void set_number_of_connections(int number_of_connections); + void set_bandwidth_usage(double new_bandwidth_usage); + void set_number_of_connections(int new_number_of_connections); }; diff --git a/vpr/src/base/noc_router.cpp b/vpr/src/base/noc_router.cpp index 922bc72547f..2a0e2d38a61 100644 --- a/vpr/src/base/noc_router.cpp +++ b/vpr/src/base/noc_router.cpp @@ -7,6 +7,11 @@ NocRouter::NocRouter(int id, int grid_position_x, int grid_position_y):router_id router_design_module_ref = ""; } +// defualt destructor +NocRouter::~NocRouter(){ + +} + // getters int NocRouter::get_router_id(void) const{ return router_id; diff --git a/vpr/src/base/noc_storage.cpp b/vpr/src/base/noc_storage.cpp index 84b3971c9e1..bc74a9e1f34 100644 --- a/vpr/src/base/noc_storage.cpp +++ b/vpr/src/base/noc_storage.cpp @@ -59,7 +59,7 @@ int NocStorage::get_noc_link_number_of_connections(NocLinkId id) const{ return link_storage[id].get_number_of_connections(); } -void NocStorage::add_router(int id, int grid_position_x, int grid_posistion_y){ +bool NocStorage::add_router(int id, int grid_position_x, int grid_posistion_y){ VTR_ASSERT_MSG(!built_noc, "NoC already built, cannot modify further."); @@ -70,17 +70,20 @@ void NocStorage::add_router(int id, int grid_position_x, int grid_posistion_y){ // We build the conversion table here as it gurantees only unique routers // in the NoC are added. NocRouterId converted_id((int)(router_storage.size() - 1)); - router_id_conversion_table.emplace(id, converted_id); + std::pair::iterator, bool> result= router_id_conversion_table.emplace(id, converted_id); - return; + return result.second; } -void NocStorage::add_link(NocRouterId source, NocRouterId sink){ +NocLinkId NocStorage::add_link(NocRouterId source, NocRouterId sink){ VTR_ASSERT_MSG(!built_noc, "NoC already built, cannot modify further."); link_storage.emplace_back(source, sink); - return; + // the newly added link was added to the back of the list, so we can get the id as the last element in the list + NocLinkId added_link_id((int)link_storage.size() - 1); + + return added_link_id; } void NocStorage::add_noc_router_link(NocRouterId router_id, NocLinkId link_id){ diff --git a/vpr/src/base/noc_storage.h b/vpr/src/base/noc_storage.h index be77eaece16..65fcdac2fca 100644 --- a/vpr/src/base/noc_storage.h +++ b/vpr/src/base/noc_storage.h @@ -64,8 +64,8 @@ class NocStorage int get_noc_link_number_of_connections(NocLinkId id) const; // setters for the NoC - void add_router(int id, int grid_position_x, int grid_position_y); - void add_link(NocRouterId source, NocRouterId sink); + bool add_router(int id, int grid_position_x, int grid_position_y); + NocLinkId add_link(NocRouterId source, NocRouterId sink); void add_noc_router_link(NocRouterId router_id, NocLinkId link_id); // setters for the noc router diff --git a/vpr/src/base/setup_noc.cpp b/vpr/src/base/setup_noc.cpp index 8d9f95a7b43..eaaf4bb6894 100644 --- a/vpr/src/base/setup_noc.cpp +++ b/vpr/src/base/setup_noc.cpp @@ -1,4 +1,7 @@ +#include +#include + #include "setup_noc.h" #include "vtr_assert.h" @@ -28,16 +31,16 @@ void setup_noc(const t_arch& arch, std::string noc_router_tile_name) // check whether the noc topology information provided is using all the routers in the FPGA if (list_of_noc_router_tiles.size() < arch.noc->router_list.size()) { - VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Provided NoC topology information in the architecture file has more routers that what is available in the FPGA."); + VTR_LOG_WARN("Provided NoC topology information in the architecture file has more routers that what is available in the FPGA."); } // generate noc model - generate_noc(arch, noc_ctx); - - - - + generate_noc(arch, noc_ctx, list_of_noc_router_tiles); + // store the general noc properties + noc_ctx.noc_link_bandwidth = arch.noc->link_bandwidth; + noc_ctx.noc_link_latency = arch.noc->link_latency; + noc_ctx.noc_router_latency = arch.noc->router_latency; return; @@ -48,10 +51,15 @@ void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, int grid_width = device_grid.width(); int grid_height = device_grid.height(); + int curr_tile_width; + int curr_tile_height; int curr_tile_width_offset; int curr_tile_height_offset; std::string curr_tile_name; + double curr_tile_centroid_x; + double curr_tile_centroid_y; + // go through the device for(int i = 0; i < grid_width; i++) { @@ -63,13 +71,20 @@ void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, curr_tile_width_offset = device_grid[i][j].width_offset; curr_tile_height_offset = device_grid[i][j].height_offset; + curr_tile_height = device_grid[i][j].type->height; + curr_tile_width = device_grid[i][j].type->width; + /* Only store the tile position if it is a noc router. Additionally, since a router tile can span multiple grid locations, we only add the tile if the height and width offset are zero (this prevents the router from being added multiple times for each grid location it spans). */ - if (!((noc_router_tile_name.compare(curr_tile_name)) && curr_tile_width_offset && curr_tile_width_offset)) + if (!((noc_router_tile_name.compare(curr_tile_name)) && curr_tile_width_offset && curr_tile_height_offset)) { - list_of_noc_router_tiles.push_back({i,j}); + // calculating the centroid position of the current tile + curr_tile_centroid_x = curr_tile_width/(double)2 + i; + curr_tile_centroid_y = curr_tile_height/(double)2 + j; + + list_of_noc_router_tiles.push_back({i,j,curr_tile_centroid_x, curr_tile_centroid_y}); } } @@ -79,8 +94,159 @@ void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, } -void generate_noc(const t_arch& arch, NocContext& noc_ctx) +/* the purpose of this function is to "assign" the logical routers defined in the architecture file to + their corresponding physical routers (represented as router nodes) in the FPGA chip. The router assignments + are done by determining the logical router who's position is the shortest distance to each physical router. + + Once the physical routers are assigned, "links" are created to connect the routers, this + is done based on the connections defines in the architecture file. + + This completes the NoC creation. +*/ +void generate_noc(const t_arch& arch, NocContext& noc_ctx, std::vector& list_of_noc_router_tiles) +{ + // refrernces to the noc + NocStorage* noc_model = &noc_ctx.noc_model; + // reference to the noc description + const t_noc_inf* noc_info = arch.noc; + + // initialize the noc + noc_model->clear_noc(); + + // create all the routers in the NoC + create_noc_routers(*arch.noc, noc_model, list_of_noc_router_tiles); + + // create all the links in the NoC + create_noc_links(noc_info, noc_model); + + // indicate that the NoC has been built + noc_model->finished_building_noc(); + + return; + +} + +void create_noc_routers(t_noc_inf noc_info, NocStorage* noc_model , std::vector& list_of_noc_router_tiles) { + // keep track of the shortest distance between a logical router and the curren physical router tile + // also keep track of the corresponding logical router + double shortest_distance; + double curr_calculated_distance; + t_router* closest_router; + + // information regarding physical router position + double curr_physical_router_pos_x; + double curr_physical_router_pos_y; + + // information regarding logical router position + double curr_logical_router_position_x; + double curr_logical_router_position_y; + + // result of adding a router to the NoC + bool router_creation; + + // keep track of the ids of the routers that ceate the case where multiple routers + // have the same distance to a physical router tile + int error_case_router_id_1; + int error_case_router_id_2; + + // Below we create all the routers within the NoC // + + // go through each physical router tile and assign it to a logical router specified by the user + // in the architecture escription + for (auto physical_router = list_of_noc_router_tiles.begin(); physical_router != list_of_noc_router_tiles.end(); physical_router++) + { + // assign the shortest distance to a large value (this is done so that the first distance calculated can replace this) + shortest_distance = LLONG_MAX; + + curr_physical_router_pos_x = physical_router->tile_centroid_x; + curr_physical_router_pos_y = physical_router->tile_centroid_y; + + closest_router = NULL; + + // initialze the router ids that track the error case where two routers have the same distance to a physical router + // we initialize it to a in-valid router id, so that it reflects the situation where we never hit this case + error_case_router_id_1 = -1; + error_case_router_id_2 = -1; + + // determine the logical router that is closest to the current physocal router tile + for (auto logical_router = noc_info.router_list.begin(); logical_router != noc_info.router_list.end(); logical_router++) + { + curr_logical_router_position_x = logical_router->device_x_position; + curr_logical_router_position_y = logical_router->device_y_position; + + // use euclidean distance to calculate the length between the current logical and physical routers + curr_calculated_distance = sqrt(pow(abs(curr_physical_router_pos_x - curr_logical_router_position_x),2.0) + + pow(abs(curr_physical_router_pos_y - curr_logical_router_position_y),2.0)); + + // if the current distance is the same as the previous shortest distance + if (curr_calculated_distance == shortest_distance) + { + // store the ids of the two routers + error_case_router_id_1 = closest_router->id; + error_case_router_id_2 = logical_router->id; + + } + else if (curr_calculated_distance < shortest_distance) // case where the current logical router is closest to the physical router tile + { + // update the shortest distance and then the closest router + shortest_distance = curr_calculated_distance; + closest_router = &*logical_router; + + } + + } + + // check the case where two routers have the same distance to the given physical router tile + if (error_case_router_id_1 == closest_router->id) + { + VPR_FATAL_ERROR(VPR_ERROR_OTHER, + "Routers with IDs: '%d' and '%d' have the same distance to a physical router tile located at position (%d,%d). Therefore, no routers could be assigned to the physical router tile.", + error_case_router_id_1, error_case_router_id_2, physical_router->grid_width_position, physical_router->grid_height_position); + } + + // at this point, the closest logical router to the current physical router was found + // so add the router to the NoC + router_creation = noc_model->add_router(closest_router->id, physical_router->grid_width_position, physical_router->grid_height_position); + + // if we failed to add a router then that means a logical router was the closest to multiple routers + if (!router_creation) + { + VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Router with ID:'%d' was the closest to multiple physical router tiles and therefore could not be assigned multiple times.", closest_router->id); + } + + } + + return; +} + +void create_noc_links(const t_noc_inf* noc_info, NocStorage* noc_model){ + // the ids used to represent the routers in the NoC are not the same as the ones provided by the user in the arch desc file. + // while going through the router connections, the user provided router ids are converted and then stored below before being used + // in the links. + NocRouterId source_router; + NocRouterId sink_router; + + // store the id of each new link we create + NocLinkId created_link_id; + + // go through each router and add its outgoing links to the NoC + for (auto router = noc_info->router_list.begin(); router != noc_info->router_list.end(); router++) + { + // get the converted id of the current source router + source_router = noc_model->convert_router_id(router->id); + + // go through all the routers connected to the current one and add links to the noc + for (auto conn_router_id = router->connection_list.begin(); conn_router_id != router->connection_list.end(); conn_router_id++) + { + // get the converted id of the currently connected sink router + sink_router = noc_model->convert_router_id(*conn_router_id); + + // add the link to the Noc + created_link_id = noc_model->add_link(source_router, sink_router); + noc_model->add_noc_router_link(source_router, created_link_id); + } + } return; diff --git a/vpr/src/base/setup_noc.h b/vpr/src/base/setup_noc.h index af25ee1e65e..73fd86535b8 100644 --- a/vpr/src/base/setup_noc.h +++ b/vpr/src/base/setup_noc.h @@ -9,6 +9,8 @@ #include "physical_types.h" #include "device_grid.h" #include "globals.h" +#include "noc_storage.h" +#include "vpr_error.h" @@ -17,6 +19,9 @@ struct t_noc_router_tile_position { int grid_width_position; int grid_height_position; + + double tile_centroid_x; + double tile_centroid_y; }; @@ -25,11 +30,11 @@ void setup_noc(const t_arch& arch, std::string noc_router_tile_name); void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, std::vector& list_of_noc_router_tiles, std::string noc_router_tile_name); -void generate_noc(const t_arch& arch, NocContext& noc_ctx); - - +void generate_noc(const t_arch& arch, NocContext& noc_ctx, std::vector& list_of_noc_router_tiles); +void create_noc_routers(t_noc_inf noc_info, NocStorage* noc_model, std::vector& list_of_noc_router_tiles); +void create_noc_links(const t_noc_inf* noc_info, NocStorage* noc_model); diff --git a/vpr/src/base/vpr_context.h b/vpr/src/base/vpr_context.h index c49da23b7ac..d8f1247a00c 100644 --- a/vpr/src/base/vpr_context.h +++ b/vpr/src/base/vpr_context.h @@ -27,6 +27,7 @@ #include "compressed_grid.h" #include "metadata_storage.h" #include "vpr_constraints.h" +#include "noc_storage.h" /** * @brief A Context is collection of state relating to a particular part of VPR @@ -388,7 +389,33 @@ struct FloorplanningContext : public Context { * NoC within the device. */ struct NocContext : public Context { + /** + * @brief A model of the NoC + * + * Contains all the routers and links that make up the NoC. The routers contain + * information regarding the physical tile positions they represent. The links + * define the connections between every router (ropology) and also metrics that describe its + * "usage". + * + * + * The NoC model is created once from the architecture file description. + */ + NocStorage noc_model; + + /** + * @brief Represents the maximum allowed bandwidth for the links in the NoC (in Gbps) + */ + int noc_link_bandwidth; + + /** + * @brief Represents the delay expected when going through a link + */ + int noc_link_latency; + /** + * @brief Represents the expected delay when going through a router + */ + int noc_router_latency; }; /** From 076b0912e11a364c730d367589a2c54709c45874 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 2 Feb 2022 01:51:00 -0500 Subject: [PATCH 021/128] removed unnecessary destructors and added a function to the NocStorage class that pre-allocates space for datastructures --- vpr/src/base/noc_link.cpp | 5 ----- vpr/src/base/noc_link.h | 1 - vpr/src/base/noc_router.cpp | 5 ----- vpr/src/base/noc_router.h | 1 - vpr/src/base/noc_storage.cpp | 21 ++++++++------------- vpr/src/base/noc_storage.h | 6 ++---- vpr/src/base/setup_noc.cpp | 6 ++++-- 7 files changed, 14 insertions(+), 31 deletions(-) diff --git a/vpr/src/base/noc_link.cpp b/vpr/src/base/noc_link.cpp index 24475e5fcee..e11f707e4f0 100644 --- a/vpr/src/base/noc_link.cpp +++ b/vpr/src/base/noc_link.cpp @@ -10,11 +10,6 @@ NocLink::NocLink(NocRouterId source, NocRouterId sink):source_router(source), si } -NocLink::~NocLink() -{ - -} - // getters NocRouterId NocLink::get_source_router(void) const{ return source_router; diff --git a/vpr/src/base/noc_link.h b/vpr/src/base/noc_link.h index 76f54fe7aa0..4467452b255 100644 --- a/vpr/src/base/noc_link.h +++ b/vpr/src/base/noc_link.h @@ -21,7 +21,6 @@ class NocLink public: NocLink(NocRouterId source_router, NocRouterId sink_router); - ~NocLink(); // getters NocRouterId get_source_router(void) const; diff --git a/vpr/src/base/noc_router.cpp b/vpr/src/base/noc_router.cpp index 2a0e2d38a61..922bc72547f 100644 --- a/vpr/src/base/noc_router.cpp +++ b/vpr/src/base/noc_router.cpp @@ -7,11 +7,6 @@ NocRouter::NocRouter(int id, int grid_position_x, int grid_position_y):router_id router_design_module_ref = ""; } -// defualt destructor -NocRouter::~NocRouter(){ - -} - // getters int NocRouter::get_router_id(void) const{ return router_id; diff --git a/vpr/src/base/noc_router.h b/vpr/src/base/noc_router.h index 4ae72e1ea25..b0761c5e5c9 100644 --- a/vpr/src/base/noc_router.h +++ b/vpr/src/base/noc_router.h @@ -24,7 +24,6 @@ class NocRouter { public: NocRouter(int id, int grid_position_x, int grid_position_y); - ~NocRouter(); int get_router_id(void) const; int get_router_grid_position_x(void) const; diff --git a/vpr/src/base/noc_storage.cpp b/vpr/src/base/noc_storage.cpp index bc74a9e1f34..8d846c0c736 100644 --- a/vpr/src/base/noc_storage.cpp +++ b/vpr/src/base/noc_storage.cpp @@ -6,10 +6,6 @@ NocStorage::NocStorage() { clear_noc(); } -// destructor -NocStorage::~NocStorage(){ -} - // getters for the NoC // get the outgoing links for a router in the NoC @@ -75,21 +71,14 @@ bool NocStorage::add_router(int id, int grid_position_x, int grid_posistion_y){ return result.second; } -NocLinkId NocStorage::add_link(NocRouterId source, NocRouterId sink){ +void NocStorage::add_link(NocRouterId source, NocRouterId sink){ VTR_ASSERT_MSG(!built_noc, "NoC already built, cannot modify further."); link_storage.emplace_back(source, sink); // the newly added link was added to the back of the list, so we can get the id as the last element in the list NocLinkId added_link_id((int)link_storage.size() - 1); - - return added_link_id; -} - -void NocStorage::add_noc_router_link(NocRouterId router_id, NocLinkId link_id){ - - VTR_ASSERT_MSG(!built_noc, "NoC already built, cannot modify further."); - router_link_list[router_id].push_back(link_id); + router_link_list[source].push_back(added_link_id); return; } @@ -147,3 +136,9 @@ NocRouterId NocStorage::convert_router_id(int id) const{ } +void NocStorage::make_room_for_noc_router_link_list(){ + + VTR_ASSERT_MSG(!built_noc, "NoC already built, cannot modify further."); + router_link_list.resize(router_storage.size()); +} + diff --git a/vpr/src/base/noc_storage.h b/vpr/src/base/noc_storage.h index 65fcdac2fca..71af56804ec 100644 --- a/vpr/src/base/noc_storage.h +++ b/vpr/src/base/noc_storage.h @@ -44,8 +44,6 @@ class NocStorage // default contructor (cleare all the elements in the vectors) NocStorage(); - // default destructor (dont have to do anything here) - ~NocStorage(); // getters for the NoC const std::vector& get_noc_router_connections(NocRouterId id) const; @@ -65,8 +63,7 @@ class NocStorage // setters for the NoC bool add_router(int id, int grid_position_x, int grid_position_y); - NocLinkId add_link(NocRouterId source, NocRouterId sink); - void add_noc_router_link(NocRouterId router_id, NocLinkId link_id); + void add_link(NocRouterId source, NocRouterId sink); // setters for the noc router void set_noc_router_design_module_ref(NocRouterId id, std::string design_module_ref); @@ -79,6 +76,7 @@ class NocStorage void finished_building_noc(); void clear_noc(); NocRouterId convert_router_id(int id) const; + void make_room_for_noc_router_link_list(); }; diff --git a/vpr/src/base/setup_noc.cpp b/vpr/src/base/setup_noc.cpp index eaaf4bb6894..3a579d45d5f 100644 --- a/vpr/src/base/setup_noc.cpp +++ b/vpr/src/base/setup_noc.cpp @@ -230,6 +230,9 @@ void create_noc_links(const t_noc_inf* noc_info, NocStorage* noc_model){ // store the id of each new link we create NocLinkId created_link_id; + // start of by creating enough space for the list of outgoing links for each router in the NoC + noc_model->make_room_for_noc_router_link_list(); + // go through each router and add its outgoing links to the NoC for (auto router = noc_info->router_list.begin(); router != noc_info->router_list.end(); router++) { @@ -243,8 +246,7 @@ void create_noc_links(const t_noc_inf* noc_info, NocStorage* noc_model){ sink_router = noc_model->convert_router_id(*conn_router_id); // add the link to the Noc - created_link_id = noc_model->add_link(source_router, sink_router); - noc_model->add_noc_router_link(source_router, created_link_id); + noc_model->add_link(source_router, sink_router);; } } From 37e11effd407dd593377f41986918d16be7a56c2 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 2 Feb 2022 01:55:45 -0500 Subject: [PATCH 022/128] added a check to catch the case where no physical router tiles exist on the FPGA device --- vpr/src/base/setup_noc.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/vpr/src/base/setup_noc.cpp b/vpr/src/base/setup_noc.cpp index 3a579d45d5f..2d5d315ff75 100644 --- a/vpr/src/base/setup_noc.cpp +++ b/vpr/src/base/setup_noc.cpp @@ -27,12 +27,14 @@ void setup_noc(const t_arch& arch, std::string noc_router_tile_name) { VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Provided NoC topology information in the architecture file has more routers that what is available in the FPGA."); } - - // check whether the noc topology information provided is using all the routers in the FPGA - if (list_of_noc_router_tiles.size() < arch.noc->router_list.size()) + else if (list_of_noc_router_tiles.size() < arch.noc->router_list.size()) // check whether the noc topology information provided is using all the routers in the FPGA { VTR_LOG_WARN("Provided NoC topology information in the architecture file has more routers that what is available in the FPGA."); } + else if (list_of_noc_router_tiles.size() == 0) // case where no physical router tiles were found + { + VPR_FATAL_ERROR(VPR_ERROR_OTHER, "No physical routers were found on the FPGA device. Either the provided name for the physical router tile was incorrect or the FPGA device has no routers."); + } // generate noc model generate_noc(arch, noc_ctx, list_of_noc_router_tiles); From 6f4beaec178208f9d3c746f023ff1f3a35696b03 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 7 Feb 2022 22:34:53 -0500 Subject: [PATCH 023/128] modified function that adds routers to noc model so that the algorithm found the closest physical router to each logical router, instead of the other way around. --- vpr/src/base/noc_storage.cpp | 15 +++--- vpr/src/base/noc_storage.h | 2 +- vpr/src/base/setup_noc.cpp | 95 +++++++++++++++++++++++------------- 3 files changed, 69 insertions(+), 43 deletions(-) diff --git a/vpr/src/base/noc_storage.cpp b/vpr/src/base/noc_storage.cpp index 8d846c0c736..783cde6d7ed 100644 --- a/vpr/src/base/noc_storage.cpp +++ b/vpr/src/base/noc_storage.cpp @@ -55,20 +55,21 @@ int NocStorage::get_noc_link_number_of_connections(NocLinkId id) const{ return link_storage[id].get_number_of_connections(); } -bool NocStorage::add_router(int id, int grid_position_x, int grid_posistion_y){ +void NocStorage::add_router(int id, int grid_position_x, int grid_posistion_y){ VTR_ASSERT_MSG(!built_noc, "NoC already built, cannot modify further."); router_storage.emplace_back(id, grid_position_x, grid_posistion_y); - // get the corresponding NocRouterId for the newly added router and - // add it to the conversion table. - // We build the conversion table here as it gurantees only unique routers - // in the NoC are added. + /* Get the corresponding NocRouterId for the newly added router and + add it to the conversion table. + Since the router is added at the end of the list, the id is equivalent to the last element index. + We build the conversion table here as it gurantees only unique routers + in the NoC are added. + */ NocRouterId converted_id((int)(router_storage.size() - 1)); - std::pair::iterator, bool> result= router_id_conversion_table.emplace(id, converted_id); - return result.second; + return; } void NocStorage::add_link(NocRouterId source, NocRouterId sink){ diff --git a/vpr/src/base/noc_storage.h b/vpr/src/base/noc_storage.h index 71af56804ec..51fff48e0fb 100644 --- a/vpr/src/base/noc_storage.h +++ b/vpr/src/base/noc_storage.h @@ -62,7 +62,7 @@ class NocStorage int get_noc_link_number_of_connections(NocLinkId id) const; // setters for the NoC - bool add_router(int id, int grid_position_x, int grid_position_y); + void add_router(int id, int grid_position_x, int grid_position_y); void add_link(NocRouterId source, NocRouterId sink); // setters for the noc router diff --git a/vpr/src/base/setup_noc.cpp b/vpr/src/base/setup_noc.cpp index 2d5d315ff75..538ba362df7 100644 --- a/vpr/src/base/setup_noc.cpp +++ b/vpr/src/base/setup_noc.cpp @@ -131,10 +131,10 @@ void generate_noc(const t_arch& arch, NocContext& noc_ctx, std::vector& list_of_noc_router_tiles) { // keep track of the shortest distance between a logical router and the curren physical router tile - // also keep track of the corresponding logical router + // also keep track of the corresponding physical router tile index (within the list) double shortest_distance; double curr_calculated_distance; - t_router* closest_router; + int closest_physical_router; // information regarding physical router position double curr_physical_router_pos_x; @@ -144,38 +144,50 @@ void create_noc_routers(t_noc_inf noc_info, NocStorage* noc_model , std::vector< double curr_logical_router_position_x; double curr_logical_router_position_y; - // result of adding a router to the NoC - bool router_creation; + // keep track of the index of each physical router (this helps uniqely identify them) + int curr_physical_router_index = 0; // keep track of the ids of the routers that ceate the case where multiple routers // have the same distance to a physical router tile - int error_case_router_id_1; - int error_case_router_id_2; + int error_case_physical_router_index_1; + int error_case_physical_router_index_2; + + // keep track of all the logical router and physical router assignments (their pairings) + // they are stored in the form (physical router index, logical router id) + std::unordered_map router_assignments; + router_assignments.clear(); + + // reference to access elements in the router_assignments above + std::unordered_map::const_iterator single_router_assignment; // Below we create all the routers within the NoC // - // go through each physical router tile and assign it to a logical router specified by the user - // in the architecture escription - for (auto physical_router = list_of_noc_router_tiles.begin(); physical_router != list_of_noc_router_tiles.end(); physical_router++) + // go through each logical router tile and assign it to a physical router on the FPGA + for (auto logical_router = noc_info.router_list.begin(); logical_router != noc_info.router_list.end(); logical_router++) { - // assign the shortest distance to a large value (this is done so that the first distance calculated can replace this) + // assign the shortest distance to a large value (this is done so that the first distance calculated and we can replace this) shortest_distance = LLONG_MAX; - curr_physical_router_pos_x = physical_router->tile_centroid_x; - curr_physical_router_pos_y = physical_router->tile_centroid_y; + // get position of the current logical router + curr_logical_router_position_x = logical_router->device_x_position; + curr_logical_router_position_y = logical_router->device_y_position; + + closest_physical_router = 0; - closest_router = NULL; + // the starting index of the physical router list + curr_physical_router_index = 0; - // initialze the router ids that track the error case where two routers have the same distance to a physical router - // we initialize it to a in-valid router id, so that it reflects the situation where we never hit this case - error_case_router_id_1 = -1; - error_case_router_id_2 = -1; + // initialze the router ids that track the error case where two physical router tiles have the same distance to a logical router + // we initialize it to a in-valid index, so that it reflects the situation where we never hit this case + error_case_physical_router_index_1 = -1; + error_case_physical_router_index_2 = -1; - // determine the logical router that is closest to the current physocal router tile - for (auto logical_router = noc_info.router_list.begin(); logical_router != noc_info.router_list.end(); logical_router++) + // determine the physical router tile that is closest to the current logical router + for (auto physical_router = list_of_noc_router_tiles.begin(); physical_router != list_of_noc_router_tiles.end(); physical_router++) { - curr_logical_router_position_x = logical_router->device_x_position; - curr_logical_router_position_y = logical_router->device_y_position; + // get the position of the current physical router tile on the FPGA device + curr_physical_router_pos_x = physical_router->tile_centroid_x; + curr_physical_router_pos_y = physical_router->tile_centroid_y; // use euclidean distance to calculate the length between the current logical and physical routers curr_calculated_distance = sqrt(pow(abs(curr_physical_router_pos_x - curr_logical_router_position_x),2.0) + @@ -184,39 +196,52 @@ void create_noc_routers(t_noc_inf noc_info, NocStorage* noc_model , std::vector< // if the current distance is the same as the previous shortest distance if (curr_calculated_distance == shortest_distance) { - // store the ids of the two routers - error_case_router_id_1 = closest_router->id; - error_case_router_id_2 = logical_router->id; + // store the ids of the two physical routers + error_case_physical_router_index_1 = closest_physical_router; + error_case_physical_router_index_2 = curr_physical_router_index; } else if (curr_calculated_distance < shortest_distance) // case where the current logical router is closest to the physical router tile { // update the shortest distance and then the closest router shortest_distance = curr_calculated_distance; - closest_router = &*logical_router; + closest_physical_router = curr_physical_router_index; } + // update the index for the next physical router + curr_physical_router_index++; + } - // check the case where two routers have the same distance to the given physical router tile - if (error_case_router_id_1 == closest_router->id) + // check the case where two physical router tiles have the same distance to the given logical router + if (error_case_physical_router_index_1 == closest_physical_router) { VPR_FATAL_ERROR(VPR_ERROR_OTHER, - "Routers with IDs: '%d' and '%d' have the same distance to a physical router tile located at position (%d,%d). Therefore, no routers could be assigned to the physical router tile.", - error_case_router_id_1, error_case_router_id_2, physical_router->grid_width_position, physical_router->grid_height_position); + "Router with ID:'%d' has the same distance to physical router tiles located at position (%d,%d) and (%d,%d). Therefore, no router assignment could be made.", + logical_router->id, list_of_noc_router_tiles[error_case_physical_router_index_1].grid_width_position, list_of_noc_router_tiles[error_case_physical_router_index_1].grid_height_position, + list_of_noc_router_tiles[error_case_physical_router_index_2].grid_width_position, list_of_noc_router_tiles[error_case_physical_router_index_2].grid_height_position); } - // at this point, the closest logical router to the current physical router was found - // so add the router to the NoC - router_creation = noc_model->add_router(closest_router->id, physical_router->grid_width_position, physical_router->grid_height_position); + // check if the current closest physical router tile was already assigned previously to another logical router + single_router_assignment = router_assignments.find(closest_physical_router); - // if we failed to add a router then that means a logical router was the closest to multiple routers - if (!router_creation) + // the current physical router was already assigned previously, so throw an error + if (single_router_assignment != router_assignments.end()) { - VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Router with ID:'%d' was the closest to multiple physical router tiles and therefore could not be assigned multiple times.", closest_router->id); + VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Routers with IDs:'%d' and '%d' are both closest to physical router tile located at (%d,%d) and the physical router could not be assigned multiple times.", + logical_router->id, single_router_assignment->second, list_of_noc_router_tiles[closest_physical_router].grid_width_position, + list_of_noc_router_tiles[closest_physical_router].grid_height_position); } + // at this point, the closest logical router to the current physical router was found + // so add the router to the NoC + noc_model->add_router(logical_router->id, list_of_noc_router_tiles[closest_physical_router].grid_width_position, + list_of_noc_router_tiles[closest_physical_router].grid_height_position); + + // add the new assignment to the tracker + router_assignments.emplace(closest_physical_router, logical_router->id); + } return; From 1e55e3dfdb42d0a5b201d724a4f4de122c355d3c Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 21 Dec 2021 13:40:23 -0500 Subject: [PATCH 024/128] adding router test --- vpr/src/base/router.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 vpr/src/base/router.cpp diff --git a/vpr/src/base/router.cpp b/vpr/src/base/router.cpp new file mode 100644 index 00000000000..245422404f9 --- /dev/null +++ b/vpr/src/base/router.cpp @@ -0,0 +1,27 @@ + + +#include "router.h" + + +Router::Router(int id, int grid_position_x, int grid_position_y):router_id(id), router_grid_position_x(grid_position_x), router_grid_position_y(grid_position_y) +{ +} + +// getters +int Router::get_router_id(void) +{ + return router_id; +} + +int Router::get_router_grid_position_x(void) +{ + return router_grid_position_x; +} + +int Router::get_router_grid_position_y(void) +{ + return router_grid_position_y; +} + +//test + From cfa39697d2c017ec858e4b046644b017edc25fd9 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 7 Feb 2022 23:15:03 -0500 Subject: [PATCH 025/128] removed older representation of a noc router --- vpr/src/base/router.cpp | 27 --------------------------- 1 file changed, 27 deletions(-) delete mode 100644 vpr/src/base/router.cpp diff --git a/vpr/src/base/router.cpp b/vpr/src/base/router.cpp deleted file mode 100644 index 245422404f9..00000000000 --- a/vpr/src/base/router.cpp +++ /dev/null @@ -1,27 +0,0 @@ - - -#include "router.h" - - -Router::Router(int id, int grid_position_x, int grid_position_y):router_id(id), router_grid_position_x(grid_position_x), router_grid_position_y(grid_position_y) -{ -} - -// getters -int Router::get_router_id(void) -{ - return router_id; -} - -int Router::get_router_grid_position_x(void) -{ - return router_grid_position_x; -} - -int Router::get_router_grid_position_y(void) -{ - return router_grid_position_y; -} - -//test - From dbb09c435aaf0bcf4adb6eb1d4c2d4ca2c1b5074 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 9 Feb 2022 20:38:22 -0500 Subject: [PATCH 026/128] changed router positions provided by the user to double format for higher precision --- libs/libarchfpga/src/physical_types.h | 4 ++-- libs/libarchfpga/src/read_xml_arch_file.cpp | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index c744a1c3f61..e064f7a76a3 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -1779,8 +1779,8 @@ connections regarding individual routers in the network. */ struct t_router { int id = -1; - int device_x_position = -1; - int device_y_position = -1; + double device_x_position = -1; + double device_y_position = -1; std::vector connection_list; }; diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index b110e786b3d..fc78c0b3cf1 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -4717,9 +4717,9 @@ static void processRouter(pugi::xml_node router_tag, const pugiutil::loc_data& l // store the router information from the attributes router_info.id = pugiutil::get_attribute(router_tag, "id", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); - router_info.device_x_position = pugiutil::get_attribute(router_tag, "positionx", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); + router_info.device_x_position = pugiutil::get_attribute(router_tag, "positionx", loc_data, pugiutil::REQUIRED).as_double(attribute_conversion_failure); - router_info.device_y_position = pugiutil::get_attribute(router_tag, "positiony", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); + router_info.device_y_position = pugiutil::get_attribute(router_tag, "positiony", loc_data, pugiutil::REQUIRED).as_double(attribute_conversion_failure); // verify whether the attribute information was legal if ((router_info.id < 0) || (router_info.device_x_position < 0) || (router_info.device_y_position < 0)) { @@ -4860,8 +4860,9 @@ static void generate_noc_mesh(pugi::xml_node mesh_topology_tag, const pugiutil:: temp_router.id = (mesh_size * j) + i; // calculate router position - temp_router.device_x_position = (i + 1)* horizontal_router_seperation; - temp_router.device_y_position = (j + 1) * vertical_router_seperation; + // the first router will always start at the coordinate (mesh_region_startx, mesh_region_start_y). Then the other routers will use the first router as reference and be positioned a specific distance from it. + temp_router.device_x_position = (i + 1)* horizontal_router_seperation + mesh_region_start_x; + temp_router.device_y_position = (j + 1) * vertical_router_seperation + mesh_region_start_y; // assign connections // check if there is a router to the left From 3ca57f19ddd020805fef87bd88053444eb2f0a29 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 14 Feb 2022 20:01:16 -0500 Subject: [PATCH 027/128] modified the mesh creation function to reduce the number of router positions calculated. Also added unit tests to very the change. --- libs/libarchfpga/src/read_xml_arch_file.cpp | 51 ++++--- .../test/test_read_xml_arch_file.cpp | 142 ++++++++++++++++++ 2 files changed, 175 insertions(+), 18 deletions(-) diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index fc78c0b3cf1..e70c344403b 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -274,7 +274,7 @@ e_side string_to_side(std::string side_str); template static T* get_type_by_name(const char* type_name, std::vector& types); -static void generate_noc_mesh(pugi::xml_node mesh_topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, int mesh_region_start_x, int mesh_region_end_x, int mesh_region_start_y, int mesh_region_end_y, int mesh_size); +static void generate_noc_mesh(pugi::xml_node mesh_topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, double mesh_region_start_x, double mesh_region_end_x, double mesh_region_start_y, double mesh_region_end_y, int mesh_size); static bool parse_noc_router_connection_list(std::vector& connection_list, std::string connection_list_attribute_value, std::map>&routers_in_arch_info); @@ -4616,10 +4616,10 @@ static void processMeshTopology(pugi::xml_node mesh_topology_tag, const pugiutil { // noc mesh topology properties - int mesh_region_start_x = 0; - int mesh_region_end_x = 0; - int mesh_region_start_y = 0; - int mesh_region_end_y = 0; + double mesh_region_start_x = 0; + double mesh_region_end_x = 0; + double mesh_region_start_y = 0; + double mesh_region_end_y = 0; int mesh_size = 0; // identifier that lets us know when we could not properly convert an attribute value to a integer @@ -4632,13 +4632,13 @@ static void processMeshTopology(pugi::xml_node mesh_topology_tag, const pugiutil pugiutil::expect_only_attributes(mesh_topology_tag, expected_router_attributes, loc_data); // go through the attributes and store their values - mesh_region_start_x = pugiutil::get_attribute(mesh_topology_tag, "startx", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); + mesh_region_start_x = pugiutil::get_attribute(mesh_topology_tag, "startx", loc_data, pugiutil::REQUIRED).as_double(attribute_conversion_failure); - mesh_region_end_x = pugiutil::get_attribute(mesh_topology_tag, "endx", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); + mesh_region_end_x = pugiutil::get_attribute(mesh_topology_tag, "endx", loc_data, pugiutil::REQUIRED).as_double(attribute_conversion_failure); - mesh_region_start_y = pugiutil::get_attribute(mesh_topology_tag, "starty", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); + mesh_region_start_y = pugiutil::get_attribute(mesh_topology_tag, "starty", loc_data, pugiutil::REQUIRED).as_double(attribute_conversion_failure); - mesh_region_end_y = pugiutil::get_attribute(mesh_topology_tag, "endy", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); + mesh_region_end_y = pugiutil::get_attribute(mesh_topology_tag, "endy", loc_data, pugiutil::REQUIRED).as_double(attribute_conversion_failure); mesh_size = pugiutil::get_attribute(mesh_topology_tag, "size", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); @@ -4825,7 +4825,7 @@ static T* get_type_by_name(const char* type_name, std::vector& types) { "Could not find type: %s\n", type_name); } -static void generate_noc_mesh(pugi::xml_node mesh_topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, int mesh_region_start_x, int mesh_region_end_x, int mesh_region_start_y, int mesh_region_end_y, int mesh_size) +static void generate_noc_mesh(pugi::xml_node mesh_topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, double mesh_region_start_x, double mesh_region_end_x, double mesh_region_start_y, double mesh_region_end_y, int mesh_size) { // check that the mesh size of the router is not 0 @@ -4837,9 +4837,23 @@ static void generate_noc_mesh(pugi::xml_node mesh_topology_tag, const pugiutil:: // calculating the vertical horizontal distances between routers in the supplied region - // we don't want to use decimals - int vertical_router_seperation = (mesh_region_end_y - mesh_region_start_y)/mesh_size; - int horizontal_router_seperation = (mesh_region_end_x - mesh_region_start_x)/mesh_size; + // we decrease the mesh size by 1 when calculating the spacing so that the first and last routers of each row or column are positioned on the mesh boundary + /* + For example: + - If we had a mesh size of 3, then using 3 would result in a spacing that would result in one router positions being placed in either the start of the reigion or end of the region. This is because the distance calculation resulted in having 3 spaces between the ends of the region + + start end + *** *** *** *** + + - if we instead used 2 in the distance calculation, the the resulting positions would result in having 2 routers positioned on the start and end of the region. This is beacuse we now specified 2 spaces between the region and this allows us to place 2 routers on the regions edges and one router in the center. + + start end + *** *** *** + + THe reasoning for this is to reduce the number of calculated router positions. + */ + double vertical_router_seperation = (mesh_region_end_y - mesh_region_start_y)/(mesh_size - 1); + double horizontal_router_seperation = (mesh_region_end_x - mesh_region_start_x)/(mesh_size - 1); t_router temp_router; @@ -4852,17 +4866,18 @@ static void generate_noc_mesh(pugi::xml_node mesh_topology_tag, const pugiutil:: // 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 i = 0; i < mesh_size; i++) + for (int j = 0; j < mesh_size; j++) { - 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 router will always start at the coordinate (mesh_region_startx, mesh_region_start_y). Then the other routers will use the first router as reference and be positioned a specific distance from it. - temp_router.device_x_position = (i + 1)* horizontal_router_seperation + mesh_region_start_x; - temp_router.device_y_position = (j + 1) * vertical_router_seperation + mesh_region_start_y; + /* 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_seperation) + mesh_region_start_x; + temp_router.device_y_position = (j * vertical_router_seperation) + mesh_region_start_y; // assign connections // check if there is a router to the left diff --git a/libs/libarchfpga/test/test_read_xml_arch_file.cpp b/libs/libarchfpga/test/test_read_xml_arch_file.cpp index a90b02edfe6..1ca75f959a8 100644 --- a/libs/libarchfpga/test/test_read_xml_arch_file.cpp +++ b/libs/libarchfpga/test/test_read_xml_arch_file.cpp @@ -5,6 +5,9 @@ // testting statuc functions so include whole source file it is in #include "read_xml_arch_file.cpp" +// for comparing floats +#include "vtr_math.h" + TEST_CASE( "Updating router info in arch", "[NoC Arch Tests]" ) { std::map> test_router_list; @@ -151,4 +154,143 @@ TEST_CASE( "Verifying a parsed NoC topology", "[NoC Arch Tests]" ) { REQUIRE_THROWS_WITH(verify_noc_topology(test_router_list), "The router with id:'4' was included more than once in the architecture file. Routers should only be declared once."); } +} + +TEST_CASE ("Verifying mesh topology creation", "[NoC Arch Tests]") { + + // data for the xml parsing + pugi::xml_node test; + pugiutil::loc_data test_location; + + // the noc storage + t_noc_inf test_noc; + + + // mesh parameters + double mesh_start_x = 10; + double mesh_start_y = 10; + double mesh_end_x = 5; + double mesh_end_y = 56; + double mesh_size = 0; + + SECTION( "Check the error where a mesh size was illegal." ) { + + REQUIRE_THROWS_WITH(generate_noc_mesh(test, test_location, &test_noc, mesh_start_x, mesh_end_x, mesh_start_y, mesh_end_y, mesh_size), "The NoC mesh size cannot be 0."); + + } + SECTION( "Check the error where a mesh region size was invalid." ) { + + mesh_size = 3; + + REQUIRE_THROWS_WITH(generate_noc_mesh(test, test_location, &test_noc, mesh_start_x, mesh_end_x, mesh_start_y, mesh_end_y, mesh_size), "The NoC region is invalid."); + } + SECTION( "Check the mesh creation for integer precision coordinates." ) { + + // define test parameters + mesh_size = 3; + + mesh_start_x = 0; + mesh_start_y = 0; + + mesh_end_x = 4; + mesh_end_y = 4; + + // create the golden golden results + double golden_results_x[9]; + double golden_results_y[9]; + + // first row of the mesh + golden_results_x[0] = 0; + golden_results_y[0] = 0; + golden_results_x[1] = 2; + golden_results_y[1] = 0; + golden_results_x[2] = 4; + golden_results_y[2] = 0; + + // second row of the mesh + golden_results_x[3] = 0; + golden_results_y[3] = 2; + golden_results_x[4] = 2; + golden_results_y[4] = 2; + golden_results_x[5] = 4; + golden_results_y[5] = 2; + + // third row of the mesh + golden_results_x[6] = 0; + golden_results_y[6] = 4; + golden_results_x[7] = 2; + golden_results_y[7] = 4; + golden_results_x[8] = 4; + golden_results_y[8] = 4; + + generate_noc_mesh(test, test_location, &test_noc, mesh_start_x, mesh_end_x, mesh_start_y, mesh_end_y, mesh_size); + + // go through all the expected routers + for (int expected_router_id = 0; expected_router_id < (mesh_size * mesh_size); expected_router_id++) + { + // make sure the router ids match + REQUIRE(test_noc.router_list[expected_router_id].id == expected_router_id); + + // make sure the position of the routers are correct + // x position + REQUIRE(golden_results_x[expected_router_id] == test_noc.router_list[expected_router_id].device_x_position); + // y position + REQUIRE(golden_results_y[expected_router_id] == test_noc.router_list[expected_router_id].device_y_position); + } + } + SECTION( "Check the mesh creation for double precision coordinates." ) { + + // define test parameters + mesh_size = 3; + + mesh_start_x = 3.5; + mesh_start_y = 5.7; + + mesh_end_x = 10.8; + mesh_end_y = 6.4; + + + // create the golden golden results + double golden_results_x[9]; + double golden_results_y[9]; + + // first row of the mesh + golden_results_x[0] = 3.5; + golden_results_y[0] = 5.7; + golden_results_x[1] = 7.15; + golden_results_y[1] = 5.7; + golden_results_x[2] = 10.8; + golden_results_y[2] = 5.7; + + // second row of the mesh + golden_results_x[3] = 3.5; + golden_results_y[3] = 6.05; + golden_results_x[4] = 7.15; + golden_results_y[4] = 6.05; + golden_results_x[5] = 10.8; + golden_results_y[5] = 6.05; + + // third row of the mesh + golden_results_x[6] = 3.5; + golden_results_y[6] = 6.4; + golden_results_x[7] = 7.15; + golden_results_y[7] = 6.4; + golden_results_x[8] = 10.8; + golden_results_y[8] = 6.4; + + generate_noc_mesh(test, test_location, &test_noc, mesh_start_x, mesh_end_x, mesh_start_y, mesh_end_y, mesh_size); + + // go through all the expected routers + for (int expected_router_id = 0; expected_router_id < (mesh_size * mesh_size); expected_router_id++) + { + // make sure the router ids match + REQUIRE(test_noc.router_list[expected_router_id].id == expected_router_id); + + // make sure the position of the routers are correct + // x position + REQUIRE(vtr::isclose(golden_results_x[expected_router_id], test_noc.router_list[expected_router_id].device_x_position)); + // y position + REQUIRE(vtr::isclose(golden_results_y[expected_router_id], test_noc.router_list[expected_router_id].device_y_position)); + } + } } \ No newline at end of file From 3b2a56539049628920414de8cbffd15fa43efd58 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 14 Feb 2022 22:15:31 -0500 Subject: [PATCH 028/128] improved accuracy of float comparison --- vpr/src/base/setup_noc.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vpr/src/base/setup_noc.cpp b/vpr/src/base/setup_noc.cpp index 538ba362df7..5850ffd255b 100644 --- a/vpr/src/base/setup_noc.cpp +++ b/vpr/src/base/setup_noc.cpp @@ -6,6 +6,7 @@ #include "vtr_assert.h" #include "vpr_error.h" +#include "vtr_math.h" void setup_noc(const t_arch& arch, std::string noc_router_tile_name) @@ -194,7 +195,7 @@ void create_noc_routers(t_noc_inf noc_info, NocStorage* noc_model , std::vector< pow(abs(curr_physical_router_pos_y - curr_logical_router_position_y),2.0)); // if the current distance is the same as the previous shortest distance - if (curr_calculated_distance == shortest_distance) + if (vtr::isclose(curr_calculated_distance, shortest_distance)) { // store the ids of the two physical routers error_case_physical_router_index_1 = closest_physical_router; From 12afbd63f69232f3856d58566d2d47485f4d06f7 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 14 Feb 2022 23:07:52 -0500 Subject: [PATCH 029/128] re-added a step in the add_router function to include the mapping between router ids and NocRouter ids --- vpr/src/base/noc_storage.cpp | 1 + vpr/src/base/noc_storage.h | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/vpr/src/base/noc_storage.cpp b/vpr/src/base/noc_storage.cpp index 783cde6d7ed..be03686644e 100644 --- a/vpr/src/base/noc_storage.cpp +++ b/vpr/src/base/noc_storage.cpp @@ -68,6 +68,7 @@ void NocStorage::add_router(int id, int grid_position_x, int grid_posistion_y){ in the NoC are added. */ NocRouterId converted_id((int)(router_storage.size() - 1)); + router_id_conversion_table.emplace(id, convert_router_id); return; } diff --git a/vpr/src/base/noc_storage.h b/vpr/src/base/noc_storage.h index 51fff48e0fb..5448f9606d1 100644 --- a/vpr/src/base/noc_storage.h +++ b/vpr/src/base/noc_storage.h @@ -40,6 +40,7 @@ class NocStorage // prevent "copying" of this object NocStorage(const NocStorage&) = delete; void operator=(const NocStorage&) = delete; + public: // default contructor (cleare all the elements in the vectors) @@ -62,7 +63,7 @@ class NocStorage int get_noc_link_number_of_connections(NocLinkId id) const; // setters for the NoC - void add_router(int id, int grid_position_x, int grid_position_y); + bool add_router(int id, int grid_position_x, int grid_position_y); void add_link(NocRouterId source, NocRouterId sink); // setters for the noc router From 52f05989f39bc10ff532ef84e30c0965c9b82208 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 14 Feb 2022 23:10:41 -0500 Subject: [PATCH 030/128] changed the use of a hashmap to keep of track of router assignments to a vector --- vpr/src/base/noc_storage.h | 2 +- vpr/src/base/setup_noc.cpp | 23 ++++++++--------------- vpr/src/base/setup_noc.h | 3 +++ 3 files changed, 12 insertions(+), 16 deletions(-) diff --git a/vpr/src/base/noc_storage.h b/vpr/src/base/noc_storage.h index 5448f9606d1..51611c841ac 100644 --- a/vpr/src/base/noc_storage.h +++ b/vpr/src/base/noc_storage.h @@ -63,7 +63,7 @@ class NocStorage int get_noc_link_number_of_connections(NocLinkId id) const; // setters for the NoC - bool add_router(int id, int grid_position_x, int grid_position_y); + void add_router(int id, int grid_position_x, int grid_position_y); void add_link(NocRouterId source, NocRouterId sink); // setters for the noc router diff --git a/vpr/src/base/setup_noc.cpp b/vpr/src/base/setup_noc.cpp index 5850ffd255b..a17a081181e 100644 --- a/vpr/src/base/setup_noc.cpp +++ b/vpr/src/base/setup_noc.cpp @@ -154,12 +154,8 @@ void create_noc_routers(t_noc_inf noc_info, NocStorage* noc_model , std::vector< int error_case_physical_router_index_2; // keep track of all the logical router and physical router assignments (their pairings) - // they are stored in the form (physical router index, logical router id) - std::unordered_map router_assignments; - router_assignments.clear(); - - // reference to access elements in the router_assignments above - std::unordered_map::const_iterator single_router_assignment; + std::vector router_assignments; + router_assignments.resize(list_of_noc_router_tiles.size(), PHYSICAL_ROUTER_NOT_ASSIGNED); // Below we create all the routers within the NoC // @@ -180,8 +176,8 @@ void create_noc_routers(t_noc_inf noc_info, NocStorage* noc_model , std::vector< // initialze the router ids that track the error case where two physical router tiles have the same distance to a logical router // we initialize it to a in-valid index, so that it reflects the situation where we never hit this case - error_case_physical_router_index_1 = -1; - error_case_physical_router_index_2 = -1; + error_case_physical_router_index_1 = INVALID_PHYSICAL_ROUTER_INDEX; + error_case_physical_router_index_2 = INVALID_PHYSICAL_ROUTER_INDEX; // determine the physical router tile that is closest to the current logical router for (auto physical_router = list_of_noc_router_tiles.begin(); physical_router != list_of_noc_router_tiles.end(); physical_router++) @@ -224,14 +220,11 @@ void create_noc_routers(t_noc_inf noc_info, NocStorage* noc_model , std::vector< list_of_noc_router_tiles[error_case_physical_router_index_2].grid_width_position, list_of_noc_router_tiles[error_case_physical_router_index_2].grid_height_position); } - // check if the current closest physical router tile was already assigned previously to another logical router - single_router_assignment = router_assignments.find(closest_physical_router); - - // the current physical router was already assigned previously, so throw an error - if (single_router_assignment != router_assignments.end()) + // check if the current physical router was already assigned previously, if so then throw an error + if (router_assignments[closest_physical_router] != PHYSICAL_ROUTER_NOT_ASSIGNED) { VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Routers with IDs:'%d' and '%d' are both closest to physical router tile located at (%d,%d) and the physical router could not be assigned multiple times.", - logical_router->id, single_router_assignment->second, list_of_noc_router_tiles[closest_physical_router].grid_width_position, + logical_router->id, router_assignments[closest_physical_router], list_of_noc_router_tiles[closest_physical_router].grid_width_position, list_of_noc_router_tiles[closest_physical_router].grid_height_position); } @@ -241,7 +234,7 @@ void create_noc_routers(t_noc_inf noc_info, NocStorage* noc_model , std::vector< list_of_noc_router_tiles[closest_physical_router].grid_height_position); // add the new assignment to the tracker - router_assignments.emplace(closest_physical_router, logical_router->id); + router_assignments[closest_physical_router] = logical_router->id; } diff --git a/vpr/src/base/setup_noc.h b/vpr/src/base/setup_noc.h index 73fd86535b8..972aefd7d3e 100644 --- a/vpr/src/base/setup_noc.h +++ b/vpr/src/base/setup_noc.h @@ -12,6 +12,9 @@ #include "noc_storage.h" #include "vpr_error.h" +#define PHYSICAL_ROUTER_NOT_ASSIGNED -1 +#define INVALID_PHYSICAL_ROUTER_INDEX -1 + // a data structure to store the position information of a noc router in the FPGA device From d8bf75aa883b8c0dcd794dc30767360669f22f79 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 16 Feb 2022 00:12:20 -0500 Subject: [PATCH 031/128] added unit tests to verify a portion of the noc storage class --- vpr/test/test_noc_storage.cpp | 128 ++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 vpr/test/test_noc_storage.cpp diff --git a/vpr/test/test_noc_storage.cpp b/vpr/test/test_noc_storage.cpp new file mode 100644 index 00000000000..ba149f3e884 --- /dev/null +++ b/vpr/test/test_noc_storage.cpp @@ -0,0 +1,128 @@ +#include "catch2/catch_test_macros.hpp" + +#include "noc_storage.h" + +#include + +// controls how many routers are in the noc storage, when testing it +#define NUM_OF_ROUTERS 100 + + +namespace { + + TEST_CASE("test_adding_routers_to_noc_storage", "[vpr_noc]") { + + // setup random number generation + std::random_device device; + std::mt19937 rand_num_gen(device()); + std::uniform_int_distribution dist(0,NUM_OF_ROUTERS); + + // create a vector routers that we will use as the golden vector set + std::vector golden_set; + + // individual router parameters + int curr_router_id; + int router_grid_position_x; + int router_grid_position_y; + + // testing datastructure + NocStorage test_noc; + + NocRouterId converted_id; + + + // add all the routers to noc_storage and populate the golden router set + for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++) + { + // determine the current router parameters + curr_router_id = router_number; + router_grid_position_x = router_number + dist(rand_num_gen); + router_grid_position_y = router_number + dist(rand_num_gen); + + // add router to the golden vector + golden_set.emplace_back(router_number, router_grid_position_x, router_grid_position_y); + + // add tje router to the noc + test_noc.add_router(curr_router_id, router_grid_position_x, router_grid_position_y); + + } + + // now verify that the routers were added properly by reading the routers back from the noc and comparing them to the golden set + for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++) + { + // get the converted router id + converted_id = (NocRouterId)router_number; + + // compare all the router properties + REQUIRE(golden_set[router_number].get_router_id() == test_noc.get_noc_router_id(converted_id)); + + REQUIRE(golden_set[router_number].get_router_grid_position_x() == test_noc.get_noc_router_grid_position_x(converted_id)); + + REQUIRE(golden_set[router_number].get_router_grid_position_y() == test_noc.get_noc_router_grid_position_y(converted_id)); + } + + } + TEST_CASE("test_router_id_conversion", "[vpr_noc]") { + + // setup random number generation + std::random_device device; + std::mt19937 rand_num_gen(device()); + std::uniform_int_distribution dist(0,NUM_OF_ROUTERS); + + // create a vector routers that we will use as the golden vector set + std::vector golden_set; + + // individual router parameters + int curr_router_id; + int router_grid_position_x; + int router_grid_position_y; + + // testing datastructure + NocStorage test_noc; + + NocRouterId converted_id; + + + // add all the routers to noc_storage and populate the golden router set + for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++) + { + // determine the current router parameters + curr_router_id = router_number; + router_grid_position_x = router_number + dist(rand_num_gen); + router_grid_position_y = router_number + dist(rand_num_gen); + + // add router to the golden vector + golden_set.emplace_back(router_number, router_grid_position_x, router_grid_position_y); + + // add tje router to the noc + test_noc.add_router(curr_router_id, router_grid_position_x, router_grid_position_y); + + } + + // now verify that the routers were added properly by reading the routers back from the noc and comparing them to the golden set + for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++) + { + // get the converted router id + converted_id = test_noc.convert_router_id(router_number); + + // compare all the router properties + REQUIRE(golden_set[router_number].get_router_id() == test_noc.get_noc_router_id(converted_id)); + + REQUIRE(golden_set[router_number].get_router_grid_position_x() == test_noc.get_noc_router_grid_position_x(converted_id)); + + REQUIRE(golden_set[router_number].get_router_grid_position_y() == test_noc.get_noc_router_grid_position_y(converted_id)); + } + + } + + + + + + + + + + + +} \ No newline at end of file From 5eec09e9f4a108d4106b70a9afb1b22d14182e18 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 18 Feb 2022 20:46:47 -0500 Subject: [PATCH 032/128] fixing compiling issue --- vpr/src/base/noc_storage.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vpr/src/base/noc_storage.cpp b/vpr/src/base/noc_storage.cpp index be03686644e..3054cd26a77 100644 --- a/vpr/src/base/noc_storage.cpp +++ b/vpr/src/base/noc_storage.cpp @@ -68,7 +68,7 @@ void NocStorage::add_router(int id, int grid_position_x, int grid_posistion_y){ in the NoC are added. */ NocRouterId converted_id((int)(router_storage.size() - 1)); - router_id_conversion_table.emplace(id, convert_router_id); + router_id_conversion_table.emplace(id, converted_id); return; } From f3e12a63f5ef4a71f2e79b89e1a32b6e3e33474d Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 18 Feb 2022 20:49:26 -0500 Subject: [PATCH 033/128] added unit tests to verfiy the noc datastructure in vtr --- vpr/test/test_noc_storage.cpp | 164 ++++++++++++++++++++++++++++++++++ 1 file changed, 164 insertions(+) diff --git a/vpr/test/test_noc_storage.cpp b/vpr/test/test_noc_storage.cpp index ba149f3e884..133891a7e34 100644 --- a/vpr/test/test_noc_storage.cpp +++ b/vpr/test/test_noc_storage.cpp @@ -7,6 +7,10 @@ // controls how many routers are in the noc storage, when testing it #define NUM_OF_ROUTERS 100 +// defines the number of links each router has +// range [1, NUM_OF_ROUTERS - 1] +#define NOC_CONNECTIVITY 10 + namespace { @@ -114,6 +118,166 @@ namespace { } } + TEST_CASE("test_add_link", "[vpr_noc]") { + + // create a vector to store the golden links + std::vector golden_set; + + // temp variables that hold the noc link properties + NocRouterId source; + NocRouterId sink; + + NocLinkId link_id; + + // testing datastructure + NocStorage test_noc; + + int total_num_of_links = NUM_OF_ROUTERS * NOC_CONNECTIVITY; + + // noc router stuff (we need routers before being able to add links) + int router_id = 0; + int curr_router_x_pos = 0; + int curr_router_y_pos = 0; + + // add all the routers to noc_storage and populate the golden router set + for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++) + { + // determine the current router parameters + router_id = router_number; + + // add tje router to the noc + test_noc.add_router(router_id, curr_router_x_pos, curr_router_y_pos); + + } + + // allocate the size for the links + test_noc.make_room_for_noc_router_link_list(); + + for (int source_router_id = 0; source_router_id < NUM_OF_ROUTERS; source_router_id++) + { + source = (NocRouterId)source_router_id; + + + for (int sink_router_id = 0; sink_router_id < NOC_CONNECTIVITY; sink_router_id++) + { + sink = (NocRouterId)sink_router_id; + + // makes sure we do not create a link for a router who acts as a sink and source + if (source_router_id != sink_router_id) + { + // add link to the golden reference + golden_set.emplace_back(source, sink); + + // add the link to the NoC + test_noc.add_link(source, sink); + } + + } + } + + // verify that the links were added properly to the NoC + for (int link_number = 0; link_number < total_num_of_links; link_number++) + { + link_id = (NocLinkId)link_number; + + // verify the link by checking its properties + REQUIRE(golden_set[link_number].get_source_router() == test_noc.get_noc_link_source_router(link_id)); + + REQUIRE(golden_set[link_number].get_sink_router() == test_noc.get_noc_link_sink_router(link_id)); + } + + } + TEST_CASE("test_router_link_list", "[vpr_noc]") + { + // create a vector to store the golden links + vtr::vector> golden_set; + + // list of router connections returned from the NoC + std::vector router_links; + + golden_set.resize(NUM_OF_ROUTERS); + + // temp variables that hold the noc link properties + NocRouterId source; + NocRouterId sink; + + NocLinkId link_id; + + // testing datastructure + NocStorage test_noc; + + // need to assign + + int curr_link_number = 0; + + int connection_size; + + // noc router stuff (we need routers before being able to add links) + int router_id = 0; + int curr_router_x_pos = 0; + int curr_router_y_pos = 0; + + // add all the routers to noc_storage and populate the golden router set + for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++) + { + // determine the current router parameters + router_id = router_number; + + // add tje router to the noc + test_noc.add_router(router_id, curr_router_x_pos, curr_router_y_pos); + + } + + // allocate the size for the links + test_noc.make_room_for_noc_router_link_list(); + + for (int source_router_id = 0; source_router_id < NUM_OF_ROUTERS; source_router_id++) + { + source = (NocRouterId)source_router_id; + + for (int sink_router_id = 0; sink_router_id < NOC_CONNECTIVITY; sink_router_id++) + { + sink = (NocRouterId)sink_router_id; + + // makes sure we do not create a link for a router who acts as a sink and source + if (source_router_id != sink_router_id) + { + // add the link to the NoC + test_noc.add_link(source, sink); + + // add the link id to the golden set + golden_set[source].push_back((NocLinkId)curr_link_number); + + curr_link_number++; + } + + + + } + } + + // now verify that the connection lists were created correctly + for (int id = 0; id < NUM_OF_ROUTERS; id++) + { + // get the current router id + source = (NocRouterId)id; + + // get the router connections from the + router_links = test_noc.get_noc_router_connections(source); + + // get the size of the current router connection list + connection_size = golden_set[source].size(); + + // go through the links from the noc and make sure they match the golden set + for (int link_index = 0; link_index < connection_size; link_index++) + { + REQUIRE(golden_set[source][link_index] == router_links[link_index]); + + } + + } + + } From cf0f13543d8bcbf172de8092679f8f86c360ca03 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 11 Mar 2022 19:53:53 -0500 Subject: [PATCH 034/128] updated error message associated with the tag --- libs/libarchfpga/src/read_xml_arch_file.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index e70c344403b..0b185b753b2 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -4646,7 +4646,7 @@ static void processMeshTopology(pugi::xml_node mesh_topology_tag, const pugiutil if (( mesh_region_start_x < 0) || (mesh_region_end_x < 0) || (mesh_region_start_y < 0) || (mesh_region_end_y < 0) || (mesh_size < 0)) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(mesh_topology_tag), - "The parameters for the mesh topology have to be positive integers."); + "The parameters for the mesh topology have to be positive values."); } // now create the mesh topology for the noc From fb41204aade579a3e1963a5b18234cb3a384a7b9 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 11 Mar 2022 19:57:31 -0500 Subject: [PATCH 035/128] added a unit tests for functions regarding the noc model setup --- vpr/test/test_noc_storage.cpp | 11 - vpr/test/test_setup_noc.cpp | 450 ++++++++++++++++++++++++++++++++++ 2 files changed, 450 insertions(+), 11 deletions(-) create mode 100644 vpr/test/test_setup_noc.cpp diff --git a/vpr/test/test_noc_storage.cpp b/vpr/test/test_noc_storage.cpp index 133891a7e34..be64c65ebea 100644 --- a/vpr/test/test_noc_storage.cpp +++ b/vpr/test/test_noc_storage.cpp @@ -278,15 +278,4 @@ namespace { } } - - - - - - - - - - - } \ No newline at end of file diff --git a/vpr/test/test_setup_noc.cpp b/vpr/test/test_setup_noc.cpp new file mode 100644 index 00000000000..45761e06933 --- /dev/null +++ b/vpr/test/test_setup_noc.cpp @@ -0,0 +1,450 @@ +#include "catch2/catch_test_macros.hpp" + +#include "setup_noc.h" +#include "globals.h" +#include "physical_types.h" + +// for comparing floats +#include "vtr_math.h" + +namespace{ + + TEST_CASE("test_identify_and_store_noc_router_tile_positions", "[vpr_setup_noc]"){ + + // test device grid name + std::string device_grid_name = "test"; + + // creating a reference for the empty tile name and router name + char empty_tile_name[6] = "empty"; + char router_tile_name[7] = "router"; + + // device grid parameters + int test_grid_width = 10; + int test_grid_height = 10; + + // create the test device grid (10x10) + auto test_grid = vtr::Matrix({10, 10}); + + // create an empty physical tile and assign its parameters + t_physical_tile_type empty_tile; + empty_tile.name = empty_tile_name; + empty_tile.height = 1; + empty_tile.width = 1; + + // create a router tile and assign its parameters + // the router will take up 4 grid spaces and be named "router" + t_physical_tile_type router_tile; + router_tile.name = router_tile_name; + router_tile.height = 2; + router_tile.width = 2; + + // name of the router physical tile + //std::string router_tile_name_string("router"); + + // results from the test function + std::vector list_of_routers; + + // make sure the test result is not corrupted + REQUIRE(list_of_routers.size() == 0); + + + SECTION("All routers are seperated by one or more grid spaces"){ + + // in this test, the routers will be on the 4 corners of the FPGA + + // bottom left corner + test_grid[0][0].type = &router_tile; + test_grid[0][0].height_offset = 0; + test_grid[0][0].width_offset = 0; + + test_grid[1][0].type = &router_tile; + test_grid[1][0].height_offset = 0; + test_grid[1][0].width_offset = 1; + + test_grid[0][1].type = &router_tile; + test_grid[0][1].height_offset = 1; + test_grid[0][1].width_offset = 0; + + test_grid[1][1].type = &router_tile; + test_grid[1][1].height_offset = 1; + test_grid[1][1].width_offset = 1; + + // bottom right corner + test_grid[8][0].type = &router_tile; + test_grid[8][0].height_offset = 0; + test_grid[8][0].width_offset = 0; + + test_grid[9][0].type = &router_tile; + test_grid[9][0].height_offset = 0; + test_grid[9][0].width_offset = 1; + + test_grid[8][1].type = &router_tile; + test_grid[8][1].height_offset = 1; + test_grid[8][1].width_offset = 0; + + test_grid[9][1].type = &router_tile; + test_grid[9][1].height_offset = 1; + test_grid[9][1].width_offset = 1; + + // top left corner + test_grid[0][8].type = &router_tile; + test_grid[0][8].height_offset = 0; + test_grid[0][8].width_offset = 0; + + test_grid[1][8].type = &router_tile; + test_grid[1][8].height_offset = 0; + test_grid[1][8].width_offset = 1; + + test_grid[0][9].type = &router_tile; + test_grid[0][9].height_offset = 1; + test_grid[0][9].width_offset = 0; + + test_grid[1][9].type = &router_tile; + test_grid[1][9].height_offset = 1; + test_grid[1][9].width_offset = 1; + + // top right corner + test_grid[8][8].type = &router_tile; + test_grid[8][8].height_offset = 0; + test_grid[8][8].width_offset = 0; + + test_grid[9][8].type = &router_tile; + test_grid[9][8].height_offset = 0; + test_grid[9][8].width_offset = 1; + + test_grid[8][9].type = &router_tile; + test_grid[8][9].height_offset = 1; + test_grid[8][9].width_offset = 0; + + test_grid[9][9].type = &router_tile; + test_grid[9][9].height_offset = 1; + test_grid[9][9].width_offset = 1; + + for(int i = 0; i < test_grid_width; i++) + { + for(int j = 0; j < test_grid_height; j++) + { + // make sure the current tyle is not a router + if (test_grid[i][j].type == nullptr) + { + // assign the non-router tile as empty + test_grid[i][j].type = &empty_tile; + test_grid[i][j].width_offset = 0; + test_grid[i][j].height_offset = 0; + } + } + } + + // create a new device grid + DeviceGrid test_device = DeviceGrid(device_grid_name, test_grid); + + // call the test function + identify_and_store_noc_router_tile_positions(test_device, list_of_routers, std::string(router_tile_name)); + + // check that the physocal router tile positions were correctly determined + // make sure that only 4 router tiles were found + REQUIRE(list_of_routers.size() == 4); + + // 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)); + + // 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)); + + // 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)); + + // 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)); + } + SECTION("All routers are horizontally connected to another router"){ + + // in this test, the routers will be on the 4 corners of the FPGA + + // bottom left corner + test_grid[3][0].type = &router_tile; + test_grid[3][0].height_offset = 0; + test_grid[3][0].width_offset = 0; + + test_grid[4][0].type = &router_tile; + test_grid[4][0].height_offset = 0; + test_grid[4][0].width_offset = 1; + + test_grid[3][1].type = &router_tile; + test_grid[3][1].height_offset = 1; + test_grid[3][1].width_offset = 0; + + test_grid[4][1].type = &router_tile; + test_grid[4][1].height_offset = 1; + test_grid[4][1].width_offset = 1; + + // bottom right corner + test_grid[5][0].type = &router_tile; + test_grid[5][0].height_offset = 0; + test_grid[5][0].width_offset = 0; + + test_grid[6][0].type = &router_tile; + test_grid[6][0].height_offset = 0; + test_grid[6][0].width_offset = 1; + + test_grid[5][1].type = &router_tile; + test_grid[5][1].height_offset = 1; + test_grid[5][1].width_offset = 0; + + test_grid[6][1].type = &router_tile; + test_grid[6][1].height_offset = 1; + test_grid[6][1].width_offset = 1; + + // top left corner + test_grid[0][5].type = &router_tile; + test_grid[0][5].height_offset = 0; + test_grid[0][5].width_offset = 0; + + test_grid[1][5].type = &router_tile; + test_grid[1][5].height_offset = 0; + test_grid[1][5].width_offset = 1; + + test_grid[0][6].type = &router_tile; + test_grid[0][6].height_offset = 1; + test_grid[0][6].width_offset = 0; + + test_grid[1][6].type = &router_tile; + test_grid[1][6].height_offset = 1; + test_grid[1][6].width_offset = 1; + + // top right corner + test_grid[2][5].type = &router_tile; + test_grid[2][5].height_offset = 0; + test_grid[2][5].width_offset = 0; + + test_grid[3][5].type = &router_tile; + test_grid[3][5].height_offset = 0; + test_grid[3][5].width_offset = 1; + + test_grid[2][6].type = &router_tile; + test_grid[2][6].height_offset = 1; + test_grid[2][6].width_offset = 0; + + test_grid[3][6].type = &router_tile; + test_grid[3][6].height_offset = 1; + test_grid[3][6].width_offset = 1; + + for(int i = 0; i < test_grid_width; i++) + { + for(int j = 0; j < test_grid_height; j++) + { + // make sure the current tyle is not a router + if (test_grid[i][j].type == nullptr) + { + // assign the non-router tile as empty + test_grid[i][j].type = &empty_tile; + test_grid[i][j].width_offset = 0; + test_grid[i][j].height_offset = 0; + } + } + } + + // create a new device grid + DeviceGrid test_device = DeviceGrid(device_grid_name, test_grid); + + // call the test function + identify_and_store_noc_router_tile_positions(test_device, list_of_routers, std::string(router_tile_name)); + + // check that the physocal router tile positions were correctly determined + // make sure that only 4 router tiles were found + REQUIRE(list_of_routers.size() == 4); + + // 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)); + + // 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)); + + // 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)); + + // 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)); + } + SECTION("All routers are vertically connected to another router"){ + + // in this test, the routers will be on the 4 corners of the FPGA + + // bottom left corner + test_grid[0][2].type = &router_tile; + test_grid[0][2].height_offset = 0; + test_grid[0][2].width_offset = 0; + + test_grid[1][2].type = &router_tile; + test_grid[1][2].height_offset = 0; + test_grid[1][2].width_offset = 1; + + test_grid[0][3].type = &router_tile; + test_grid[0][3].height_offset = 1; + test_grid[0][3].width_offset = 0; + + test_grid[1][3].type = &router_tile; + test_grid[1][3].height_offset = 1; + test_grid[1][3].width_offset = 1; + + // bottom right corner + test_grid[0][4].type = &router_tile; + test_grid[0][4].height_offset = 0; + test_grid[0][4].width_offset = 0; + + test_grid[1][4].type = &router_tile; + test_grid[1][4].height_offset = 0; + test_grid[1][4].width_offset = 1; + + test_grid[0][5].type = &router_tile; + test_grid[0][5].height_offset = 1; + test_grid[0][5].width_offset = 0; + + test_grid[1][5].type = &router_tile; + test_grid[1][5].height_offset = 1; + test_grid[1][5].width_offset = 1; + + // top left corner + test_grid[7][6].type = &router_tile; + test_grid[7][6].height_offset = 0; + test_grid[7][6].width_offset = 0; + + test_grid[8][6].type = &router_tile; + test_grid[8][6].height_offset = 0; + test_grid[8][6].width_offset = 1; + + test_grid[7][7].type = &router_tile; + test_grid[7][7].height_offset = 1; + test_grid[7][7].width_offset = 0; + + test_grid[8][7].type = &router_tile; + test_grid[8][7].height_offset = 1; + test_grid[8][7].width_offset = 1; + + // top right corner + test_grid[7][8].type = &router_tile; + test_grid[7][8].height_offset = 0; + test_grid[7][8].width_offset = 0; + + test_grid[8][8].type = &router_tile; + test_grid[8][8].height_offset = 0; + test_grid[8][8].width_offset = 1; + + test_grid[7][9].type = &router_tile; + test_grid[7][9].height_offset = 1; + test_grid[7][9].width_offset = 0; + + test_grid[8][9].type = &router_tile; + test_grid[8][9].height_offset = 1; + test_grid[8][9].width_offset = 1; + + for(int i = 0; i < test_grid_width; i++) + { + for(int j = 0; j < test_grid_height; j++) + { + // make sure the current tyle is not a router + if (test_grid[i][j].type == nullptr) + { + // assign the non-router tile as empty + test_grid[i][j].type = &empty_tile; + test_grid[i][j].width_offset = 0; + test_grid[i][j].height_offset = 0; + } + } + } + + // create a new device grid + DeviceGrid test_device = DeviceGrid(device_grid_name, test_grid); + + // call the test function + identify_and_store_noc_router_tile_positions(test_device, list_of_routers, std::string(router_tile_name)); + + // check that the physocal router tile positions were correctly determined + // make sure that only 4 router tiles were found + REQUIRE(list_of_routers.size() == 4); + + // 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)); + + // 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)); + + // 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)); + + // 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)); + } + + } + TEST_CASE("test_create_noc_routers", "[vpr_setup_noc]"){ + + // datastructure to hold the list of physical tiles + std::vector list_of_routers; + + /* + Setup: + - The router will take over a 3x2 grid area + - The NoC will be a 3x3 Mesh topology and located at + the following: + - router 1: (0,0) + - router 2: (4,0) + - router 3: (8,0) + - router 4: (0,4) + - router 5: (4,4) + - router 6: (8,4) + - router 7: (0,8) + - router 8: (4,8) + - router 9: (8,8) + */ + list_of_routers.push_back({0,0,0.5,1}); + list_of_routers.push_back({4,0,4.5,1}); + list_of_routers.push_back({8,0,8.5,1}); + + list_of_routers.push_back({0,4,0.5,5}); + list_of_routers.push_back({4,4,4.5,5}); + list_of_routers.push_back({8,4,8.5,5}); + + list_of_routers.push_back({0,8,0.5,9}); + list_of_routers.push_back({4,8,4.5,9}); + list_of_routers.push_back({8,8,8.5,9}); + + } + +} \ No newline at end of file From 0de01cceec79f4758d4b9e6ebad0b459fbe52dbc Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 11 Mar 2022 19:59:07 -0500 Subject: [PATCH 036/128] fixed issue with how the centroid points were being calculated for each router tile. Also fixed bug that was incorrectly identifying noc router physical tiles --- vpr/src/base/setup_noc.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vpr/src/base/setup_noc.cpp b/vpr/src/base/setup_noc.cpp index a17a081181e..c95a0654e57 100644 --- a/vpr/src/base/setup_noc.cpp +++ b/vpr/src/base/setup_noc.cpp @@ -81,11 +81,11 @@ void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, Only store the tile position if it is a noc router. Additionally, since a router tile can span multiple grid locations, we only add the tile if the height and width offset are zero (this prevents the router from being added multiple times for each grid location it spans). */ - if (!((noc_router_tile_name.compare(curr_tile_name)) && curr_tile_width_offset && curr_tile_height_offset)) + if (!(noc_router_tile_name.compare(curr_tile_name)) && !curr_tile_width_offset && !curr_tile_height_offset) { // calculating the centroid position of the current tile - curr_tile_centroid_x = curr_tile_width/(double)2 + i; - curr_tile_centroid_y = curr_tile_height/(double)2 + j; + curr_tile_centroid_x = (curr_tile_width - 1)/(double)2 + i; + curr_tile_centroid_y = (curr_tile_height - 1)/(double)2 + j; list_of_noc_router_tiles.push_back({i,j,curr_tile_centroid_x, curr_tile_centroid_y}); } From df88ab72bab908e3c1ffdb69617387bb893a99c6 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Sun, 13 Mar 2022 18:30:41 -0400 Subject: [PATCH 037/128] added getters to the noc storage class to retrieve the fulle list of all routers and links inside the NoC --- vpr/src/base/noc_storage.cpp | 10 ++++++++++ vpr/src/base/noc_storage.h | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/vpr/src/base/noc_storage.cpp b/vpr/src/base/noc_storage.cpp index 3054cd26a77..8d69a51399b 100644 --- a/vpr/src/base/noc_storage.cpp +++ b/vpr/src/base/noc_storage.cpp @@ -15,6 +15,16 @@ const std::vector& NocStorage::get_noc_router_connections(NocRouterId } +const vtr::vector& NocStorage::get_noc_routers(void) const{ + + return router_storage; +} + +const vtr::vector& NocStorage::get_noc_links(void) const{ + + return link_storage; +} + int NocStorage::get_noc_router_grid_position_x(NocRouterId id) const{ return router_storage[id].get_router_grid_position_x(); diff --git a/vpr/src/base/noc_storage.h b/vpr/src/base/noc_storage.h index 51611c841ac..52f3c95352d 100644 --- a/vpr/src/base/noc_storage.h +++ b/vpr/src/base/noc_storage.h @@ -48,6 +48,8 @@ class NocStorage // getters for the NoC const std::vector& get_noc_router_connections(NocRouterId id) const; + const vtr::vector& get_noc_routers(void) const; + const vtr::vector& get_noc_links(void) const; // getters for routers int get_noc_router_grid_position_x(NocRouterId id) const; @@ -79,6 +81,9 @@ class NocStorage NocRouterId convert_router_id(int id) const; void make_room_for_noc_router_link_list(); + + + }; From ad39612704501041647c8f97c862e879a95f65d6 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Sun, 13 Mar 2022 18:32:05 -0400 Subject: [PATCH 038/128] modified the noc router creator function to pass the noc information from the user by reference --- vpr/src/base/setup_noc.cpp | 2 +- vpr/src/base/setup_noc.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vpr/src/base/setup_noc.cpp b/vpr/src/base/setup_noc.cpp index c95a0654e57..61e08bfe250 100644 --- a/vpr/src/base/setup_noc.cpp +++ b/vpr/src/base/setup_noc.cpp @@ -129,7 +129,7 @@ void generate_noc(const t_arch& arch, NocContext& noc_ctx, std::vector& list_of_noc_router_tiles) +void create_noc_routers(const t_noc_inf& noc_info, NocStorage* noc_model , std::vector& list_of_noc_router_tiles) { // keep track of the shortest distance between a logical router and the curren physical router tile // also keep track of the corresponding physical router tile index (within the list) diff --git a/vpr/src/base/setup_noc.h b/vpr/src/base/setup_noc.h index 972aefd7d3e..5ab554dcd9f 100644 --- a/vpr/src/base/setup_noc.h +++ b/vpr/src/base/setup_noc.h @@ -35,7 +35,7 @@ void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, void generate_noc(const t_arch& arch, NocContext& noc_ctx, std::vector& list_of_noc_router_tiles); -void create_noc_routers(t_noc_inf noc_info, NocStorage* noc_model, std::vector& list_of_noc_router_tiles); +void create_noc_routers(const t_noc_inf& noc_info, NocStorage* noc_model, std::vector& list_of_noc_router_tiles); void create_noc_links(const t_noc_inf* noc_info, NocStorage* noc_model); From c3dbe68c26fe49df571ca75c6717eee3aa3636f2 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 16 Mar 2022 19:50:23 -0400 Subject: [PATCH 039/128] added unit tests to verify functions associated with setting up the NoC --- vpr/test/test_setup_noc.cpp | 557 +++++++++++++++++++++++++++++++++++- 1 file changed, 555 insertions(+), 2 deletions(-) diff --git a/vpr/test/test_setup_noc.cpp b/vpr/test/test_setup_noc.cpp index 45761e06933..430fdf9f880 100644 --- a/vpr/test/test_setup_noc.cpp +++ b/vpr/test/test_setup_noc.cpp @@ -1,4 +1,5 @@ #include "catch2/catch_test_macros.hpp" +#include "catch2/matchers/catch_matchers_all.hpp" #include "setup_noc.h" #include "globals.h" @@ -420,9 +421,9 @@ namespace{ /* Setup: - - The router will take over a 3x2 grid area + - The router will take over a 2x3 grid area - The NoC will be a 3x3 Mesh topology and located at - the following: + the following positions: - router 1: (0,0) - router 2: (4,0) - router 3: (8,0) @@ -445,6 +446,558 @@ namespace{ list_of_routers.push_back({4,8,4.5,9}); list_of_routers.push_back({8,8,8.5,9}); + // create the noc model (to store the routers) + NocStorage noc_model; + + // create the logical router list + t_noc_inf noc_info; + + // pointer to each logical router + t_router* temp_router = NULL; + + const vtr::vector* noc_routers = NULL; + + SECTION("Test create routers when logical routers match to exactly one physical router. The number of routers is less than whats on the FPGA."){ + + // start by creating all the logical routers + // this is similiar to the user provided a config file + temp_router = new t_router; + + NocRouterId noc_router_id; + + for (int router_id = 1; router_id < 7; router_id++){ + + // we will have 6 logical routers that will take up the bottom and middle physical routers of the mesh + temp_router->device_x_position = list_of_routers[router_id-1].tile_centroid_x; + temp_router->device_y_position = list_of_routers[router_id-1].tile_centroid_y; + temp_router->id = router_id; + noc_info.router_list.push_back(*temp_router); + } + + // delete the router struct + delete temp_router; + + // call the router creation + create_noc_routers(noc_info, &noc_model, list_of_routers); + + // get the routers from the noc + noc_routers = &(noc_model.get_noc_routers()); + + // first check that only 6 routers were created + REQUIRE(noc_routers->size() == 6); + + // now we got through the noc model and confirm that the correct + for (int router_id = 1; router_id < 7; router_id++) + { + // covert the router id + noc_router_id = noc_model.convert_router_id(router_id); + + // now check that the proper physical router was assigned to + REQUIRE(noc_model.get_noc_router_grid_position_x(noc_router_id) == list_of_routers[router_id-1].grid_width_position); + REQUIRE(noc_model.get_noc_router_grid_position_y(noc_router_id) == list_of_routers[router_id-1].grid_height_position); + + } + } + SECTION("Test create routers when logical routers match to exactly one physical router. The number of routers is exacrly the same as on the FPGA."){ + + // start by creating all the logical routers + // this is similiar to the user provided a config file + temp_router = new t_router; + + NocRouterId noc_router_id; + + for (int router_id = 1; router_id < 10; router_id++){ + + // we will have 6 logical routers that will take up the bottom and middle physical routers of the mesh + temp_router->device_x_position = list_of_routers[router_id-1].tile_centroid_x; + temp_router->device_y_position = list_of_routers[router_id-1].tile_centroid_y; + temp_router->id = router_id; + noc_info.router_list.push_back(*temp_router); + } + + // delete the router struct + delete temp_router; + + // call the router creation + create_noc_routers(noc_info, &noc_model, list_of_routers); + + // get the routers from the noc + noc_routers = &(noc_model.get_noc_routers()); + + // first check that only 6 routers were created + REQUIRE(noc_routers->size() == 9); + + // now we got through the noc model and confirm that the correct + for (int router_id = 1; router_id < 10; router_id++) + { + // covert the router id + noc_router_id = noc_model.convert_router_id(router_id); + + // now check that the proper physical router was assigned to + REQUIRE(noc_model.get_noc_router_grid_position_x(noc_router_id) == list_of_routers[router_id-1].grid_width_position); + REQUIRE(noc_model.get_noc_router_grid_position_y(noc_router_id) == list_of_routers[router_id-1].grid_height_position); + + } + } + SECTION("Test create routers when a logical router can be matched to two physical routers. The number of routers is exactly the same as on the FPGA."){ + + // start by creating all the logical routers + // this is similiar to the user provided a config file + temp_router = new t_router; + + NocRouterId noc_router_id; + + for (int router_id = 1; router_id < 9; router_id++){ + + // we will have 6 logical routers that will take up the bottom and middle physical routers of the mesh + temp_router->device_x_position = list_of_routers[router_id-1].tile_centroid_x; + temp_router->device_y_position = list_of_routers[router_id-1].tile_centroid_y; + temp_router->id = router_id; + noc_info.router_list.push_back(*temp_router); + } + + // the top right logical router will be between the top right and top center physical routers in the mesh + temp_router->device_x_position = 6.5; + temp_router->device_y_position = 9; + temp_router->id = 9; + noc_info.router_list.push_back(*temp_router); + + // delete the router struct + delete temp_router; + + // call the router creation + REQUIRE_THROWS_WITH(create_noc_routers(noc_info, &noc_model, list_of_routers), "Router with ID:'9' has the same distance to physical router tiles located at position (4,8) and (8,8). Therefore, no router assignment could be made."); + } + SECTION("Test create routers when a physical router can be matched to two logical routers. The number of routers is exactly the same as on the FPGA."){ + + // start by creating all the logical routers + // this is similiar to the user provided a config file + temp_router = new t_router; + + NocRouterId noc_router_id; + + for (int router_id = 1; router_id < 9; router_id++){ + + // we will have 6 logical routers that will take up the bottom and middle physical routers of the mesh + temp_router->device_x_position = list_of_routers[router_id-1].tile_centroid_x; + temp_router->device_y_position = list_of_routers[router_id-1].tile_centroid_y; + temp_router->id = router_id; + noc_info.router_list.push_back(*temp_router); + } + + // the top right logical router will be between the top right and top center physical routers in the mesh + temp_router->device_x_position = 4.8; + temp_router->device_y_position = 5.1; + temp_router->id = 9; + noc_info.router_list.push_back(*temp_router); + + // delete the router struct + delete temp_router; + + // call the router creation + REQUIRE_THROWS_WITH(create_noc_routers(noc_info, &noc_model, list_of_routers), "Routers with IDs:'9' and '5' are both closest to physical router tile located at (4,4) and the physical router could not be assigned multiple times."); + } + + + } + TEST_CASE("test_create_noc_links", "[vpr_setup_noc]"){ + + // datastructure to hold the list of physical tiles + std::vector list_of_routers; + + /* + Setup: + - The router will take over a 2x3 grid area + - The NoC will be a 3x3 Mesh topology and located at + the following positions: + - router 1: (0,0) + - router 2: (4,0) + - router 3: (8,0) + - router 4: (0,4) + - router 5: (4,4) + - router 6: (8,4) + - router 7: (0,8) + - router 8: (4,8) + - router 9: (8,8) + */ + list_of_routers.push_back({0,0,0.5,1}); + list_of_routers.push_back({4,0,4.5,1}); + list_of_routers.push_back({8,0,8.5,1}); + + list_of_routers.push_back({0,4,0.5,5}); + list_of_routers.push_back({4,4,4.5,5}); + list_of_routers.push_back({8,4,8.5,5}); + + list_of_routers.push_back({0,8,0.5,9}); + list_of_routers.push_back({4,8,4.5,9}); + list_of_routers.push_back({8,8,8.5,9}); + + // create the noc model (to store the routers) + NocStorage noc_model; + + // create the logical router list + t_noc_inf noc_info; + + // pointer to each logical router + t_router* temp_router = NULL; + + // start by creating all the logical routers + // this is similiar to the user provided a config file + temp_router = new t_router; + + for (int router_id = 1; router_id < 10; router_id++){ + + // we will have 9 logical routers that will take up all physical routers + temp_router->device_x_position = list_of_routers[router_id-1].tile_centroid_x; + temp_router->device_y_position = list_of_routers[router_id-1].tile_centroid_y; + temp_router->id = router_id; + noc_info.router_list.push_back(*temp_router); + + // add the router to the NoC + noc_model.add_router(router_id, list_of_routers[router_id-1].grid_width_position, list_of_routers[router_id-1].grid_height_position); + } + + delete temp_router; + + // need to add the links to the noc_info + // this will be a mesh structure + noc_info.router_list[0].connection_list.push_back(2); + noc_info.router_list[0].connection_list.push_back(4); + + noc_info.router_list[1].connection_list.push_back(1); + noc_info.router_list[1].connection_list.push_back(3); + noc_info.router_list[1].connection_list.push_back(5); + + noc_info.router_list[2].connection_list.push_back(2); + noc_info.router_list[2].connection_list.push_back(6); + + noc_info.router_list[3].connection_list.push_back(1); + noc_info.router_list[3].connection_list.push_back(5); + noc_info.router_list[3].connection_list.push_back(7); + + noc_info.router_list[4].connection_list.push_back(2); + noc_info.router_list[4].connection_list.push_back(4); + noc_info.router_list[4].connection_list.push_back(6); + noc_info.router_list[4].connection_list.push_back(8); + + noc_info.router_list[5].connection_list.push_back(3); + noc_info.router_list[5].connection_list.push_back(5); + noc_info.router_list[5].connection_list.push_back(9); + + noc_info.router_list[6].connection_list.push_back(4); + noc_info.router_list[6].connection_list.push_back(8); + + noc_info.router_list[7].connection_list.push_back(5); + noc_info.router_list[7].connection_list.push_back(7); + noc_info.router_list[7].connection_list.push_back(9); + + noc_info.router_list[8].connection_list.push_back(6); + noc_info.router_list[8].connection_list.push_back(8); + + // call the function to test + create_noc_links(&noc_info, &noc_model); + + NocRouterId current_source_router; + NocRouterId current_destination_router; + + std::vector::iterator router_connection; + + // now verify the created links + for(int router_id = 1; router_id < 10; router_id++) + { + current_source_router = noc_model.convert_router_id(router_id); + + router_connection = noc_info.router_list[router_id-1].connection_list.begin(); + + for (auto noc_link = noc_model.get_noc_router_connections(current_source_router).begin(); noc_link != noc_model.get_noc_router_connections(current_source_router).begin(); noc_link++) + { + current_destination_router = noc_model.get_noc_link_sink_router(*noc_link); + + REQUIRE((noc_model.get_noc_router_id(current_destination_router)) == (*router_connection)); + + router_connection++; + } + } + } + TEST_CASE("test_setup_noc", "[vpr_setup_noc]"){ + + // create the architecture object + t_arch arch; + + // create the logical router list + t_noc_inf noc_info; + + // pointer to each logical router + t_router* temp_router = NULL; + + // start by creating all the logical routers + // this is similiar to the user provided a config file + temp_router = new t_router; + + // datastructure to hold the list of physical tiles + std::vector list_of_routers; + + // get a mutable to the device context + auto& device_ctx = g_vpr_ctx.mutable_device(); + + // delete any previous device grid + device_ctx.grid.clear(); + + /* + Setup: + - The router will take over a 2x3 grid area + - The NoC will be a 3x3 Mesh topology and located at + the following positions: + - router 1: (0,0) + - router 2: (4,0) + - router 3: (8,0) + - router 4: (0,4) + - router 5: (4,4) + - router 6: (8,4) + - router 7: (0,8) + - router 8: (4,8) + - router 9: (8,8) + */ + list_of_routers.push_back({0,0,0.5,1}); + list_of_routers.push_back({4,0,4.5,1}); + list_of_routers.push_back({8,0,8.5,1}); + + list_of_routers.push_back({0,4,0.5,5}); + list_of_routers.push_back({4,4,4.5,5}); + list_of_routers.push_back({8,4,8.5,5}); + + list_of_routers.push_back({0,8,0.5,9}); + list_of_routers.push_back({4,8,4.5,9}); + list_of_routers.push_back({8,8,8.5,9}); + + for (int router_id = 1; router_id < 10; router_id++){ + + // we will have 9 logical routers that will take up all physical routers + temp_router->device_x_position = list_of_routers[router_id-1].tile_centroid_x; + temp_router->device_y_position = list_of_routers[router_id-1].tile_centroid_y; + temp_router->id = router_id; + noc_info.router_list.push_back(*temp_router); + + } + + delete temp_router; + + // need to add the links to the noc_info + // this will be a mesh structure + noc_info.router_list[0].connection_list.push_back(2); + noc_info.router_list[0].connection_list.push_back(4); + + noc_info.router_list[1].connection_list.push_back(1); + noc_info.router_list[1].connection_list.push_back(3); + noc_info.router_list[1].connection_list.push_back(5); + + noc_info.router_list[2].connection_list.push_back(2); + noc_info.router_list[2].connection_list.push_back(6); + + noc_info.router_list[3].connection_list.push_back(1); + noc_info.router_list[3].connection_list.push_back(5); + noc_info.router_list[3].connection_list.push_back(7); + + noc_info.router_list[4].connection_list.push_back(2); + noc_info.router_list[4].connection_list.push_back(4); + noc_info.router_list[4].connection_list.push_back(6); + noc_info.router_list[4].connection_list.push_back(8); + + noc_info.router_list[5].connection_list.push_back(3); + noc_info.router_list[5].connection_list.push_back(5); + noc_info.router_list[5].connection_list.push_back(9); + + noc_info.router_list[6].connection_list.push_back(4); + noc_info.router_list[6].connection_list.push_back(8); + + noc_info.router_list[7].connection_list.push_back(5); + noc_info.router_list[7].connection_list.push_back(7); + noc_info.router_list[7].connection_list.push_back(9); + + noc_info.router_list[8].connection_list.push_back(6); + noc_info.router_list[8].connection_list.push_back(8); + + //assign the noc_info to the arch + arch.noc = &noc_info; + + // the architecture file has been setup to include the noc topology and we set the parameters below + noc_info.link_bandwidth = 67.8; + noc_info.link_latency = 56.7; + noc_info.router_latency = 2.3; + + SECTION("Test setup_noc when the number of logical routers is more than the number of physical routers in the FPGA."){ + + // test device grid name + std::string device_grid_name = "test"; + + // creating a reference for the empty tile name and router name + char empty_tile_name[6] = "empty"; + char router_tile_name[7] = "router"; + + // device grid parameters + int test_grid_width = 10; + int test_grid_height = 10; + + // create the test device grid (10x10) + auto test_grid = vtr::Matrix({10, 10}); + + // create an empty physical tile and assign its parameters + t_physical_tile_type empty_tile; + empty_tile.name = empty_tile_name; + empty_tile.height = 1; + empty_tile.width = 1; + + // create a router tile and assign its parameters + // the router will take up 4 grid spaces and be named "router" + t_physical_tile_type router_tile; + router_tile.name = router_tile_name; + router_tile.height = 2; + router_tile.width = 2; + + // in this test, the routers will be on the 4 corners of the FPGA + + // bottom left corner + test_grid[0][0].type = &router_tile; + test_grid[0][0].height_offset = 0; + test_grid[0][0].width_offset = 0; + + test_grid[1][0].type = &router_tile; + test_grid[1][0].height_offset = 0; + test_grid[1][0].width_offset = 1; + + test_grid[0][1].type = &router_tile; + test_grid[0][1].height_offset = 1; + test_grid[0][1].width_offset = 0; + + test_grid[1][1].type = &router_tile; + test_grid[1][1].height_offset = 1; + test_grid[1][1].width_offset = 1; + + // bottom right corner + test_grid[8][0].type = &router_tile; + test_grid[8][0].height_offset = 0; + test_grid[8][0].width_offset = 0; + + test_grid[9][0].type = &router_tile; + test_grid[9][0].height_offset = 0; + test_grid[9][0].width_offset = 1; + + test_grid[8][1].type = &router_tile; + test_grid[8][1].height_offset = 1; + test_grid[8][1].width_offset = 0; + + test_grid[9][1].type = &router_tile; + test_grid[9][1].height_offset = 1; + test_grid[9][1].width_offset = 1; + + // top left corner + test_grid[0][8].type = &router_tile; + test_grid[0][8].height_offset = 0; + test_grid[0][8].width_offset = 0; + + test_grid[1][8].type = &router_tile; + test_grid[1][8].height_offset = 0; + test_grid[1][8].width_offset = 1; + + test_grid[0][9].type = &router_tile; + test_grid[0][9].height_offset = 1; + test_grid[0][9].width_offset = 0; + + test_grid[1][9].type = &router_tile; + test_grid[1][9].height_offset = 1; + test_grid[1][9].width_offset = 1; + + // top right corner + test_grid[8][8].type = &router_tile; + test_grid[8][8].height_offset = 0; + test_grid[8][8].width_offset = 0; + + test_grid[9][8].type = &router_tile; + test_grid[9][8].height_offset = 0; + test_grid[9][8].width_offset = 1; + + test_grid[8][9].type = &router_tile; + test_grid[8][9].height_offset = 1; + test_grid[8][9].width_offset = 0; + + test_grid[9][9].type = &router_tile; + test_grid[9][9].height_offset = 1; + test_grid[9][9].width_offset = 1; + + for(int i = 0; i < test_grid_width; i++) + { + for(int j = 0; j < test_grid_height; j++) + { + // make sure the current tyle is not a router + if (test_grid[i][j].type == nullptr) + { + // assign the non-router tile as empty + test_grid[i][j].type = &empty_tile; + test_grid[i][j].width_offset = 0; + test_grid[i][j].height_offset = 0; + } + } + } + + device_ctx.grid = DeviceGrid(device_grid_name, test_grid); + + REQUIRE_THROWS_WITH(setup_noc(arch, router_tile_name), "The Provided NoC topology information in the architecture file has more number of routers than what is available in the FPGA device."); + + } + SECTION("Test setup_noc when there are no physical NoC routers on the FPGA."){ + + // test device grid name + std::string device_grid_name = "test"; + + // creating a reference for the empty tile name and router name + char empty_tile_name[6] = "empty"; + char router_tile_name[7] = "router"; + + // device grid parameters + int test_grid_width = 10; + int test_grid_height = 10; + + // create the test device grid (10x10) + auto test_grid = vtr::Matrix({10, 10}); + + // create an empty physical tile and assign its parameters + t_physical_tile_type empty_tile; + empty_tile.name = empty_tile_name; + empty_tile.height = 1; + empty_tile.width = 1; + + // create a router tile and assign its parameters + // the router will take up 4 grid spaces and be named "router" + t_physical_tile_type router_tile; + router_tile.name = router_tile_name; + router_tile.height = 2; + router_tile.width = 2; + + // in this test, there should be no physical router tiles ih the FPGA device and there should be no routers in the topology description + + for(int i = 0; i < test_grid_width; i++) + { + for(int j = 0; j < test_grid_height; j++) + { + // make sure the current tyle is not a router + if (test_grid[i][j].type == nullptr) + { + // assign the non-router tile as empty + test_grid[i][j].type = &empty_tile; + test_grid[i][j].width_offset = 0; + test_grid[i][j].height_offset = 0; + } + } + } + + noc_info.router_list.clear(); + + device_ctx.grid = DeviceGrid(device_grid_name, test_grid); + + REQUIRE_THROWS_WITH(setup_noc(arch, router_tile_name), "No physical NoC routers were found on the FPGA device. Either the provided name for the physical router tile was incorrect or the FPGA device has no routers."); + + } + } } \ No newline at end of file From 7786b8f13982ed8f787d16d0742c8cf5489bd7b4 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 16 Mar 2022 19:52:06 -0400 Subject: [PATCH 040/128] improved error messages in setup_noc() and also fixed a few bugs --- vpr/src/base/setup_noc.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vpr/src/base/setup_noc.cpp b/vpr/src/base/setup_noc.cpp index 61e08bfe250..4b2264cb185 100644 --- a/vpr/src/base/setup_noc.cpp +++ b/vpr/src/base/setup_noc.cpp @@ -24,17 +24,17 @@ void setup_noc(const t_arch& arch, std::string noc_router_tile_name) identify_and_store_noc_router_tile_positions(device_ctx.grid,list_of_noc_router_tiles, noc_router_tile_name); // check whether the noc topology information provided uses more than the number of available routers in the FPGA - if (list_of_noc_router_tiles.size() > arch.noc->router_list.size()) + if (list_of_noc_router_tiles.size() < arch.noc->router_list.size()) { - VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Provided NoC topology information in the architecture file has more routers that what is available in the FPGA."); + VPR_FATAL_ERROR(VPR_ERROR_OTHER, "The Provided NoC topology information in the architecture file has more number of routers than what is available in the FPGA device."); } - else if (list_of_noc_router_tiles.size() < arch.noc->router_list.size()) // check whether the noc topology information provided is using all the routers in the FPGA + else if (list_of_noc_router_tiles.size() > arch.noc->router_list.size()) // check whether the noc topology information provided is using all the routers in the FPGA { - VTR_LOG_WARN("Provided NoC topology information in the architecture file has more routers that what is available in the FPGA."); + VTR_LOG_WARN("The Provided NoC topology information in the architecture file has less number of routers than what is available in the FPGA device."); } else if (list_of_noc_router_tiles.size() == 0) // case where no physical router tiles were found { - VPR_FATAL_ERROR(VPR_ERROR_OTHER, "No physical routers were found on the FPGA device. Either the provided name for the physical router tile was incorrect or the FPGA device has no routers."); + VPR_FATAL_ERROR(VPR_ERROR_OTHER, "No physical NoC routers were found on the FPGA device. Either the provided name for the physical router tile was incorrect or the FPGA device has no routers."); } // generate noc model From 1b291e83caf1b3aa866ec0afd1bf848c2de51e7b Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 18 Mar 2022 13:37:23 -0400 Subject: [PATCH 041/128] added new command line options for the NoC --- vpr/src/base/read_options.cpp | 17 +++++++++++++++++ vpr/src/base/read_options.h | 4 ++++ 2 files changed, 21 insertions(+) diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index 074e84a2e8c..21337696bf2 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -2611,6 +2611,23 @@ argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& arg .help("Signal activities file for all nets (see documentation).") .show_in(argparse::ShowIn::HELP_ONLY); + auto& noc_grp = parser.add_argument_group("noc options"); + + noc_grp.add_argument(args.include_noc, "--include_noc") + .help( + "Enables a NoC-driven placer that optimizes the placement of routers on the NoC." + "Also enables an option in the graphical display that can be used to display the NoC on the FPGA." + "This should be on only when the FPGA device contains a NoC and the provided netlist connects to the NoC.") + .default_value("off") + .show_in(argparse::ShowIn::HELP_ONLY); + + noc_grp.add_argument(args.noc_router_tile_name, "--noc_router_tile_name") + .help( + "The name used when describing the NoC router tiles in the FPGA architecture description." + "This needs to be provided if --include_noc is used.") + .default_value("") + .show_in(argparse::ShowIn::HELP_ONLY); + return parser; } diff --git a/vpr/src/base/read_options.h b/vpr/src/base/read_options.h index d2edecc27ac..18a3cdb2910 100644 --- a/vpr/src/base/read_options.h +++ b/vpr/src/base/read_options.h @@ -137,6 +137,10 @@ struct t_options { argparse::ArgValue place_constraint_subtile; argparse::ArgValue floorplan_num_horizontal_partitions; argparse::ArgValue floorplan_num_vertical_partitions; + + // NoC-driven placement + argparse::ArgValue include_noc; + argparse::ArgValue noc_router_tile_name; /* Timing-driven placement options only */ argparse::ArgValue PlaceTimingTradeoff; From fcb9bfb1e81803d02e6fd6c19e63e92095ac4c85 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 18 Mar 2022 13:44:30 -0400 Subject: [PATCH 042/128] added a new set of options for the NoC in vpr setup --- vpr/src/base/vpr_types.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index e80118eafb9..654c36dea95 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -1269,6 +1269,11 @@ struct t_analysis_opts { e_timing_update_type timing_update_type; }; +struct t_noc_opts { + bool include_noc; ///* PackerRRGraph; std::vector Segments; /// Date: Tue, 22 Mar 2022 23:17:10 -0400 Subject: [PATCH 043/128] added another attribute of the noc, which is the name used to describe router tiles. Then updated setup_noc to use the new value. --- libs/libarchfpga/src/physical_types.h | 2 ++ libs/libarchfpga/src/read_xml_arch_file.cpp | 14 +++++++++++++- vpr/src/base/setup_noc.cpp | 4 ++-- vpr/src/base/setup_noc.h | 2 +- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index e064f7a76a3..a592cb744b3 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -1793,6 +1793,8 @@ struct t_noc_inf { int router_latency; // in nanoseconds std::vector router_list; + + std::string noc_router_tile_name; }; /* Detailed routing architecture */ diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index 0b185b753b2..38660516429 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -4543,7 +4543,7 @@ static void ProcessClocks(pugi::xml_node Parent, t_clock_arch* clocks, const pug static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc_data& loc_data) { // a vector representing all the possible attributes within the noc tag - std::vector expected_noc_attributes = {"link_bandwidth", "link_latency", "router_latency"}; + std::vector expected_noc_attributes = {"link_bandwidth", "link_latency", "router_latency", "noc_router_tile_name"}; std::vector expected_noc_children_tags = {"mesh","topology"}; @@ -4553,6 +4553,9 @@ static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc // identifier that lets us know when we could not properly convert an attribute value to a integer int attribute_conversion_failure = -1; + // identifier that lets us know when we could not properly convert a string conversion value + std::string attribute_conversion_failure_string = ""; + // if we are here, then the user has a NoC in their architecture, so need to add it arch->noc = new t_noc_inf; t_noc_inf* noc_ref = arch->noc; @@ -4569,6 +4572,8 @@ static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc noc_ref->router_latency = pugiutil::get_attribute(noc_tag, "router_latency", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); + noc_ref->noc_router_tile_name = pugiutil::get_attribute(noc_tag, "noc_router_tile_name", loc_data, pugiutil::REQUIRED).as_string(); + // the noc parameters can only be non-zero positive values if ((noc_ref->link_bandwidth < 0) || (noc_ref->link_latency < 0) || (noc_ref->router_latency < 0)) { @@ -4576,6 +4581,13 @@ static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc "The link bandwidth, link latency and router latency for the NoC must be a positive non-zero integer."); } + // check that the router tile name was supplied properly + if (!(noc_ref->noc_router_tile_name.compare(attribute_conversion_failure_string))) + { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(noc_tag), + "The noc router tile name must be a string."); + } + /* We processed the NoC node, so now process the topology*/ // make sure that only the topology tag is found under NoC diff --git a/vpr/src/base/setup_noc.cpp b/vpr/src/base/setup_noc.cpp index 4b2264cb185..bf9415c9e38 100644 --- a/vpr/src/base/setup_noc.cpp +++ b/vpr/src/base/setup_noc.cpp @@ -9,7 +9,7 @@ #include "vtr_math.h" -void setup_noc(const t_arch& arch, std::string noc_router_tile_name) +void setup_noc(const t_arch& arch) { // variable to store all the noc router tiles within the FPGA device @@ -21,7 +21,7 @@ void setup_noc(const t_arch& arch, std::string noc_router_tile_name) // go through the FPGA grid and find the noc router tiles // then store the position - identify_and_store_noc_router_tile_positions(device_ctx.grid,list_of_noc_router_tiles, noc_router_tile_name); + identify_and_store_noc_router_tile_positions(device_ctx.grid,list_of_noc_router_tiles, arch.noc->noc_router_tile_name); // check whether the noc topology information provided uses more than the number of available routers in the FPGA if (list_of_noc_router_tiles.size() < arch.noc->router_list.size()) diff --git a/vpr/src/base/setup_noc.h b/vpr/src/base/setup_noc.h index 5ab554dcd9f..a01684b2c5f 100644 --- a/vpr/src/base/setup_noc.h +++ b/vpr/src/base/setup_noc.h @@ -29,7 +29,7 @@ struct t_noc_router_tile_position { }; -void setup_noc(const t_arch& arch, std::string noc_router_tile_name); +void setup_noc(const t_arch& arch); void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, std::vector& list_of_noc_router_tiles, std::string noc_router_tile_name); From df6651c354c4b350af42ce9e3ef7c8930d96a7c3 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 22 Mar 2022 23:22:04 -0400 Subject: [PATCH 044/128] updated the command line parser to include a new set of options for the NoC. Also added logic so that the noc setup is only run when the user turns on the noc option in the command line --- vpr/src/base/SetupVPR.cpp | 12 ++++++++++++ vpr/src/base/SetupVPR.h | 1 + vpr/src/base/read_options.cpp | 9 +-------- vpr/src/base/read_options.h | 2 +- vpr/src/base/vpr_api.cpp | 9 +++++++-- vpr/src/base/vpr_api.h | 1 + vpr/src/base/vpr_types.h | 2 +- 7 files changed, 24 insertions(+), 12 deletions(-) diff --git a/vpr/src/base/SetupVPR.cpp b/vpr/src/base/SetupVPR.cpp index f75745facae..cccc195f754 100644 --- a/vpr/src/base/SetupVPR.cpp +++ b/vpr/src/base/SetupVPR.cpp @@ -35,6 +35,8 @@ static void SetupPlacerOpts(const t_options& Options, static void SetupAnnealSched(const t_options& Options, t_annealing_sched* AnnealSched); static void SetupRouterOpts(const t_options& Options, t_router_opts* RouterOpts); +static void SetupNocOpts(const t_options& Options, + t_noc_opts* NocOpts); static void SetupRoutingArch(const t_arch& Arch, t_det_routing_arch* RoutingArch); static void SetupTiming(const t_options& Options, const bool TimingEnabled, t_timing_inf* Timing); static void SetupSwitches(const t_arch& Arch, @@ -64,6 +66,7 @@ void SetupVPR(const t_options* Options, t_annealing_sched* AnnealSched, t_router_opts* RouterOpts, t_analysis_opts* AnalysisOpts, + t_noc_opts* NocOpts, t_det_routing_arch* RoutingArch, std::vector** PackerRRGraphs, std::vector& Segments, @@ -108,6 +111,7 @@ void SetupVPR(const t_options* Options, SetupRouterOpts(*Options, RouterOpts); SetupAnalysisOpts(*Options, *AnalysisOpts); SetupPowerOpts(*Options, PowerOpts, Arch); + SetupNocOpts(*Options, NocOpts); if (readArchFile == true) { vtr::ScopedStartFinishTimer t("Loading Architecture Description"); @@ -655,6 +659,14 @@ static void SetupPowerOpts(const t_options& Options, t_power_opts* power_opts, t } } +static void SetupNocOpts(const t_options& Options, t_noc_opts* NocOpts) { + + // assign the noc specific options from the command line + NocOpts->noc = Options.noc; + + return; +} + static int find_ipin_cblock_switch_index(const t_arch& Arch) { int ipin_cblock_switch_index = UNDEFINED; for (int i = 0; i < Arch.num_switches; ++i) { diff --git a/vpr/src/base/SetupVPR.h b/vpr/src/base/SetupVPR.h index 941fa568015..7f7bb7105ea 100644 --- a/vpr/src/base/SetupVPR.h +++ b/vpr/src/base/SetupVPR.h @@ -19,6 +19,7 @@ void SetupVPR(const t_options* Options, t_annealing_sched* AnnealSched, t_router_opts* RouterOpts, t_analysis_opts* AnalysisOpts, + t_noc_opts* NocOpts, t_det_routing_arch* RoutingArch, std::vector** PackerRRGraphs, std::vector& Segments, diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index 21337696bf2..2552ce0b3e4 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -2613,7 +2613,7 @@ argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& arg auto& noc_grp = parser.add_argument_group("noc options"); - noc_grp.add_argument(args.include_noc, "--include_noc") + noc_grp.add_argument(args.noc, "--noc") .help( "Enables a NoC-driven placer that optimizes the placement of routers on the NoC." "Also enables an option in the graphical display that can be used to display the NoC on the FPGA." @@ -2621,13 +2621,6 @@ argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& arg .default_value("off") .show_in(argparse::ShowIn::HELP_ONLY); - noc_grp.add_argument(args.noc_router_tile_name, "--noc_router_tile_name") - .help( - "The name used when describing the NoC router tiles in the FPGA architecture description." - "This needs to be provided if --include_noc is used.") - .default_value("") - .show_in(argparse::ShowIn::HELP_ONLY); - return parser; } diff --git a/vpr/src/base/read_options.h b/vpr/src/base/read_options.h index 18a3cdb2910..7e40cbbf424 100644 --- a/vpr/src/base/read_options.h +++ b/vpr/src/base/read_options.h @@ -139,7 +139,7 @@ struct t_options { argparse::ArgValue floorplan_num_vertical_partitions; // NoC-driven placement - argparse::ArgValue include_noc; + argparse::ArgValue noc; argparse::ArgValue noc_router_tile_name; /* Timing-driven placement options only */ diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index 49547b87847..486fc532e20 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -289,6 +289,7 @@ void vpr_init_with_options(const t_options* options, t_vpr_setup* vpr_setup, t_a &vpr_setup->AnnealSched, &vpr_setup->RouterOpts, &vpr_setup->AnalysisOpts, + &vpr_setup->NocOpts, &vpr_setup->RoutingArch, &vpr_setup->PackerRRGraph, vpr_setup->Segments, @@ -394,6 +395,8 @@ void vpr_create_device(t_vpr_setup& vpr_setup, const t_arch& arch) { vpr_setup_clock_networks(vpr_setup, arch); + vpr_setup_noc(vpr_setup, arch); + if (vpr_setup.PlacerOpts.place_chan_width != NO_FIXED_CHANNEL_WIDTH) { vpr_create_rr_graph(vpr_setup, arch, vpr_setup.PlacerOpts.place_chan_width); } @@ -491,9 +494,9 @@ void vpr_setup_clock_networks(t_vpr_setup& vpr_setup, const t_arch& Arch) { void vpr_setup_noc(const t_vpr_setup& vpr_setup, const t_arch& arch) { // check if the user provided the option to model the noc - if (vpr_setup.include_noc == true) + if (vpr_setup.NocOpts.noc == true) { - setup_noc(arch, vpr_setup.noc_router_tile_name); + setup_noc(arch); } } @@ -1140,6 +1143,7 @@ void vpr_setup_vpr(t_options* Options, t_annealing_sched* AnnealSched, t_router_opts* RouterOpts, t_analysis_opts* AnalysisOpts, + t_noc_opts* NocOpts, t_det_routing_arch* RoutingArch, std::vector** PackerRRGraph, std::vector& Segments, @@ -1163,6 +1167,7 @@ void vpr_setup_vpr(t_options* Options, AnnealSched, RouterOpts, AnalysisOpts, + NocOpts, RoutingArch, PackerRRGraph, Segments, diff --git a/vpr/src/base/vpr_api.h b/vpr/src/base/vpr_api.h index 102058bbec0..8d11d136331 100644 --- a/vpr/src/base/vpr_api.h +++ b/vpr/src/base/vpr_api.h @@ -157,6 +157,7 @@ void vpr_setup_vpr(t_options* Options, t_annealing_sched* AnnealSched, t_router_opts* RouterOpts, t_analysis_opts* AnalysisOpts, + t_noc_opts* NocOpts, t_det_routing_arch* RoutingArch, std::vector** PackerRRGraph, std::vector& Segments, diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index 654c36dea95..0036da66ed6 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -1270,7 +1270,7 @@ struct t_analysis_opts { }; struct t_noc_opts { - bool include_noc; /// Date: Tue, 22 Mar 2022 23:46:57 -0400 Subject: [PATCH 045/128] ensured that all the helper functions in setup noc are limited to be used in setup_noc.cpp --- vpr/src/base/setup_noc.cpp | 14 +++++++++++--- vpr/src/base/setup_noc.h | 15 --------------- 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/vpr/src/base/setup_noc.cpp b/vpr/src/base/setup_noc.cpp index bf9415c9e38..7832860c67e 100644 --- a/vpr/src/base/setup_noc.cpp +++ b/vpr/src/base/setup_noc.cpp @@ -8,6 +8,14 @@ #include "vpr_error.h" #include "vtr_math.h" +static void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, std::vector& list_of_noc_router_tiles, std::string noc_router_tile_name); + +static void generate_noc(const t_arch& arch, NocContext& noc_ctx, std::vector& list_of_noc_router_tiles); + +static void create_noc_routers(const t_noc_inf& noc_info, NocStorage* noc_model, std::vector& list_of_noc_router_tiles); + +static void create_noc_links(const t_noc_inf* noc_info, NocStorage* noc_model); + void setup_noc(const t_arch& arch) { @@ -49,7 +57,7 @@ void setup_noc(const t_arch& arch) } -void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, std::vector& list_of_noc_router_tiles, std::string noc_router_tile_name) +static void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, std::vector& list_of_noc_router_tiles, std::string noc_router_tile_name) { int grid_width = device_grid.width(); int grid_height = device_grid.height(); @@ -129,7 +137,7 @@ void generate_noc(const t_arch& arch, NocContext& noc_ctx, std::vector& list_of_noc_router_tiles) +static void create_noc_routers(const t_noc_inf& noc_info, NocStorage* noc_model , std::vector& list_of_noc_router_tiles) { // keep track of the shortest distance between a logical router and the curren physical router tile // also keep track of the corresponding physical router tile index (within the list) @@ -241,7 +249,7 @@ void create_noc_routers(const t_noc_inf& noc_info, NocStorage* noc_model , std:: return; } -void create_noc_links(const t_noc_inf* noc_info, NocStorage* noc_model){ +static void create_noc_links(const t_noc_inf* noc_info, NocStorage* noc_model){ // the ids used to represent the routers in the NoC are not the same as the ones provided by the user in the arch desc file. // while going through the router connections, the user provided router ids are converted and then stored below before being used // in the links. diff --git a/vpr/src/base/setup_noc.h b/vpr/src/base/setup_noc.h index a01684b2c5f..bce77b64267 100644 --- a/vpr/src/base/setup_noc.h +++ b/vpr/src/base/setup_noc.h @@ -31,20 +31,5 @@ struct t_noc_router_tile_position { void setup_noc(const t_arch& arch); -void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, std::vector& list_of_noc_router_tiles, std::string noc_router_tile_name); - -void generate_noc(const t_arch& arch, NocContext& noc_ctx, std::vector& list_of_noc_router_tiles); - -void create_noc_routers(const t_noc_inf& noc_info, NocStorage* noc_model, std::vector& list_of_noc_router_tiles); - -void create_noc_links(const t_noc_inf* noc_info, NocStorage* noc_model); - - - - - - - - #endif \ No newline at end of file From 8f226c36d30ee8d32f53044f8a5b64d76ce6ebea Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 23 Mar 2022 20:32:00 -0400 Subject: [PATCH 046/128] added an echo file for the NoC and a function that dumps the contents of the NoC model datastructure --- vpr/src/base/echo_files.cpp | 3 ++ vpr/src/base/echo_files.h | 3 ++ vpr/src/base/setup_noc.cpp | 66 +++++++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+) diff --git a/vpr/src/base/echo_files.cpp b/vpr/src/base/echo_files.cpp index 49f2d42579e..7f898551592 100644 --- a/vpr/src/base/echo_files.cpp +++ b/vpr/src/base/echo_files.cpp @@ -123,6 +123,9 @@ void alloc_and_load_echo_file_info() { setEchoFileName(E_ECHO_LOOKAHEAD_MAP, "lookahead_map.echo"); setEchoFileName(E_ECHO_RR_GRAPH_INDEXED_DATA, "rr_indexed_data.echo"); setEchoFileName(E_ECHO_COMPRESSED_GRIDS, "compressed_grids.echo"); + + //NoC + setEchoFileName(E_ECHO_NOC_MODEL, "noc_model.echo"); } void free_echo_file_info() { diff --git a/vpr/src/base/echo_files.h b/vpr/src/base/echo_files.h index 86fbb60e4fa..ffe3c6fe5a5 100644 --- a/vpr/src/base/echo_files.h +++ b/vpr/src/base/echo_files.h @@ -61,6 +61,9 @@ enum e_echo_files { E_ECHO_FINAL_ROUTING_TIMING_GRAPH, E_ECHO_ANALYSIS_TIMING_GRAPH, + //NoC + E_ECHO_NOC_MODEL, + E_ECHO_END_TOKEN }; diff --git a/vpr/src/base/setup_noc.cpp b/vpr/src/base/setup_noc.cpp index 7832860c67e..3f030095e93 100644 --- a/vpr/src/base/setup_noc.cpp +++ b/vpr/src/base/setup_noc.cpp @@ -7,6 +7,7 @@ #include "vtr_assert.h" #include "vpr_error.h" #include "vtr_math.h" +#include "echo_files.h" static void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, std::vector& list_of_noc_router_tiles, std::string noc_router_tile_name); @@ -16,6 +17,8 @@ static void create_noc_routers(const t_noc_inf& noc_info, NocStorage* noc_model, static void create_noc_links(const t_noc_inf* noc_info, NocStorage* noc_model); +static void echo_noc(char* file_name); + void setup_noc(const t_arch& arch) { @@ -53,6 +56,14 @@ void setup_noc(const t_arch& arch) noc_ctx.noc_link_latency = arch.noc->link_latency; noc_ctx.noc_router_latency = arch.noc->router_latency; + // echo the noc info + if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_NOC_MODEL)) + { + echo_noc(getEchoFileName(E_ECHO_NOC_MODEL)); + } + + exit(1); + return; } @@ -283,4 +294,59 @@ static void create_noc_links(const t_noc_inf* noc_info, NocStorage* noc_model){ } +static void echo_noc(char* file_name) +{ + FILE* fp; + fp = vtr::fopen(file_name, "w"); + + fprintf(fp, "--------------------------------------------------------------\n"); + fprintf(fp, "NoC\n"); + fprintf(fp, "--------------------------------------------------------------\n"); + fprintf(fp, "\n"); + + auto& noc_ctx = g_vpr_ctx.noc(); + + // print the overall constraints of the NoC + fprintf(fp, "NoC Constraints:\n"); + fprintf(fp, "--------------------------------------------------------------\n"); + fprintf(fp, "\n"); + fprintf(fp, "Maximum NoC Link Bandwidth: %d\n", noc_ctx.noc_link_bandwidth); + fprintf(fp, "\n"); + fprintf(fp, "NoC Link Latency: %d\n", noc_ctx.noc_link_latency); + fprintf(fp, "\n"); + fprintf(fp, "NoC Router Latency: %d\n", noc_ctx.noc_router_latency); + fprintf(fp, "\n"); + + // print all the routers and their properties + fprintf(fp, "NoC Router List:\n"); + fprintf(fp, "--------------------------------------------------------------\n"); + fprintf(fp, "\n"); + + auto& noc_routers = noc_ctx.noc_model.get_noc_routers(); + + // go through each router and print its information + for (auto router = noc_routers.begin(); router != noc_routers.end(); router++) + { + fprintf(fp,"Router %d:\n", router->get_router_id()); + // if the router tile is larger than a single grid, the position represents the bottom left corner of the tile + fprintf(fp,"Equivalent Physical Tile Grid Position -> (%d,%d)\n", router->get_router_grid_position_x(), router->get_router_grid_position_y()); + fprintf(fp, "Router Connections ->"); + + auto& router_connections = noc_ctx.noc_model.get_noc_router_connections(noc_ctx.noc_model.convert_router_id(router->get_router_id())); + + // go through the links of the current router and add the connecting router to the list + for (auto router_link = router_connections.begin(); router_link != router_connections.end(); router_link++) + { + fprintf(fp, " %d", noc_ctx.noc_model.get_noc_router_id(noc_ctx.noc_model.get_noc_link_sink_router(*router_link))); + } + + fprintf(fp, "\n\n"); + } + + fclose(fp); + + return; + +} + From 6321cc5752728a4ebc18ec312a8a0ac0291d7d73 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 23 Mar 2022 20:43:38 -0400 Subject: [PATCH 047/128] Changed the precision of the noc constraints (noc link bandwidth, link latency, etc..) from integer to double --- libs/libarchfpga/src/physical_types.h | 6 +++--- libs/libarchfpga/src/read_xml_arch_file.cpp | 8 ++++---- vpr/src/base/setup_noc.cpp | 6 +++--- vpr/src/base/vpr_context.h | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index a592cb744b3..d10a3daf9a8 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -1788,9 +1788,9 @@ struct t_router { /* Network-on-chip(NoC) data type used to store the network properties and used when builidng a dedicated on-chip network*/ struct t_noc_inf { - int link_bandwidth; // in Gbps - int link_latency; // in nanoseconds - int router_latency; // in nanoseconds + double link_bandwidth; // in Gbps + double link_latency; // in nanoseconds + double router_latency; // in nanoseconds std::vector router_list; diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index 38660516429..fe7db1c9827 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -4566,11 +4566,11 @@ static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc pugiutil::expect_only_attributes(noc_tag, expected_noc_attributes, loc_data); // now go through and parse the required attributes for noc tag - noc_ref->link_bandwidth = pugiutil::get_attribute(noc_tag, "link_bandwidth", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); + noc_ref->link_bandwidth = pugiutil::get_attribute(noc_tag, "link_bandwidth", loc_data, pugiutil::REQUIRED).as_double(attribute_conversion_failure); - noc_ref->link_latency = pugiutil::get_attribute(noc_tag, "link_latency", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); + noc_ref->link_latency = pugiutil::get_attribute(noc_tag, "link_latency", loc_data, pugiutil::REQUIRED).as_double(attribute_conversion_failure); - noc_ref->router_latency = pugiutil::get_attribute(noc_tag, "router_latency", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); + noc_ref->router_latency = pugiutil::get_attribute(noc_tag, "router_latency", loc_data, pugiutil::REQUIRED).as_double(attribute_conversion_failure); noc_ref->noc_router_tile_name = pugiutil::get_attribute(noc_tag, "noc_router_tile_name", loc_data, pugiutil::REQUIRED).as_string(); @@ -4578,7 +4578,7 @@ static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc if ((noc_ref->link_bandwidth < 0) || (noc_ref->link_latency < 0) || (noc_ref->router_latency < 0)) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(noc_tag), - "The link bandwidth, link latency and router latency for the NoC must be a positive non-zero integer."); + "The link bandwidth, link latency and router latency for the NoC must be a positive non-zero value."); } // check that the router tile name was supplied properly diff --git a/vpr/src/base/setup_noc.cpp b/vpr/src/base/setup_noc.cpp index 3f030095e93..76a6e1ff146 100644 --- a/vpr/src/base/setup_noc.cpp +++ b/vpr/src/base/setup_noc.cpp @@ -310,11 +310,11 @@ static void echo_noc(char* file_name) fprintf(fp, "NoC Constraints:\n"); fprintf(fp, "--------------------------------------------------------------\n"); fprintf(fp, "\n"); - fprintf(fp, "Maximum NoC Link Bandwidth: %d\n", noc_ctx.noc_link_bandwidth); + fprintf(fp, "Maximum NoC Link Bandwidth: %f\n", noc_ctx.noc_link_bandwidth); fprintf(fp, "\n"); - fprintf(fp, "NoC Link Latency: %d\n", noc_ctx.noc_link_latency); + fprintf(fp, "NoC Link Latency: %f\n", noc_ctx.noc_link_latency); fprintf(fp, "\n"); - fprintf(fp, "NoC Router Latency: %d\n", noc_ctx.noc_router_latency); + fprintf(fp, "NoC Router Latency: %f\n", noc_ctx.noc_router_latency); fprintf(fp, "\n"); // print all the routers and their properties diff --git a/vpr/src/base/vpr_context.h b/vpr/src/base/vpr_context.h index d8f1247a00c..b456bccaa9a 100644 --- a/vpr/src/base/vpr_context.h +++ b/vpr/src/base/vpr_context.h @@ -405,17 +405,17 @@ struct NocContext : public Context { /** * @brief Represents the maximum allowed bandwidth for the links in the NoC (in Gbps) */ - int noc_link_bandwidth; + double noc_link_bandwidth; /** * @brief Represents the delay expected when going through a link */ - int noc_link_latency; + double noc_link_latency; /** * @brief Represents the expected delay when going through a router */ - int noc_router_latency; + double noc_router_latency; }; /** From 2e461f1f2f99725e3b2b5532b5ac617f8c804a53 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 23 Mar 2022 22:38:21 -0400 Subject: [PATCH 048/128] added a function to log the options used when the NoC is enabled --- vpr/src/base/ShowSetup.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/vpr/src/base/ShowSetup.cpp b/vpr/src/base/ShowSetup.cpp index 782038c4a31..cc49576f2f3 100644 --- a/vpr/src/base/ShowSetup.cpp +++ b/vpr/src/base/ShowSetup.cpp @@ -20,6 +20,7 @@ static void ShowPlacerOpts(const t_placer_opts& PlacerOpts, const t_annealing_sched& AnnealSched); static void ShowRouterOpts(const t_router_opts& RouterOpts); static void ShowAnalysisOpts(const t_analysis_opts& AnalysisOpts); +static void ShowNocOpts(const t_noc_opts& NocOpts); static void ShowAnnealSched(const t_annealing_sched& AnnealSched); @@ -61,6 +62,9 @@ void ShowSetup(const t_vpr_setup& vpr_setup) { if (vpr_setup.AnalysisOpts.doAnalysis) { ShowAnalysisOpts(vpr_setup.AnalysisOpts); } + if (vpr_setup.NocOpts.noc) { + ShowNocOpts(vpr_setup.NocOpts); + } } void ClusteredNetlistStats::writeHuman(std::ostream& output) const { @@ -764,3 +768,11 @@ static void ShowPackerOpts(const t_packer_opts& PackerOpts) { VTR_LOG("\n"); VTR_LOG("\n"); } + +static void ShowNocOpts(const t_noc_opts& NocOpts) +{ + // show options such as routing algorithm used + // name of the flows file + // etc... + return; +} From b9d3f67b6f2ec399bdb03c823ade83f353a0e9ff Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 28 Mar 2022 23:36:00 -0400 Subject: [PATCH 049/128] added a check to make sure that we dont read a nullptr when a noc topology isnt provided in the arch file. Also, now an error is thrown when the topology information doesnt use all the routers in the FPGA --- vpr/src/base/setup_noc.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/vpr/src/base/setup_noc.cpp b/vpr/src/base/setup_noc.cpp index 76a6e1ff146..69f155511e5 100644 --- a/vpr/src/base/setup_noc.cpp +++ b/vpr/src/base/setup_noc.cpp @@ -30,6 +30,13 @@ void setup_noc(const t_arch& arch) auto& device_ctx = g_vpr_ctx.device(); auto& noc_ctx = g_vpr_ctx.mutable_noc(); + // quick error check that the noc attribute of the arch is not empty + // basically, no noc topology information was provided by the user in the arch file + if (arch.noc == nullptr) + { + VPR_FATAL_ERROR(VPR_ERROR_OTHER, "No NoC topology information was provided in the architecture file."); + } + // go through the FPGA grid and find the noc router tiles // then store the position identify_and_store_noc_router_tile_positions(device_ctx.grid,list_of_noc_router_tiles, arch.noc->noc_router_tile_name); @@ -41,7 +48,7 @@ void setup_noc(const t_arch& arch) } else if (list_of_noc_router_tiles.size() > arch.noc->router_list.size()) // check whether the noc topology information provided is using all the routers in the FPGA { - VTR_LOG_WARN("The Provided NoC topology information in the architecture file has less number of routers than what is available in the FPGA device."); + VPR_FATAL_ERROR(VPR_ERROR_OTHER,"The Provided NoC topology information in the architecture file uses less number of routers than what is available in the FPGA device."); } else if (list_of_noc_router_tiles.size() == 0) // case where no physical router tiles were found { @@ -62,8 +69,6 @@ void setup_noc(const t_arch& arch) echo_noc(getEchoFileName(E_ECHO_NOC_MODEL)); } - exit(1); - return; } From 066e57a0bc087f71539429c96366bb9173f3d522 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 28 Mar 2022 23:49:09 -0400 Subject: [PATCH 050/128] the display_noc radio button only appears when the user supplied the --noc on option in the command line. --- vpr/src/base/vpr_api.cpp | 7 +++++++ vpr/src/draw/buttons.cpp | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index 486fc532e20..26776c9dd67 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -493,10 +493,17 @@ void vpr_setup_clock_networks(t_vpr_setup& vpr_setup, const t_arch& Arch) { void vpr_setup_noc(const t_vpr_setup& vpr_setup, const t_arch& arch) { + t_draw_state* draw_state = get_draw_state_vars(); + // check if the user provided the option to model the noc if (vpr_setup.NocOpts.noc == true) { setup_noc(arch); + + // setup the graphics + // if the user turned on "noc" in the command line, then we also want them to have the option to display the noc, so set that option here to be able to display it. + // if the "noc" was not turned on, then we don't need to provide the user with the option to display it + draw_state->show_noc_button = true; } } diff --git a/vpr/src/draw/buttons.cpp b/vpr/src/draw/buttons.cpp index ea3488e039b..82c9215f553 100644 --- a/vpr/src/draw/buttons.cpp +++ b/vpr/src/draw/buttons.cpp @@ -245,6 +245,16 @@ void button_for_toggle_crit_path() { } void button_for_displaying_noc() { + + t_draw_state* draw_state = get_draw_state_vars(); + + // if the user did not turn on the "noc" option then we don't give the option to display the noc to the user + if (!draw_state->show_noc_button) + { + return; + } + + // if we are here then the user turned the "noc" option on, so create a radio button to allow the user to display the noc GObject* main_window = application.get_object(application.get_main_window_id().c_str()); GObject* main_window_grid = application.get_object("InnerGrid"); @@ -259,6 +269,7 @@ void button_for_displaying_noc() { gtk_widget_show_all((GtkWidget*)main_window); // future signal connection + g_signal_connect(display_noc_widget, "toggled", G_CALLBACK(toggle_noc_display), NULL); } From 11c88fa0cae8274c032d7b4e8e6fbe1adeee6345 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 28 Mar 2022 23:52:14 -0400 Subject: [PATCH 051/128] added functions to draw the NoC on the FPGA when the display noc radio button is asserted. The NoC links and their connection points are drawn. --- vpr/src/draw/draw.cpp | 220 ++++++++++++++++++++++++++++++++++++++ vpr/src/draw/draw.h | 1 + vpr/src/draw/draw_types.h | 2 + 3 files changed, 223 insertions(+) diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 34900a8af1f..325b29d273e 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -95,6 +95,7 @@ static void draw_routing_bb(ezgl::renderer* g); static void draw_routing_util(ezgl::renderer* g); static void draw_crit_path(ezgl::renderer* g); static void draw_placement_macros(ezgl::renderer* g); +static void draw_noc(ezgl::renderer* g); void act_on_key_press(ezgl::application* /*app*/, GdkEventKey* /*event*/, char* key_name); void act_on_mouse_press(ezgl::application* app, GdkEventButton* event, double x, double y); @@ -187,6 +188,13 @@ static void set_block_text(GtkWidget* widget, gint /*response_id*/, gpointer /*d static void clip_routing_util(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); static void run_graphics_commands(std::string commands); +// draw_noc helper functions +static ezgl::rectangle get_noc_connection_marker_bbox(const t_logical_block_type_ptr noc_router_logical_block_type); + +static void draw_noc_connection_marker(ezgl::renderer* g, const vtr::vector& router_list, ezgl::rectangle connection_marker_bbox); + +static void draw_noc_links(ezgl::renderer* g, const t_logical_block_type_ptr noc_router_logical_block_type); + /************************** File Scope Variables ****************************/ //The arrow head position for turning/straight-thru connections in a switch box @@ -194,6 +202,10 @@ constexpr float SB_EDGE_TURN_ARROW_POSITION = 0.2; constexpr float SB_EDGE_STRAIGHT_ARROW_POSITION = 0.95; constexpr float EMPTY_BLOCK_LIGHTEN_FACTOR = 0.20; +// defines the area of the marker that represents connection points between links +// area is equivalent to the %x of the area of the router +constexpr float SIZE_OF_NOC_MARKER = 0.04; + //Kelly's maximum contrast colors are selected to be easily distinguishable as described in: // Kenneth Kelly, "Twenty-Two Colors of Maximum Contrast", Color Eng. 3(6), 1943 //We use these to highlight a relatively small number of things (e.g. stages in a critical path, @@ -312,6 +324,8 @@ static void draw_main_canvas(ezgl::renderer* g) { draw_logical_connections(g); + draw_noc(g); + if (draw_state->color_map) { draw_color_map_legend(*draw_state->color_map, g); draw_state->color_map.reset(); //Free color map in preparation for next redraw @@ -903,6 +917,20 @@ void toggle_router_expansion_costs(GtkWidget* /*widget*/, gint /*response_id*/, application.refresh_drawing(); } +void toggle_noc_display(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/) +{ + t_draw_state* draw_state = get_draw_state_vars(); + + // assign corresponding bool value to draw_state->noc_display + if (gtk_toggle_button_get_active((GtkToggleButton*)widget)) + draw_state->draw_noc = true; + else + draw_state->draw_noc = false; + + //redraw + application.refresh_drawing(); +} + #endif // NO_GRAPHICS void alloc_draw_structs(const t_arch* arch) { @@ -3643,6 +3671,198 @@ static void draw_routed_timing_edge(tatum::NodeId start_tnode, g->set_line_dash(ezgl::line_dash::none); } +/* + This function draws the NoC by drawing the links of the NoC and highlights the connection points between links.The drawing is done on top of all the placment and routing, so this acts as an overlay. + +*/ +static void draw_noc(ezgl::renderer *g) +{ + t_draw_state* draw_state = get_draw_state_vars(); + auto& noc_ctx = g_vpr_ctx.noc(); + auto& device_ctx = g_vpr_ctx.device(); + + // vector of routers in the NoC + vtr::vector router_list = noc_ctx.noc_model.get_noc_routers(); + + + // start by checking to see if the NoC display button was selected + // if the noc display option was not selected then don't draw the noc + if (!draw_state->draw_noc) + { + return; + } + + // check that the NoC tile has a capacity greater than 0 (can we assume it always will?) and if not then we cant draw anythign as the NoC tile wont be drawn + /* since the vector of routers all have a reference positions on the grid to the corresponding physical tile, just use the first router in the vector and get its position, then use this to get the capcity of a noc router tile + */ + int num_subtiles = device_ctx.grid[router_list.begin()->get_router_grid_position_x()][router_list.begin()->get_router_grid_position_y()].type->capacity; + + // get the logical type of a noc router tile + t_logical_block_type_ptr noc_router_logical_type = pick_logical_type(device_ctx.grid[router_list.begin()->get_router_grid_position_x()][router_list.begin()->get_router_grid_position_y()].type); + + if (num_subtiles == 0) + { + return; + } + + // Now construct the coordinates for the markers that represent the connections between links (relative to the noc router tile position) + ezgl::rectangle noc_connection_marker_bbox = get_noc_connection_marker_bbox(noc_router_logical_type); + + + draw_noc_connection_marker(g, router_list, noc_connection_marker_bbox); + draw_noc_links(g, noc_router_logical_type); + + return; +} + +/************* draw_noc helper functions below *************/ + +/* + This function calculates the position of the marker that will be drawn inside the noc router tile on the FPGA. This marker will be located in the center of the tile and represents a connection point between links that connect to the router. +*/ +static ezgl::rectangle get_noc_connection_marker_bbox(const t_logical_block_type_ptr noc_router_logical_block_type) +{ + t_draw_coords* draw_coords = get_draw_coords_vars(); + + // get the drawing information for a noc router + t_draw_pb_type_info& blk_type_info = draw_coords->blk_info.at(noc_router_logical_block_type->index); + + // get the drawing coordinates for the noc router tile + auto& pb_gnode = *noc_router_logical_block_type->pb_graph_head; + ezgl::rectangle noc_router_pb_bbox = blk_type_info.get_pb_bbox(pb_gnode); + + /* + The connection marker will be positioned at the center of the noc router tile. For example it will look like below: + + ********************* + * * + * * + * **** * + * * * * + * **** * + * * + * * + ********************* + + We do the following to calculate the position of the marker: + 1. Get the area of the larger router tile + 2. Calculate the area of the marker (based on a predefined percentage of the area of the larger noc tile) + 3. The marker is a square, so we can can calculate the lengths + of the sides of the marker + 4. Divide the side length by 2 and subtract this from the x & y coordinates of the center of the larger noc router tile. This is the bottom left corner of the rectangle. + 5. Then add the side length to the x & y coordinate of the center of the larger noc router tile. THis is the top right corner of the rectangle. + */ + double noc_router_bbox_area = noc_router_pb_bbox.area(); + ezgl::point2d noc_router_bbox_center = noc_router_pb_bbox.center(); + + double connection_marker_bbox_area = noc_router_bbox_area * SIZE_OF_NOC_MARKER; + double connection_marker_bbox_side_length = sqrt(connection_marker_bbox_area); + + double half_of_connection_marker_bbox_side_length = connection_marker_bbox_side_length/2; + + // calculate bottom left corner coordinate of marker + ezgl::point2d connection_marker_origin_pt(noc_router_bbox_center.x - half_of_connection_marker_bbox_side_length, noc_router_bbox_center.y - half_of_connection_marker_bbox_side_length); + // calculate upper right corner coordinate of marker + ezgl::point2d connection_marker_top_right_pt(noc_router_bbox_center.x + half_of_connection_marker_bbox_side_length, noc_router_bbox_center.y + half_of_connection_marker_bbox_side_length); + + ezgl::rectangle connection_marker_bbox(connection_marker_origin_pt, connection_marker_top_right_pt); + + return connection_marker_bbox; + +} + +/* + This function draws the markers inside the noc router tiles. This marker represents a connection that is an intersection points between multiple links. +*/ +static void draw_noc_connection_marker(ezgl::renderer* g,const vtr::vector& router_list, ezgl::rectangle connection_marker_bbox) +{ + t_draw_coords* draw_coords = get_draw_coords_vars(); + + //set the color of the marker + g->set_color(ezgl::BLACK); + + int router_grid_position_x = 0; + int router_grid_position_y = 0; + + ezgl::rectangle updated_connection_marker_bbox; + + // go through the routers and create the connection marker + for(auto router = router_list.begin(); router != router_list.end(); router++) + { + router_grid_position_x = router->get_router_grid_position_x(); + router_grid_position_y = router->get_router_grid_position_y(); + + // get the coordinates to draw the marker given the current routers tile position + updated_connection_marker_bbox = connection_marker_bbox + ezgl::point2d(draw_coords->tile_x[router_grid_position_x], draw_coords->tile_y[router_grid_position_y]); + + // draw the marker + g->fill_rectangle(updated_connection_marker_bbox); + + } + + return; +} + +/* + This function draws the links within the noc. So based on a given noc topology, this function draws the links that connect the routers in the noc together. +*/ +static void draw_noc_links(ezgl::renderer* g, const t_logical_block_type_ptr noc_router_logical_block_type) +{ + t_draw_coords* draw_coords = get_draw_coords_vars(); + auto& noc_ctx = g_vpr_ctx.noc(); + + // vector of routers in the NoC + vtr::vector router_list = noc_ctx.noc_model.get_noc_routers(); + + // get the links of the NoC + vtr::vector link_list = noc_ctx.noc_model.get_noc_links(); + + // set the color of the noc link + g->set_color(ezgl::BLACK); + // set the width of the link + g->set_line_width(4); + + // routers connecting links + NocRouterId source_router; + NocRouterId sink_router; + + // source router grid coordinates + int source_router_x_position = 0; + int source_router_y_position = 0; + + // sink router grid coordinates + int sink_router_x_position = 0; + int sink_router_y_position = 0; + + // coordinates of source and sink routers + ezgl::rectangle abs_source_router_bbox; + ezgl::rectangle abs_sink_router_bbox; + + + // loop through the links and draw them + for(auto link = link_list.begin(); link != link_list.end(); link++) + { + // get the routers + source_router = link->get_source_router(); + sink_router = link->get_sink_router(); + + // calculate the grid positions of the source and sink routers + source_router_x_position = router_list[source_router].get_router_grid_position_x(); + source_router_y_position = router_list[source_router].get_router_grid_position_y(); + + sink_router_x_position = router_list[sink_router].get_router_grid_position_x(); + sink_router_y_position = router_list[sink_router].get_router_grid_position_y(); + + // get the drawing box coordinates of the source and sink routers + abs_source_router_bbox = draw_coords->get_absolute_clb_bbox(source_router_x_position, source_router_y_position, 0,noc_router_logical_block_type); + abs_sink_router_bbox = draw_coords->get_absolute_clb_bbox(sink_router_x_position, sink_router_y_position, 0,noc_router_logical_block_type); + + //draw a line between the center of the two routers this link connects + g->draw_line(abs_source_router_bbox.center(), abs_sink_router_bbox.center()); + } + + return; +} //Collect all the drawing locations associated with the timing edge between start and end static void draw_routed_timing_edge_connection(tatum::NodeId src_tnode, tatum::NodeId sink_tnode, diff --git a/vpr/src/draw/draw.h b/vpr/src/draw/draw.h index ebe90441955..158ed0cb7e4 100644 --- a/vpr/src/draw/draw.h +++ b/vpr/src/draw/draw.h @@ -78,6 +78,7 @@ void toggle_crit_path(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*da void toggle_block_pin_util(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); void toggle_router_expansion_costs(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); void toggle_placement_macros(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); +void toggle_noc_display(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); void net_max_fanout(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); void set_net_alpha_value(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); void set_net_alpha_value_with_enter(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); diff --git a/vpr/src/draw/draw_types.h b/vpr/src/draw/draw_types.h index 52640d8e7d6..e230e30c089 100644 --- a/vpr/src/draw/draw_types.h +++ b/vpr/src/draw/draw_types.h @@ -198,6 +198,8 @@ struct t_draw_state { float net_alpha = 0.1; float pres_fac = 1.; ManualMovesState manual_moves_state; + bool show_noc_button = false; + bool draw_noc = false; std::vector list_of_breakpoints; From bde20d43ba5c04482dfd51f0627eb2edfb5f7545 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 29 Mar 2022 23:14:30 -0400 Subject: [PATCH 052/128] added a new feature that displays a heat map of the usage of all the noc links --- vpr/src/draw/draw.cpp | 153 ++++++++++++++++++++++++++++++++++++-- vpr/src/draw/draw_types.h | 1 + 2 files changed, 146 insertions(+), 8 deletions(-) diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 325b29d273e..687117e4b13 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -193,7 +193,9 @@ static ezgl::rectangle get_noc_connection_marker_bbox(const t_logical_block_type static void draw_noc_connection_marker(ezgl::renderer* g, const vtr::vector& router_list, ezgl::rectangle connection_marker_bbox); -static void draw_noc_links(ezgl::renderer* g, const t_logical_block_type_ptr noc_router_logical_block_type); +static void draw_noc_links(ezgl::renderer* g, const t_logical_block_type_ptr noc_router_logical_block_type, vtr::vector& noc_link_colors); + +static void draw_noc_usage(vtr::vector& noc_link_colors); /************************** File Scope Variables ****************************/ @@ -3684,6 +3686,12 @@ static void draw_noc(ezgl::renderer *g) // vector of routers in the NoC vtr::vector router_list = noc_ctx.noc_model.get_noc_routers(); + // a vector of colors to use for the NoC links, determines the colors used when drawing each link + vtr::vector noc_link_colors; + + // initialize all the link colors to black and set the vector size to the total number of links + noc_link_colors.resize(noc_ctx.noc_model.get_noc_links().size(), ezgl::BLACK); + // start by checking to see if the NoC display button was selected // if the noc display option was not selected then don't draw the noc @@ -3710,7 +3718,132 @@ static void draw_noc(ezgl::renderer *g) draw_noc_connection_marker(g, router_list, noc_connection_marker_bbox); - draw_noc_links(g, noc_router_logical_type); + draw_noc_usage(noc_link_colors); + draw_noc_links(g, noc_router_logical_type, noc_link_colors); + + // draw the color map legend + draw_color_map_legend(*(draw_state->noc_usage_color_map), g); + + return; +} + +static void draw_noc_usage(vtr::vector& noc_link_colors) +{ + t_draw_state* draw_state = get_draw_state_vars(); + auto& noc_ctx = g_vpr_ctx.noc(); + + // get the maximum badnwidth per link + double max_noc_link_bandwidth = noc_ctx.noc_link_bandwidth; + + // check to see if a color map was already created previously + if (draw_state->noc_usage_color_map == nullptr) + { + // we havent created a color map yet for the noc link usage, so create it here + // the color map creates a color spectrum that gradually changes from a dark to light color. Where a dark color represents low noc link usage (low bandwidth) and a light color represents high noc link usage (high bandwidth) + // The color map needs a min and max value to generate the color range. + // for the NoC, the min value is 0, since you cannot go lower than 0 badnwidth. + // The max value is going to be the maximum allowable bandwidth on the noc link (as provided by the user) + draw_state->noc_usage_color_map = std::make_shared(0.0, max_noc_link_bandwidth); + } + + // get the list of links in the NoC + // get the links of the NoC + vtr::vector link_list = noc_ctx.noc_model.get_noc_links(); + + // if the grpah is undirected, then we have a set of parallel links between the same set of routers, so keep track of their bandwidths + double parallel_link_one_bandwidth = -1; + double parallel_link_two_bandwidth = -1; + + // stores the larger bandwidth between two parallel links + double larger_link_bandwidth = -1; + + // the color of the current parallel links + ezgl::color current_noc_link_color; + + // variables to keep track of the source and sink router for each link + NocRouterId link_source_router; + NocRouterId link_sink_router; + + // when we go through the links, if the noc connections are undirected, then we want to get the corresponding parralel link of the current link + // to find this parallel link, we need to go through all the links in the current links sink router, so we store those links here + std::vector sink_router_links; + + + // now we need to determine the colors for each link + for (int link = 0; link < (int)link_list.size(); link++) + { + // get the current link id + NocLinkId link_id(link); + + // keep track of the parallel link id, initialize to an invalid value + NocLinkId parallel_link_id(-1); + + // reset link badnwidths + parallel_link_one_bandwidth = -1; + parallel_link_two_bandwidth = -1; + larger_link_bandwidth = -1; + + // only update the color of the link if it wasnt updated previously + if (noc_link_colors[link_id] == ezgl::BLACK) + { + // if we are here then the link was not updated previously, so assign the color here + parallel_link_one_bandwidth = link_list[link_id].get_bandwidth_usage(); + + // get the source and sink routers of the current link + link_source_router = link_list[link_id].get_source_router(); + link_sink_router = link_list[link_id].get_sink_router(); + + sink_router_links = noc_ctx.noc_model.get_noc_router_connections(link_sink_router); + + // go through the links of the sink router to see if there is a parallel link + for (auto sink_router_link = sink_router_links.begin(); sink_router_link != sink_router_links.end(); sink_router_link++) + { + // the current source link is a parallel link if it has the same source and sink routers as the original link + if ((link_source_router == noc_ctx.noc_model.get_noc_link_sink_router(*sink_router_link)) && (link_sink_router == noc_ctx.noc_model.get_noc_link_source_router(*sink_router_link))) + { + // second the parallel links badnwidth + parallel_link_two_bandwidth = noc_ctx.noc_model.get_noc_link_bandwidth_usage(*sink_router_link); + + // store the parallel link id + parallel_link_id = *sink_router_link; + + break; + } + } + + // we care more about an individual link bandwidth more than the combined bandwidth of both links, so choose the larger bandwidth to detertime the color of both links + // We need to set this color for both links because one will overwrite the other + if (parallel_link_one_bandwidth >= parallel_link_two_bandwidth) + { + larger_link_bandwidth = parallel_link_one_bandwidth; + } + else + { + larger_link_bandwidth = parallel_link_two_bandwidth; + } + + // there is a possibility for the bandwidth to be larger than the maximum, so if it is, we cap it to the maximum value + if (larger_link_bandwidth > noc_ctx.noc_link_bandwidth) + { + larger_link_bandwidth = noc_ctx.noc_link_bandwidth; + } + + // get the corresponding color that represents the link bandwidth + current_noc_link_color = to_ezgl_color(draw_state->noc_usage_color_map->color(larger_link_bandwidth)); + + + // set the colors of the links + noc_link_colors[link_id] = current_noc_link_color; + + // check to see if there was a parallel link and assign it the color if there was + if (parallel_link_id != (NocLinkId)-1) + { + noc_link_colors[parallel_link_id] = current_noc_link_color; + } + + } + + } return; } @@ -3806,7 +3939,7 @@ static void draw_noc_connection_marker(ezgl::renderer* g,const vtr::vector& noc_link_colors) { t_draw_coords* draw_coords = get_draw_coords_vars(); auto& noc_ctx = g_vpr_ctx.noc(); @@ -3817,8 +3950,6 @@ static void draw_noc_links(ezgl::renderer* g, const t_logical_block_type_ptr noc // get the links of the NoC vtr::vector link_list = noc_ctx.noc_model.get_noc_links(); - // set the color of the noc link - g->set_color(ezgl::BLACK); // set the width of the link g->set_line_width(4); @@ -3840,11 +3971,14 @@ static void draw_noc_links(ezgl::renderer* g, const t_logical_block_type_ptr noc // loop through the links and draw them - for(auto link = link_list.begin(); link != link_list.end(); link++) + for(int link = 0; link < (int)link_list.size(); link++) { + // get the converted link if + NocLinkId link_id(link); + // get the routers - source_router = link->get_source_router(); - sink_router = link->get_sink_router(); + source_router = link_list[link_id].get_source_router(); + sink_router = link_list[link_id].get_sink_router(); // calculate the grid positions of the source and sink routers source_router_x_position = router_list[source_router].get_router_grid_position_x(); @@ -3857,6 +3991,9 @@ static void draw_noc_links(ezgl::renderer* g, const t_logical_block_type_ptr noc abs_source_router_bbox = draw_coords->get_absolute_clb_bbox(source_router_x_position, source_router_y_position, 0,noc_router_logical_block_type); abs_sink_router_bbox = draw_coords->get_absolute_clb_bbox(sink_router_x_position, sink_router_y_position, 0,noc_router_logical_block_type); + // set the color to draw the current link + g->set_color(noc_link_colors[link_id]); + //draw a line between the center of the two routers this link connects g->draw_line(abs_source_router_bbox.center(), abs_sink_router_bbox.center()); } diff --git a/vpr/src/draw/draw_types.h b/vpr/src/draw/draw_types.h index e230e30c089..37e97ab3316 100644 --- a/vpr/src/draw/draw_types.h +++ b/vpr/src/draw/draw_types.h @@ -200,6 +200,7 @@ struct t_draw_state { ManualMovesState manual_moves_state; bool show_noc_button = false; bool draw_noc = false; + std::shared_ptr noc_usage_color_map = nullptr; std::vector list_of_breakpoints; From 774e10f18e7162191c509d758979b94c37b0c9d3 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 30 Mar 2022 22:03:51 -0400 Subject: [PATCH 053/128] created a combo box that allows users to have the option to just display the noc links or also the bandwidth usage of each link. --- vpr/src/draw/buttons.cpp | 27 ++++++++++++++++++--------- vpr/src/draw/draw.cpp | 34 +++++++++++++++++++++++----------- vpr/src/draw/draw.h | 2 +- vpr/src/draw/draw_types.h | 14 +++++++++++++- 4 files changed, 55 insertions(+), 22 deletions(-) diff --git a/vpr/src/draw/buttons.cpp b/vpr/src/draw/buttons.cpp index 82c9215f553..5d1450bab7a 100644 --- a/vpr/src/draw/buttons.cpp +++ b/vpr/src/draw/buttons.cpp @@ -246,6 +246,8 @@ void button_for_toggle_crit_path() { void button_for_displaying_noc() { + GObject* main_window = application.get_object(application.get_main_window_id().c_str()); + GObject* main_window_grid = application.get_object("InnerGrid"); t_draw_state* draw_state = get_draw_state_vars(); // if the user did not turn on the "noc" option then we don't give the option to display the noc to the user @@ -255,22 +257,29 @@ void button_for_displaying_noc() { } // if we are here then the user turned the "noc" option on, so create a radio button to allow the user to display the noc - GObject* main_window = application.get_object(application.get_main_window_id().c_str()); - GObject* main_window_grid = application.get_object("InnerGrid"); - GtkWidget* display_noc_widget = gtk_check_button_new_with_label("Display NoC"); - gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(display_noc_widget), false); - gtk_widget_set_name(display_noc_widget, "display_noc"); + //combo box for toggle_crit_path + GtkWidget* toggle_noc_display_widget = gtk_combo_box_text_new(); + GtkWidget* toggle_noc_display_label = gtk_label_new("Toggle NoC Display:"); + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(toggle_noc_display_widget), "None"); + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(toggle_noc_display_widget), "NoC Links"); + gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(toggle_noc_display_widget), "NoC Link Usage"); + + gtk_combo_box_set_active((GtkComboBox*)toggle_noc_display_widget, 0); // default set to None which has an index 0 + gtk_widget_set_name(toggle_noc_display_widget, "toggle_noc_display"); //attach to the grid - gtk_grid_attach((GtkGrid*)main_window_grid, display_noc_widget, label_left_start_col, button_row++, box_width, box_height); + gtk_grid_attach((GtkGrid*)main_window_grid, toggle_noc_display_label, label_left_start_col, button_row++, box_width, box_height); + gtk_grid_attach((GtkGrid*)main_window_grid, toggle_noc_display_widget, box_left_start_col, button_row++, box_width, box_height); // show the newy added check box gtk_widget_show_all((GtkWidget*)main_window); - // future signal connection - g_signal_connect(display_noc_widget, "toggled", G_CALLBACK(toggle_noc_display), NULL); - + //connect signals + g_signal_connect_swapped(GTK_COMBO_BOX_TEXT(toggle_noc_display_widget), + "changed", + G_CALLBACK(toggle_noc_display), + toggle_noc_display_widget); } diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 687117e4b13..9145acdf115 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -919,17 +919,24 @@ void toggle_router_expansion_costs(GtkWidget* /*widget*/, gint /*response_id*/, application.refresh_drawing(); } -void toggle_noc_display(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/) +void toggle_noc_display(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { + /* this is the callback function for runtime created toggle_noc_display button + * which is written in button.cpp */ t_draw_state* draw_state = get_draw_state_vars(); + std::string button_name = "toggle_noc_display"; + auto toggle_crit_path = find_button(button_name.c_str()); - // assign corresponding bool value to draw_state->noc_display - if (gtk_toggle_button_get_active((GtkToggleButton*)widget)) - draw_state->draw_noc = true; + gchar* combo_box_content = gtk_combo_box_text_get_active_text( + GTK_COMBO_BOX_TEXT(toggle_crit_path)); + if (strcmp(combo_box_content, "None") == 0) { + draw_state->draw_noc = DRAW_NO_NOC; + } else if (strcmp(combo_box_content, "NoC Links") == 0) + draw_state->draw_noc = DRAW_NOC_LINKS; else - draw_state->draw_noc = false; + draw_state->draw_noc = DRAW_NOC_LINK_USAGE; - //redraw + g_free(combo_box_content); application.refresh_drawing(); } @@ -3695,7 +3702,7 @@ static void draw_noc(ezgl::renderer *g) // start by checking to see if the NoC display button was selected // if the noc display option was not selected then don't draw the noc - if (!draw_state->draw_noc) + if (draw_state->draw_noc == DRAW_NO_NOC) { return; } @@ -3716,13 +3723,18 @@ static void draw_noc(ezgl::renderer *g) // Now construct the coordinates for the markers that represent the connections between links (relative to the noc router tile position) ezgl::rectangle noc_connection_marker_bbox = get_noc_connection_marker_bbox(noc_router_logical_type); + // only draw the noc useage if the user selected the option + if (draw_state->draw_noc == DRAW_NOC_LINK_USAGE) { + + draw_noc_usage(noc_link_colors); + + // draw the color map legend + draw_color_map_legend(*(draw_state->noc_usage_color_map), g); + } - draw_noc_connection_marker(g, router_list, noc_connection_marker_bbox); - draw_noc_usage(noc_link_colors); draw_noc_links(g, noc_router_logical_type, noc_link_colors); - // draw the color map legend - draw_color_map_legend(*(draw_state->noc_usage_color_map), g); + draw_noc_connection_marker(g, router_list, noc_connection_marker_bbox); return; } diff --git a/vpr/src/draw/draw.h b/vpr/src/draw/draw.h index 158ed0cb7e4..6a3f21f0688 100644 --- a/vpr/src/draw/draw.h +++ b/vpr/src/draw/draw.h @@ -78,7 +78,7 @@ void toggle_crit_path(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*da void toggle_block_pin_util(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); void toggle_router_expansion_costs(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); void toggle_placement_macros(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); -void toggle_noc_display(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); +void toggle_noc_display(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); void net_max_fanout(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); void set_net_alpha_value(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); void set_net_alpha_value_with_enter(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); diff --git a/vpr/src/draw/draw_types.h b/vpr/src/draw/draw_types.h index 37e97ab3316..091c4b287c6 100644 --- a/vpr/src/draw/draw_types.h +++ b/vpr/src/draw/draw_types.h @@ -118,6 +118,18 @@ enum e_edge_dir { FROM_Y_TO_X }; +/* + Defines the type of drawings that can be generated for the NoC. + DRAW_NO_NOC -> user did not select the option to draw the NoC + DRAW_NOC_LINKS -> display the NoC links and how they are connected to each other + DRAW_NOC_LINK_USAGE -> Display the NoC links (same as DRAW_NOC_LINKS) and color the links based on their bandwidth usage +*/ +enum e_draw_noc { + DRAW_NO_NOC = 0, + DRAW_NOC_LINKS, + DRAW_NOC_LINK_USAGE +}; + /* Structure which stores state information of a rr_node. Used * for controling the drawing each rr_node when ROUTING is on screen. * color: Color of the rr_node @@ -199,7 +211,7 @@ struct t_draw_state { float pres_fac = 1.; ManualMovesState manual_moves_state; bool show_noc_button = false; - bool draw_noc = false; + e_draw_noc draw_noc = DRAW_NO_NOC; std::shared_ptr noc_usage_color_map = nullptr; std::vector list_of_breakpoints; From fc66cc922781adfb52fe310f8d3b28749ccab1ae Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 5 Apr 2022 17:15:32 -0400 Subject: [PATCH 054/128] added a utility function that finds a parralel link of any link in the NoC (if it exsists) --- vpr/src/base/noc_storage.cpp | 26 ++++++++++++++++++++++++++ vpr/src/base/noc_storage.h | 4 ++++ 2 files changed, 30 insertions(+) diff --git a/vpr/src/base/noc_storage.cpp b/vpr/src/base/noc_storage.cpp index 8d69a51399b..23af75c15ac 100644 --- a/vpr/src/base/noc_storage.cpp +++ b/vpr/src/base/noc_storage.cpp @@ -154,3 +154,29 @@ void NocStorage::make_room_for_noc_router_link_list(){ router_link_list.resize(router_storage.size()); } +NocLinkId NocStorage::get_parallel_link(NocLinkId current_link){ + + // get the current source and sink router + NocRouterId curr_source_router = link_storage[current_link].get_source_router(); + NocRouterId curr_sink_router = link_storage[current_link].get_sink_router(); + + // get the link list of the sink router + std::vector *sink_router_links = &(router_link_list[curr_sink_router]); + + NocLinkId parallel_link = INVALID_LINK_ID; + + // go through the links of the sink router and the link that has the current source router as the sink router of the link is the parallel link we are looking for + for (auto link = sink_router_links->begin(); link != sink_router_links->end(); link++){ + + if (link_storage[*link].get_sink_router() == curr_source_router) + { + parallel_link = *link; + break; + } + } + + return parallel_link; + +} + + diff --git a/vpr/src/base/noc_storage.h b/vpr/src/base/noc_storage.h index 52f3c95352d..03a359297b3 100644 --- a/vpr/src/base/noc_storage.h +++ b/vpr/src/base/noc_storage.h @@ -13,6 +13,9 @@ #include "vtr_assert.h" #include "vpr_error.h" +// represents the value of a link that does not exist in the NoC +const NocLinkId INVALID_LINK_ID(-1); + class NocStorage { @@ -80,6 +83,7 @@ class NocStorage void clear_noc(); NocRouterId convert_router_id(int id) const; void make_room_for_noc_router_link_list(); + NocLinkId get_parallel_link(NocLinkId current_link); From ba26e7ceb77fa842f22887da445be30ee6961b41 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 6 Apr 2022 18:08:48 -0400 Subject: [PATCH 055/128] made sure the new utility to find a parallel link in the noc did not mody anything by making it a constant function --- vpr/src/base/noc_storage.cpp | 4 ++-- vpr/src/base/noc_storage.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vpr/src/base/noc_storage.cpp b/vpr/src/base/noc_storage.cpp index 23af75c15ac..c7077388945 100644 --- a/vpr/src/base/noc_storage.cpp +++ b/vpr/src/base/noc_storage.cpp @@ -154,14 +154,14 @@ void NocStorage::make_room_for_noc_router_link_list(){ router_link_list.resize(router_storage.size()); } -NocLinkId NocStorage::get_parallel_link(NocLinkId current_link){ +NocLinkId NocStorage::get_parallel_link(NocLinkId current_link) const{ // get the current source and sink router NocRouterId curr_source_router = link_storage[current_link].get_source_router(); NocRouterId curr_sink_router = link_storage[current_link].get_sink_router(); // get the link list of the sink router - std::vector *sink_router_links = &(router_link_list[curr_sink_router]); + const std::vector *sink_router_links = &(router_link_list[curr_sink_router]); NocLinkId parallel_link = INVALID_LINK_ID; diff --git a/vpr/src/base/noc_storage.h b/vpr/src/base/noc_storage.h index 03a359297b3..295a260411b 100644 --- a/vpr/src/base/noc_storage.h +++ b/vpr/src/base/noc_storage.h @@ -83,7 +83,7 @@ class NocStorage void clear_noc(); NocRouterId convert_router_id(int id) const; void make_room_for_noc_router_link_list(); - NocLinkId get_parallel_link(NocLinkId current_link); + NocLinkId get_parallel_link(NocLinkId current_link) const; From 0038cc022ede4b29fa86a50cacac7c6031a652fe Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 6 Apr 2022 19:05:11 -0400 Subject: [PATCH 056/128] When displaying the NoC, the noc links are drawn so that any parallel links are seperated and not drawn on top of each other --- vpr/src/draw/draw.cpp | 51 ++++++-- vpr/src/draw/draw_noc.cpp | 252 ++++++++++++++++++++++++++++++++++++++ vpr/src/draw/draw_noc.h | 81 ++++++++++++ 3 files changed, 372 insertions(+), 12 deletions(-) create mode 100644 vpr/src/draw/draw_noc.cpp create mode 100644 vpr/src/draw/draw_noc.h diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 9145acdf115..a986b30e87f 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -48,6 +48,7 @@ #include "route_common.h" #include "breakpoint.h" #include "manual_moves.h" +#include "draw_noc.h" #include "move_utils.h" @@ -193,7 +194,7 @@ static ezgl::rectangle get_noc_connection_marker_bbox(const t_logical_block_type static void draw_noc_connection_marker(ezgl::renderer* g, const vtr::vector& router_list, ezgl::rectangle connection_marker_bbox); -static void draw_noc_links(ezgl::renderer* g, const t_logical_block_type_ptr noc_router_logical_block_type, vtr::vector& noc_link_colors); +static void draw_noc_links(ezgl::renderer* g, const t_logical_block_type_ptr noc_router_logical_block_type, vtr::vector& noc_link_colors, ezgl::rectangle noc_connection_marker_bbox, const vtr::vector& list_of_noc_link_shift_directions); static void draw_noc_usage(vtr::vector& noc_link_colors); @@ -206,7 +207,7 @@ constexpr float EMPTY_BLOCK_LIGHTEN_FACTOR = 0.20; // defines the area of the marker that represents connection points between links // area is equivalent to the %x of the area of the router -constexpr float SIZE_OF_NOC_MARKER = 0.04; +constexpr float SIZE_OF_NOC_MARKER = 0.30; //Kelly's maximum contrast colors are selected to be easily distinguishable as described in: // Kenneth Kelly, "Twenty-Two Colors of Maximum Contrast", Color Eng. 3(6), 1943 @@ -3699,6 +3700,11 @@ static void draw_noc(ezgl::renderer *g) // initialize all the link colors to black and set the vector size to the total number of links noc_link_colors.resize(noc_ctx.noc_model.get_noc_links().size(), ezgl::BLACK); + // variables to keep track of how each link is drawn + vtr::vector list_of_noc_link_shift_directions; + + // initialize all the link shift directions to no shift and set the vector size to the total number of links + list_of_noc_link_shift_directions.resize(noc_ctx.noc_model.get_noc_links().size(), NocLinkShift::NO_SHIFT); // start by checking to see if the NoC display button was selected // if the noc display option was not selected then don't draw the noc @@ -3712,14 +3718,14 @@ static void draw_noc(ezgl::renderer *g) */ int num_subtiles = device_ctx.grid[router_list.begin()->get_router_grid_position_x()][router_list.begin()->get_router_grid_position_y()].type->capacity; - // get the logical type of a noc router tile - t_logical_block_type_ptr noc_router_logical_type = pick_logical_type(device_ctx.grid[router_list.begin()->get_router_grid_position_x()][router_list.begin()->get_router_grid_position_y()].type); - if (num_subtiles == 0) { return; } + // get the logical type of a noc router tile + t_logical_block_type_ptr noc_router_logical_type = pick_logical_type(device_ctx.grid[router_list.begin()->get_router_grid_position_x()][router_list.begin()->get_router_grid_position_y()].type); + // Now construct the coordinates for the markers that represent the connections between links (relative to the noc router tile position) ezgl::rectangle noc_connection_marker_bbox = get_noc_connection_marker_bbox(noc_router_logical_type); @@ -3732,7 +3738,11 @@ static void draw_noc(ezgl::renderer *g) draw_color_map_legend(*(draw_state->noc_usage_color_map), g); } - draw_noc_links(g, noc_router_logical_type, noc_link_colors); + // go through all the pairs of parallel links (if there are any) and assign a shift direction to them. + // One link will shift in one direction (knows as TOP) and the other link will shift in the opposite direction (known as BOTTOM) + determine_direction_to_shift_noc_links(list_of_noc_link_shift_directions); + + draw_noc_links(g, noc_router_logical_type, noc_link_colors, noc_connection_marker_bbox, list_of_noc_link_shift_directions); draw_noc_connection_marker(g, router_list, noc_connection_marker_bbox); @@ -3951,7 +3961,7 @@ static void draw_noc_connection_marker(ezgl::renderer* g,const vtr::vector& noc_link_colors) +static void draw_noc_links(ezgl::renderer* g, const t_logical_block_type_ptr noc_router_logical_block_type, vtr::vector& noc_link_colors, ezgl::rectangle noc_connection_marker_bbox, const vtr::vector& list_of_noc_link_shift_directions) { t_draw_coords* draw_coords = get_draw_coords_vars(); auto& noc_ctx = g_vpr_ctx.noc(); @@ -3963,7 +3973,7 @@ static void draw_noc_links(ezgl::renderer* g, const t_logical_block_type_ptr noc vtr::vector link_list = noc_ctx.noc_model.get_noc_links(); // set the width of the link - g->set_line_width(4); + g->set_line_width(3); // routers connecting links NocRouterId source_router; @@ -3981,6 +3991,17 @@ static void draw_noc_links(ezgl::renderer* g, const t_logical_block_type_ptr noc ezgl::rectangle abs_source_router_bbox; ezgl::rectangle abs_sink_router_bbox; + // the coordinates to draw the link + noc_link_draw_coords link_coords; + + // the type of the noc link + NocLinkType link_type; + + // get half the width and height of the noc connection marker + // we will shift the links based on this parameters since the links will be drawn at the boundaries of connection marker instead of the center + double noc_connection_marker_quarter_width = (noc_connection_marker_bbox.center().x - noc_connection_marker_bbox.bottom_left().x)/2; + double noc_connection_marker_quarter_height = (noc_connection_marker_bbox.center().y - noc_connection_marker_bbox.bottom_left().y)/2; + // loop through the links and draw them for(int link = 0; link < (int)link_list.size(); link++) @@ -3999,15 +4020,21 @@ static void draw_noc_links(ezgl::renderer* g, const t_logical_block_type_ptr noc sink_router_x_position = router_list[sink_router].get_router_grid_position_x(); sink_router_y_position = router_list[sink_router].get_router_grid_position_y(); - // get the drawing box coordinates of the source and sink routers - abs_source_router_bbox = draw_coords->get_absolute_clb_bbox(source_router_x_position, source_router_y_position, 0,noc_router_logical_block_type); - abs_sink_router_bbox = draw_coords->get_absolute_clb_bbox(sink_router_x_position, sink_router_y_position, 0,noc_router_logical_block_type); + // get the initial drawing coordinates of the noc link + // it will be drawn from the center of two routers it connects + link_coords.start = draw_coords->get_absolute_clb_bbox(source_router_x_position, source_router_y_position, 0,noc_router_logical_block_type).center(); + link_coords.end = draw_coords->get_absolute_clb_bbox(sink_router_x_position, sink_router_y_position, 0,noc_router_logical_block_type).center(); + + // determine the current noc link type + link_type = determine_noc_link_type(link_coords.start, link_coords.end); + shift_noc_link(link_coords, list_of_noc_link_shift_directions[link_id], link_type, noc_connection_marker_quarter_width, noc_connection_marker_quarter_height); + // set the color to draw the current link g->set_color(noc_link_colors[link_id]); //draw a line between the center of the two routers this link connects - g->draw_line(abs_source_router_bbox.center(), abs_sink_router_bbox.center()); + g->draw_line(link_coords.start, link_coords.end); } return; diff --git a/vpr/src/draw/draw_noc.cpp b/vpr/src/draw/draw_noc.cpp new file mode 100644 index 00000000000..33f37a1087e --- /dev/null +++ b/vpr/src/draw/draw_noc.cpp @@ -0,0 +1,252 @@ + +#include "draw_noc.h" +#include "globals.h" +#include "noc_storage.h" +#include "vpr_error.h" +#include "vtr_math.h" + +/** + * @brief For a NoC that is undirected, each connection between routers has two + * parallel links. This function goes through all the links and assigns + * opposite directions to shift each pair of parallel links. This + * information is later used to determine how each link is shifted. + * The reason for shifting the links is so that the two parallel links + * do not overlap each other when drawn. Instead they are spread apart a + * bit. + * + * @param list_of_noc_link_shift_directions A list that stores the direction to + * shift each link in the NoC when + * drawn. + */ +void determine_direction_to_shift_noc_links(vtr::vector& list_of_noc_link_shift_directions){ + + auto& noc_ctx = g_vpr_ctx.noc(); + //const NocStorage* noc_model = &noc_ctx.noc_model; + + int number_of_links = list_of_noc_link_shift_directions.size(); + + // store the parallel link of wach link we process + NocLinkId parallel_link; + + // go through all the noc links and assign how the link should be shifted + for (int link = 0; link < number_of_links; link++){ + + // convert the link to a link id + NocLinkId link_id(link); + + // only assign a shift direction if we havent already + if (list_of_noc_link_shift_directions[link_id] == NocLinkShift::NO_SHIFT){ + + // the current link will always have a TOP_shift + list_of_noc_link_shift_directions[link_id] = NocLinkShift::TOP_SHIFT; + + // find the parallel link and assign it a BOTTOM_shift + parallel_link = noc_ctx.noc_model.get_parallel_link(link_id); + + // check first if a legal link id was found + if (parallel_link == INVALID_LINK_ID) + { + // if we are here, then a parallel link wasnt found, so that means there is only a single link and there is no need to perform any shifting on the single link + list_of_noc_link_shift_directions[link_id] = NocLinkShift::NO_SHIFT; + + continue; + } + + list_of_noc_link_shift_directions[parallel_link] = NocLinkShift::BOTTOM_SHIFT; + + } + + } + + return; +} + + +/** + * @brief The type (orientation) of a line is determine here. A second + * horizontal line is created that connects to the starting point of the + * provided line (function input). Then the angle between the two + * lines is calculated using the cross product. Based on this angle, the + * line direction is determined (vertical, horizontal, positive sloped + * or negative sloped). + * + * @param link_start_point The starting point of a line that represents a NoC + * link. + * @param link_end_point THe end point of a line that represent a NoC link. +*/ +NocLinkType determine_noc_link_type(ezgl::point2d link_start_point, ezgl::point2d link_end_point){ + + // get the coordinates of the provided line + double x_coord_start = link_start_point.x; + double y_coord_start = link_start_point.y; + + double x_coord_end = link_end_point.x; + double y_coord_end = link_end_point.y; + + // create a horizontal line that connects to the start point of the provided line and spans a predefined length + double x_coord_horizontal_start = link_start_point.x; + double y_coord_horizontal_start = link_start_point.y; + + double x_coord_horziontal_end = x_coord_horizontal_start + HORIZONTAL_LINE_LENGTH; + double y_coord_horizontal_end = link_start_point.y; + + // stores the line type + NocLinkType result = NocLinkType::INVALID_TYPE; + + // we can check quickly if the line is vertical or horizontal without calculating the cross product. If it is vertical or horizontal then we just return. Otherwise we have to calculate it. + + // check if the line is vertical by determining if there is any horizontal change + if (vtr::isclose(x_coord_end - x_coord_start, 0.0)){ + result = NocLinkType::VERTICAL; + + return result; + } + + // check if the line is horizontal by determinig if there is any vertical shift + if (vtr::isclose(y_coord_end - y_coord_start, 0.0)){ + result = NocLinkType::HORIZONTAL; + + return result; + } + + // if we are here then the line has a slope, so we use the cross product to determine the angle + double angle = acos(((x_coord_end - x_coord_start) * (x_coord_horziontal_end - x_coord_horizontal_start) + (y_coord_end - y_coord_start) * (y_coord_horizontal_end - y_coord_horizontal_start)) / (sqrt(pow(x_coord_end - x_coord_start, 2.0) + pow(y_coord_end - y_coord_start, 2.0)) * sqrt(pow(x_coord_horziontal_end - x_coord_horizontal_start, 2.0) + pow(y_coord_horizontal_end - y_coord_horizontal_start, 2.0)))); + + // the angle is in the first or fourth quandrant of the unit circle + if ((angle > 0) && (angle < (PI_RADIAN/2))){ + + // if it is a positive sloped line, then the y coordinate of the end point is higher the y-coordinate of the horizontal line + if (y_coord_end > y_coord_horizontal_end){ + + result = NocLinkType::POSITVE_SLOPE; + } + else{ // if the end y-coordinate is less than the horizontal line then we have a negative sloped line + + result = NocLinkType::NEGATIVE_SLOPE; + } + + } + else{ // the case where the angle is in the 3rd and 4th quandrant of the unit cirle + + // if the line is positive sloped, then the y-coordinate of the end point is lower than the y-coordinate of the horizontal line + if (y_coord_end < y_coord_horizontal_end){ + + result = NocLinkType::POSITVE_SLOPE; + } + else{ // if the end y-coordinate of is greater than the horizontal line then we have a negative sloped line + + result = NocLinkType::NEGATIVE_SLOPE; + } + } + + return result; + +} + +/** + * @brief Given the starting and end coordinates of a line that represents a + * NoC link, the line shifted to a new set of coordinates based on its + * type and shift direction. THe appropriate shifting formula is applied + * to each line based on its type and direction to shift. The end result + * is that each pair of parallel links are spaces apart and not drawn on + * top of each other. + * + * @param link_coords The original coordinates to draw the NoC link. + * @param link_shift_direction The direction to shift the NoC link. + * @param link_type The type (direction) of the NoC link. + * @param noc_connection_marker_quarter_width The distance to shift the NoC link + * in the horizontal direction. + * @param noc_connection_marker_quarter_height The distance to shift the NoC + * link in the vertical direction. + */ +void shift_noc_link(noc_link_draw_coords& link_coords, NocLinkShift link_shift_direction, NocLinkType link_type, double noc_connection_marker_quarter_width, double noc_connection_marker_quarter_height){ + + // determine the type of link and based on that shift the link accordingly + /* + Vertical line: shift the link left and right and the distance is equal to half the width of the connection marker + + horizontal line: shift the link up and down and the distance is equal to half the width of the connection marker + + positive slope line: shift the link to the bottom right and top left corners of the connection marker + + negative slope line: shift the link to the bottom left and top roght corners of the connection marker + + */ + + switch (link_type){ + case NocLinkType::INVALID_TYPE: + break; + case NocLinkType::VERTICAL: + if (link_shift_direction == NocLinkShift::TOP_SHIFT){ + // shift the link left + link_coords.start.x -= noc_connection_marker_quarter_width; + link_coords.end.x -= noc_connection_marker_quarter_width; + } + else if (link_shift_direction == NocLinkShift::BOTTOM_SHIFT){ + // shift to the right + link_coords.start.x += noc_connection_marker_quarter_width; + link_coords.end.x += noc_connection_marker_quarter_width; + } + // dont change anything if we arent shifting at all + break; + case NocLinkType::HORIZONTAL: + if (link_shift_direction == NocLinkShift::TOP_SHIFT){ + // shift the link up + link_coords.start.y += noc_connection_marker_quarter_height; + link_coords.end.y += noc_connection_marker_quarter_height; + } + else if (link_shift_direction == NocLinkShift::BOTTOM_SHIFT){ + // shift to the down + link_coords.start.y -= noc_connection_marker_quarter_height; + link_coords.end.y -= noc_connection_marker_quarter_height; + } + // dont change anything if we arent shifting at all + break; + case NocLinkType::POSITVE_SLOPE: + if (link_shift_direction == NocLinkShift::TOP_SHIFT){ + // shift link up and left to the top left corner + link_coords.start.x -= noc_connection_marker_quarter_width; + link_coords.end.x -= noc_connection_marker_quarter_width; + + link_coords.start.y += noc_connection_marker_quarter_height; + link_coords.end.y += noc_connection_marker_quarter_height; + } + else if (link_shift_direction == NocLinkShift::BOTTOM_SHIFT){ + // shift link down and right to the bottom right corner + link_coords.start.x += noc_connection_marker_quarter_width; + link_coords.end.x += noc_connection_marker_quarter_width; + + link_coords.start.y -= noc_connection_marker_quarter_height; + link_coords.end.y -= noc_connection_marker_quarter_height; + } + // dont change anything if we arent shifting at all + break; + case NocLinkType::NEGATIVE_SLOPE: + if (link_shift_direction == NocLinkShift::TOP_SHIFT){ + // shift link down and left to the bottom left corner + link_coords.start.x -= noc_connection_marker_quarter_width; + link_coords.end.x -= noc_connection_marker_quarter_width; + + link_coords.start.y -= noc_connection_marker_quarter_height; + link_coords.end.y -= noc_connection_marker_quarter_height; + } + else if (link_shift_direction == NocLinkShift::BOTTOM_SHIFT){ + // shift link up and right to the top right corner + link_coords.start.x += noc_connection_marker_quarter_width; + link_coords.end.x += noc_connection_marker_quarter_width; + + link_coords.start.y += noc_connection_marker_quarter_height; + link_coords.end.y += noc_connection_marker_quarter_height; + } + // dont change anything if we arent shifting at all + break; + default: + break; + } + + return; +} + + + + diff --git a/vpr/src/draw/draw_noc.h b/vpr/src/draw/draw_noc.h new file mode 100644 index 00000000000..ef5f7c0c236 --- /dev/null +++ b/vpr/src/draw/draw_noc.h @@ -0,0 +1,81 @@ +#ifndef DRAW_NOC_H +#define DRAW_NOC_H +/* + THis file contains functions and data types related to drawing the NoC in the canvas. + + The functions here should be used to determine how the NoC links should be drawn. + +*/ +#include +#include + +#include "draw.h" + +// defines the length of a reference horizontal line that is used in a cross product to calculate the angle between this line and a noc link to be drawn +const double HORIZONTAL_LINE_LENGTH(5.0); + +const double PI_RADIAN(3.141593); + +// represents the coordinates needed to draw any noc link in the canvas +// contains the start and end positions of the link +struct noc_link_draw_coords { + ezgl::point2d start; + ezgl::point2d end; +}; + + +// define the types of orientations we will see links draw in in the canvas +// vertical defines a vertical line +// horizontal defines a horizontal line +// positive_slope defines a line that is angled and has a positive slope +// negative_slope defines a line that is angled and has a negative slope +enum NocLinkType { + INVALID_TYPE, // initially all links are undefined + HORIZONTAL, + VERTICAL, + POSITVE_SLOPE, + NEGATIVE_SLOPE +}; + +/* + Since the noc links run in both directions between any two routers, we want to draw them parallel to each other instead of ovrelapping them. So the idea is to shift one link in one direction and shift the other link in the opposite direction. THe enum below defines the direction a link was shifted, so for example if we had a vertical line, top would be mean shift left and Bottom would mean shift right. SImilarily, if we had a horizontal line, top would mean shift up and bottom would mean shift down. +*/ +enum NocLinkShift { + NO_SHIFT, // initially there is no shift + TOP_SHIFT, + BOTTOM_SHIFT +}; + +void determine_direction_to_shift_noc_links(vtr::vector& list_of_noc_link_shift_directions); + +NocLinkType determine_noc_link_type(ezgl::point2d link_start_point, ezgl::point2d link_end_point); + +void shift_noc_link(noc_link_draw_coords& link_coords, NocLinkShift link_shift_direction, NocLinkType link_type, double noc_connection_marker_quarter_width, double noc_connection_marker_quarter_height); + + + + + + + + + + + + + + + + + + + + + + + + + + + +#endif \ No newline at end of file From bd6ca3f503de34dad5a9b64ffb72f07ef72c1e4f Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Thu, 7 Apr 2022 19:40:52 -0400 Subject: [PATCH 057/128] Since the links don't overlap anymore, ensured that each link as a unique color to represent its usage. --- vpr/src/draw/draw.cpp | 87 ++++++++----------------------------------- 1 file changed, 15 insertions(+), 72 deletions(-) diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index a986b30e87f..77b5af2f587 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -3763,33 +3763,21 @@ static void draw_noc_usage(vtr::vector& noc_link_colors) // we havent created a color map yet for the noc link usage, so create it here // the color map creates a color spectrum that gradually changes from a dark to light color. Where a dark color represents low noc link usage (low bandwidth) and a light color represents high noc link usage (high bandwidth) // The color map needs a min and max value to generate the color range. + // The noc usage is calculated by taking the ratio of the links current bandwidth over the maximum allowable bandwidth // for the NoC, the min value is 0, since you cannot go lower than 0 badnwidth. - // The max value is going to be the maximum allowable bandwidth on the noc link (as provided by the user) - draw_state->noc_usage_color_map = std::make_shared(0.0, max_noc_link_bandwidth); + // The max value is going to be 1 and represents the case where the link is used to full capacity on the noc link (as provided by the user) + draw_state->noc_usage_color_map = std::make_shared(0.0, 1.0); } // get the list of links in the NoC - // get the links of the NoC vtr::vector link_list = noc_ctx.noc_model.get_noc_links(); - // if the grpah is undirected, then we have a set of parallel links between the same set of routers, so keep track of their bandwidths - double parallel_link_one_bandwidth = -1; - double parallel_link_two_bandwidth = -1; - - // stores the larger bandwidth between two parallel links - double larger_link_bandwidth = -1; + // store each links bandwidth usage + double link_bandwidth_usage; - // the color of the current parallel links + // represents the color to draw each noc link ezgl::color current_noc_link_color; - // variables to keep track of the source and sink router for each link - NocRouterId link_source_router; - NocRouterId link_sink_router; - - // when we go through the links, if the noc connections are undirected, then we want to get the corresponding parralel link of the current link - // to find this parallel link, we need to go through all the links in the current links sink router, so we store those links here - std::vector sink_router_links; - // now we need to determine the colors for each link for (int link = 0; link < (int)link_list.size(); link++) @@ -3797,72 +3785,27 @@ static void draw_noc_usage(vtr::vector& noc_link_colors) // get the current link id NocLinkId link_id(link); - // keep track of the parallel link id, initialize to an invalid value - NocLinkId parallel_link_id(-1); - - // reset link badnwidths - parallel_link_one_bandwidth = -1; - parallel_link_two_bandwidth = -1; - larger_link_bandwidth = -1; - // only update the color of the link if it wasnt updated previously if (noc_link_colors[link_id] == ezgl::BLACK) { // if we are here then the link was not updated previously, so assign the color here - parallel_link_one_bandwidth = link_list[link_id].get_bandwidth_usage(); - - // get the source and sink routers of the current link - link_source_router = link_list[link_id].get_source_router(); - link_sink_router = link_list[link_id].get_sink_router(); - - sink_router_links = noc_ctx.noc_model.get_noc_router_connections(link_sink_router); - - // go through the links of the sink router to see if there is a parallel link - for (auto sink_router_link = sink_router_links.begin(); sink_router_link != sink_router_links.end(); sink_router_link++) - { - // the current source link is a parallel link if it has the same source and sink routers as the original link - if ((link_source_router == noc_ctx.noc_model.get_noc_link_sink_router(*sink_router_link)) && (link_sink_router == noc_ctx.noc_model.get_noc_link_source_router(*sink_router_link))) - { - // second the parallel links badnwidth - parallel_link_two_bandwidth = noc_ctx.noc_model.get_noc_link_bandwidth_usage(*sink_router_link); - - // store the parallel link id - parallel_link_id = *sink_router_link; - - break; - } - } - // we care more about an individual link bandwidth more than the combined bandwidth of both links, so choose the larger bandwidth to detertime the color of both links - // We need to set this color for both links because one will overwrite the other - if (parallel_link_one_bandwidth >= parallel_link_two_bandwidth) - { - larger_link_bandwidth = parallel_link_one_bandwidth; - } - else - { - larger_link_bandwidth = parallel_link_two_bandwidth; - } + //get the current link bandwidth usage (ratio calculation) + link_bandwidth_usage = (link_list[link_id].get_bandwidth_usage()) / max_noc_link_bandwidth; - // there is a possibility for the bandwidth to be larger than the maximum, so if it is, we cap it to the maximum value - if (larger_link_bandwidth > noc_ctx.noc_link_bandwidth) + // check if the link is being overused and if it is then cap it at 1.0 + if (link_bandwidth_usage > 1.0) { - larger_link_bandwidth = noc_ctx.noc_link_bandwidth; + link_bandwidth_usage = 1.0; } - // get the corresponding color that represents the link bandwidth - current_noc_link_color = to_ezgl_color(draw_state->noc_usage_color_map->color(larger_link_bandwidth)); + // get the corresponding color that represents the link bandwidth usgae + current_noc_link_color = to_ezgl_color(draw_state->noc_usage_color_map->color(link_bandwidth_usage)); - // set the colors of the links + // set the colors of the link noc_link_colors[link_id] = current_noc_link_color; - - // check to see if there was a parallel link and assign it the color if there was - if (parallel_link_id != (NocLinkId)-1) - { - noc_link_colors[parallel_link_id] = current_noc_link_color; - } - + } } From ee0c34469515cede0e5bfb5ad2d14083e4303364 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 11 Apr 2022 22:39:16 -0400 Subject: [PATCH 058/128] Improved code documentation (added comments) --- libs/libarchfpga/src/physical_types.h | 8 +- libs/libarchfpga/src/read_xml_arch_file.cpp | 321 ++- .../test/test_read_xml_arch_file.cpp | 87 +- vpr/src/base/SetupVPR.cpp | 6 +- vpr/src/base/ShowSetup.cpp | 3 +- vpr/src/base/noc_data_types.h | 6 +- vpr/src/base/noc_link.cpp | 42 +- vpr/src/base/noc_link.h | 59 +- vpr/src/base/noc_router.cpp | 42 +- vpr/src/base/noc_router.h | 58 +- vpr/src/base/noc_storage.cpp | 129 +- vpr/src/base/noc_storage.h | 148 +- vpr/src/base/read_options.h | 3 +- vpr/src/base/setup_noc.cpp | 226 ++- vpr/src/base/setup_noc.h | 19 +- vpr/src/base/vpr_api.cpp | 18 +- vpr/src/base/vpr_api.h | 3 +- vpr/src/base/vpr_types.h | 4 +- vpr/src/draw/buttons.cpp | 11 +- vpr/src/draw/draw.cpp | 136 +- vpr/src/draw/draw_noc.cpp | 96 +- vpr/src/draw/draw_noc.h | 43 +- vpr/src/draw/draw_types.h | 12 +- vpr/test/test_noc_storage.cpp | 375 ++-- vpr/test/test_setup_noc.cpp | 1766 ++++++++--------- 25 files changed, 1739 insertions(+), 1882 deletions(-) diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index d10a3daf9a8..47a2fff04a6 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -1775,21 +1775,21 @@ struct t_lut_element { }; /* Network-on-chip(NoC) Router data type used to identify -connections regarding individual routers in the network. */ + * connections regarding individual routers in the network. */ struct t_router { int id = -1; double device_x_position = -1; double device_y_position = -1; - + std::vector connection_list; }; /* Network-on-chip(NoC) data type used to store the network -properties and used when builidng a dedicated on-chip network*/ + * properties and used when builidng a dedicated on-chip network*/ struct t_noc_inf { double link_bandwidth; // in Gbps - double link_latency; // in nanoseconds + double link_latency; // in nanoseconds double router_latency; // in nanoseconds std::vector router_list; diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index fe7db1c9827..0804da920c9 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -257,7 +257,7 @@ static void processTopology(pugi::xml_node topology_tag, const pugiutil::loc_dat static void processMeshTopology(pugi::xml_node mesh_topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref); -static void processRouter(pugi::xml_node router_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, std::map>&routers_info_in_arch); +static void processRouter(pugi::xml_node router_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, std::map>& routers_info_in_arch); static void ProcessPb_TypePowerEstMethod(pugi::xml_node Parent, t_pb_type* pb_type, const pugiutil::loc_data& loc_data); static void ProcessPb_TypePort_Power(pugi::xml_node Parent, t_port* port, e_power_estimation_method power_method, const pugiutil::loc_data& loc_data); @@ -276,11 +276,11 @@ static T* get_type_by_name(const char* type_name, std::vector& types); static void generate_noc_mesh(pugi::xml_node mesh_topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, double mesh_region_start_x, double mesh_region_end_x, double mesh_region_start_y, double mesh_region_end_y, int mesh_size); -static bool parse_noc_router_connection_list(std::vector& connection_list, std::string connection_list_attribute_value, std::map>&routers_in_arch_info); +static bool parse_noc_router_connection_list(std::vector& connection_list, std::string connection_list_attribute_value, std::map>& routers_in_arch_info); -static void update_router_info_in_arch(int router_id, bool router_updated_as_a_connection, std::map>&routers_in_arch_info); +static void update_router_info_in_arch(int router_id, bool router_updated_as_a_connection, std::map>& routers_in_arch_info); -static void verify_noc_topology(std::map>&routers_in_arch_info); +static void verify_noc_topology(std::map>& routers_in_arch_info); /* * @@ -448,7 +448,7 @@ void XmlReadArch(const char* ArchFile, // process NoC (optional) Next = get_single_child(architecture, "noc", loc_data, pugiutil::OPTIONAL); - if (Next){ + if (Next) { ProcessNoc(Next, arch, loc_data); } @@ -4536,16 +4536,15 @@ static void ProcessClocks(pugi::xml_node Parent, t_clock_arch* clocks, const pug /* get the next clock item */ Node = Node.next_sibling(Node.name()); } - - } - -static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc_data& loc_data) -{ +/* + * Get the NoC design + */ +static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc_data& loc_data) { // a vector representing all the possible attributes within the noc tag std::vector expected_noc_attributes = {"link_bandwidth", "link_latency", "router_latency", "noc_router_tile_name"}; - std::vector expected_noc_children_tags = {"mesh","topology"}; + std::vector expected_noc_children_tags = {"mesh", "topology"}; pugi::xml_node noc_topology; pugi::xml_node noc_mesh_topology; @@ -4575,17 +4574,15 @@ static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc noc_ref->noc_router_tile_name = pugiutil::get_attribute(noc_tag, "noc_router_tile_name", loc_data, pugiutil::REQUIRED).as_string(); // the noc parameters can only be non-zero positive values - if ((noc_ref->link_bandwidth < 0) || (noc_ref->link_latency < 0) || (noc_ref->router_latency < 0)) - { + if ((noc_ref->link_bandwidth < 0) || (noc_ref->link_latency < 0) || (noc_ref->router_latency < 0)) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(noc_tag), - "The link bandwidth, link latency and router latency for the NoC must be a positive non-zero value."); + "The link bandwidth, link latency and router latency for the NoC must be a positive non-zero value."); } // check that the router tile name was supplied properly - if (!(noc_ref->noc_router_tile_name.compare(attribute_conversion_failure_string))) - { + if (!(noc_ref->noc_router_tile_name.compare(attribute_conversion_failure_string))) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(noc_tag), - "The noc router tile name must be a string."); + "The noc router tile name must be a string."); } /* We processed the NoC node, so now process the topology*/ @@ -4598,24 +4595,19 @@ static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc // we cannot check for errors related to number of routers and as well as whether a router is out of bounds (this will be done later) // the chip still needs to be sized - if (noc_mesh_topology) - { - processMeshTopology(noc_mesh_topology, loc_data, noc_ref); + if (noc_mesh_topology) { + processMeshTopology(noc_mesh_topology, loc_data, noc_ref); - for (auto i = noc_ref->router_list.begin(); i != noc_ref->router_list.end(); i++) - { - std::cout << "router " << i->id << ": "; + for (auto i = noc_ref->router_list.begin(); i != noc_ref->router_list.end(); i++) { + std::cout << "router " << i->id << ": "; - for (auto j = i->connection_list.begin(); j != i->connection_list.end(); j++) - { - std::cout << *j << ","; - } + for (auto j = i->connection_list.begin(); j != i->connection_list.end(); j++) { + std::cout << *j << ","; + } - std::cout << "\n"; - } - } - else - { + std::cout << "\n"; + } + } else { noc_topology = pugiutil::get_single_child(noc_tag, "topology", loc_data, pugiutil::REQUIRED); processTopology(noc_topology, loc_data, noc_ref); @@ -4624,9 +4616,10 @@ static void ProcessNoc(pugi::xml_node noc_tag, t_arch* arch, const pugiutil::loc return; } -static void processMeshTopology(pugi::xml_node mesh_topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref) -{ - +/* + * A NoC mesh is created based on the user supplied size and region location. + */ +static void processMeshTopology(pugi::xml_node mesh_topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref) { // noc mesh topology properties double mesh_region_start_x = 0; double mesh_region_end_x = 0; @@ -4655,10 +4648,9 @@ static void processMeshTopology(pugi::xml_node mesh_topology_tag, const pugiutil mesh_size = pugiutil::get_attribute(mesh_topology_tag, "size", loc_data, pugiutil::REQUIRED).as_int(attribute_conversion_failure); // verify that the attrbiutes provided were legal - if (( mesh_region_start_x < 0) || (mesh_region_end_x < 0) || (mesh_region_start_y < 0) || (mesh_region_end_y < 0) || (mesh_size < 0)) - { + if ((mesh_region_start_x < 0) || (mesh_region_end_x < 0) || (mesh_region_start_y < 0) || (mesh_region_end_y < 0) || (mesh_size < 0)) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(mesh_topology_tag), - "The parameters for the mesh topology have to be positive values."); + "The parameters for the mesh topology have to be positive values."); } // now create the mesh topology for the noc @@ -4666,11 +4658,12 @@ static void processMeshTopology(pugi::xml_node mesh_topology_tag, const pugiutil generate_noc_mesh(mesh_topology_tag, loc_data, noc_ref, mesh_region_start_x, mesh_region_end_x, mesh_region_start_y, mesh_region_end_y, mesh_size); return; - } -static void processTopology(pugi::xml_node topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref) -{ +/* + * Go through each router in the NoC and store the list of routers that connect to it. + */ +static void processTopology(pugi::xml_node topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref) { // The topology tag should have no attributes, check that pugiutil::expect_only_attributes(topology_tag, {}, loc_data); @@ -4679,35 +4672,34 @@ static void processTopology(pugi::xml_node topology_tag, const pugiutil::loc_dat std::map> routers_in_arch_info; /* Now go through the children tags of topology, which is basically - each router found within the NoC - */ - for (pugi::xml_node router : topology_tag.children()) { - // we can only have router tags within the topology - if (router.name() != std::string("router")) { - bad_tag(router, loc_data, topology_tag, {"router"}); - } - else { - // curent tag is a valid router, so process it - processRouter(router, loc_data, noc_ref, routers_in_arch_info); - - } - } - - // check whether any routers were supplied - if (noc_ref->router_list.size() == 0) - { - archfpga_throw(loc_data.filename_c_str(), loc_data.line(topology_tag), - "No routers were supplied for the NoC."); - } - - // check that the topology of the noc was correctly described in the arch file - verify_noc_topology(routers_in_arch_info); + * each router found within the NoC + */ + for (pugi::xml_node router : topology_tag.children()) { + // we can only have router tags within the topology + if (router.name() != std::string("router")) { + bad_tag(router, loc_data, topology_tag, {"router"}); + } else { + // curent tag is a valid router, so process it + processRouter(router, loc_data, noc_ref, routers_in_arch_info); + } + } + + // check whether any routers were supplied + if (noc_ref->router_list.size() == 0) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(topology_tag), + "No routers were supplied for the NoC."); + } + + // check that the topology of the noc was correctly described in the arch file + verify_noc_topology(routers_in_arch_info); return; } -static void processRouter(pugi::xml_node router_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, std::map>&routers_in_arch_info) -{ +/* + * Store the properties of a single router and then store the list of routers that connect to it. + */ +static void processRouter(pugi::xml_node router_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, std::map>& routers_in_arch_info) { // identifier that lets us know when we could not properly convert an attribute value to a integer int attribute_conversion_failure = -1; @@ -4715,7 +4707,7 @@ static void processRouter(pugi::xml_node router_tag, const pugiutil::loc_data& l std::vector expected_router_attributes = {"id", "positionx", "positiony", "connections"}; // variable to store current router info - t_router router_info; + t_router router_info; // router connection list attribute information std::string router_connection_list_attribute_value; @@ -4735,9 +4727,8 @@ static void processRouter(pugi::xml_node router_tag, const pugiutil::loc_data& l // verify whether the attribute information was legal if ((router_info.id < 0) || (router_info.device_x_position < 0) || (router_info.device_y_position < 0)) { - archfpga_throw(loc_data.filename_c_str(), loc_data.line(router_tag), - "The router id, and position (x & y) for the router must be a positive number."); + "The router id, and position (x & y) for the router must be a positive number."); } // get the current router connection list @@ -4745,23 +4736,19 @@ static void processRouter(pugi::xml_node router_tag, const pugiutil::loc_data& l // if the connections attrbiute was not provided or it was empty, then we don't process it and throw a warning - if (router_connection_list_attribute_value.compare("") != 0) - { + if (router_connection_list_attribute_value.compare("") != 0) { // process the router connection list router_connection_list_result = parse_noc_router_connection_list(router_info.connection_list, router_connection_list_attribute_value, routers_in_arch_info); // check if the user provided a legal router connection list - if (!router_connection_list_result) - { + if (!router_connection_list_result) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(router_tag), - "The 'connections' attribute for the router must be a list of integers seperated by spaces, where each integer represents a router id that the current router is connected to."); + "The 'connections' attribute for the router must be a list of integers seperated by spaces, where each integer represents a router id that the current router is connected to."); } - } - else - { + } else { VTR_LOGF_WARN(loc_data.filename_c_str(), loc_data.line(router_tag), - "The router with id:%d either has an empty 'connections' attrtibute or does not have any associated connections to other routers in the NoC.\n", router_info.id); + "The router with id:%d either has an empty 'connections' attrtibute or does not have any associated connections to other routers in the NoC.\n", router_info.id); } // at this point the current router information was completely legal, so we store the newly created router within the noc @@ -4837,85 +4824,77 @@ static T* get_type_by_name(const char* type_name, std::vector& types) { "Could not find type: %s\n", type_name); } -static void generate_noc_mesh(pugi::xml_node mesh_topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, double mesh_region_start_x, double mesh_region_end_x, double mesh_region_start_y, double mesh_region_end_y, int mesh_size) -{ - +/* + * Create routers and set their properties so that a mesh grid of routers is created. Then connect the routers together so that a mesh topology is created. + */ +static void generate_noc_mesh(pugi::xml_node mesh_topology_tag, const pugiutil::loc_data& loc_data, t_noc_inf* noc_ref, double mesh_region_start_x, double mesh_region_end_x, double mesh_region_start_y, double mesh_region_end_y, int mesh_size) { // check that the mesh size of the router is not 0 - if (mesh_size == 0) - { + if (mesh_size == 0) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(mesh_topology_tag), - "The NoC mesh size cannot be 0."); + "The NoC mesh size cannot be 0."); } - // calculating the vertical horizontal distances between routers in the supplied region // we decrease the mesh size by 1 when calculating the spacing so that the first and last routers of each row or column are positioned on the mesh boundary /* - For example: - - If we had a mesh size of 3, then using 3 would result in a spacing that would result in one router positions being placed in either the start of the reigion or end of the region. This is because the distance calculation resulted in having 3 spaces between the ends of the region - - start end - *** *** *** *** - - - if we instead used 2 in the distance calculation, the the resulting positions would result in having 2 routers positioned on the start and end of the region. This is beacuse we now specified 2 spaces between the region and this allows us to place 2 routers on the regions edges and one router in the center. - - start end - *** *** *** - - THe reasoning for this is to reduce the number of calculated router positions. - */ - double vertical_router_seperation = (mesh_region_end_y - mesh_region_start_y)/(mesh_size - 1); - double horizontal_router_seperation = (mesh_region_end_x - mesh_region_start_x)/(mesh_size - 1); + * For example: + * - If we had a mesh size of 3, then using 3 would result in a spacing that would result in one router positions being placed in either the start of the reigion or end of the region. This is because the distance calculation resulted in having 3 spaces between the ends of the region + * + * start end + *** *** *** *** + * + * - if we instead used 2 in the distance calculation, the the resulting positions would result in having 2 routers positioned on the start and end of the region. This is beacuse we now specified 2 spaces between the region and this allows us to place 2 routers on the regions edges and one router in the center. + * + * start end + *** *** *** + * + * THe reasoning for this is to reduce the number of calculated router positions. + */ + double vertical_router_seperation = (mesh_region_end_y - mesh_region_start_y) / (mesh_size - 1); + double horizontal_router_seperation = (mesh_region_end_x - mesh_region_start_x) / (mesh_size - 1); t_router temp_router; // improper region check - if ( (vertical_router_seperation <= 0) || (horizontal_router_seperation <= 0)) - { + if ((vertical_router_seperation <= 0) || (horizontal_router_seperation <= 0)) { archfpga_throw(loc_data.filename_c_str(), loc_data.line(mesh_topology_tag), - "The NoC region is invalid."); + "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++) - { + 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_seperation) + mesh_region_start_x; temp_router.device_y_position = (j * vertical_router_seperation) + mesh_region_start_y; // assign connections // check if there is a router to the left - if ((i - 1) >= 0) - { + if ((i - 1) >= 0) { // add the left router as a connection temp_router.connection_list.push_back((mesh_size * j) + i - 1); } - + // check if there is a router to the top - if ((j + 1) <= (mesh_size - 1)) - { + if ((j + 1) <= (mesh_size - 1)) { // add the top router as a connection temp_router.connection_list.push_back((mesh_size * (j + 1)) + i); } // check if there is a router to the right - if ((i + 1) <= (mesh_size - 1)) - { + if ((i + 1) <= (mesh_size - 1)) { // add the router located to the right temp_router.connection_list.push_back((mesh_size * j) + i + 1); } // check of there is a router below - if ((j - 1) >= (0)) - { + if ((j - 1) >= (0)) { // add the bottom router as a connection temp_router.connection_list.push_back((mesh_size * (j - 1)) + i); } @@ -4925,30 +4904,33 @@ static void generate_noc_mesh(pugi::xml_node mesh_topology_tag, const pugiutil:: // clear the current router information for the next router temp_router.connection_list.clear(); - } } return; - } -static bool parse_noc_router_connection_list(std::vector& connection_list, std::string connection_list_attribute_value, std::map>&routers_in_arch_info) -{ +/* + * THe user provides the list of routers any given router is connected to by the router ids seperated by spaces. For example: + * + * connections= 1 2 3 4 5 + * + * Go through the connections here and store them. Also make sure the list is legal. + */ +static bool parse_noc_router_connection_list(std::vector& connection_list, std::string connection_list_attribute_value, std::map>& routers_in_arch_info) { // we wil be modifying the string so store it in a temporary variable // additinally, we peocess substrings seperated by spaces, so we add a space at the end of the string to be able to process the last sub-string - std::string modified_attribute_value= connection_list_attribute_value + " "; + std::string modified_attribute_value = connection_list_attribute_value + " "; std::string delimiter = " "; std::stringstream single_connection; int converted_connection; size_t position = 0; - + bool result = true; // find the position of the first space in the connection list string - while ((position = modified_attribute_value.find(delimiter)) != std::string::npos) - { + while ((position = modified_attribute_value.find(delimiter)) != std::string::npos) { // the string upto the space represent a single connection, so grab the substring single_connection << modified_attribute_value.substr(0, position); @@ -4956,19 +4938,17 @@ static bool parse_noc_router_connection_list(std::vector& connection_list, single_connection >> converted_connection; /* we expect the connection list to be a string of integers seperated by spaces, where each integer represents a router id that the current router is connected to. So we make sure that the router id was an integer. - */ - if (single_connection.fail()) - { - // if we are here, then an integer was not supplied - result = false; - break; - } + */ + if (single_connection.fail()) { + // if we are here, then an integer was not supplied + result = false; + break; + } // check the case where a duplicate connection was provided - if (std::find(connection_list.begin(), connection_list.end(), converted_connection) != connection_list.end()) - { - archfpga_throw("",-1, - "The router with id:'%d' was included multiple times in the connection list for another router.", converted_connection); + if (std::find(connection_list.begin(), connection_list.end(), converted_connection) != connection_list.end()) { + archfpga_throw("", -1, + "The router with id:'%d' was included multiple times in the connection list for another router.", converted_connection); } // if we are here then a legal router id was supplied, so store it @@ -4985,81 +4965,64 @@ static bool parse_noc_router_connection_list(std::vector& connection_list, } return result; - } /* Each router needs a sperate tag in the architecture description - to declare it. The number of declarations for each router in the - architecture file is updated here. - - Additionally, for any given topology, a router can connect to other routers. - THe number of connections for each router is also updated here. - -*/ -static void update_router_info_in_arch(int router_id, bool router_updated_as_a_connection, std::map>&routers_in_arch_info) { - + * to declare it. The number of declarations for each router in the + * architecture file is updated here. + * + * Additionally, for any given topology, a router can connect to other routers. + * THe number of connections for each router is also updated here. + * + */ +static void update_router_info_in_arch(int router_id, bool router_updated_as_a_connection, std::map>& routers_in_arch_info) { // get the corresponding router info for the given router id std::map>::iterator curr_router_info = routers_in_arch_info.find(router_id); // check if the router previously existed in the router indo database if (curr_router_info == routers_in_arch_info.end()) { - // case where the router did not exist previosuly, so we add it here and also get a reference to it // initially a router has no declarations or connections curr_router_info = routers_in_arch_info.insert(std::pair>(router_id, std::pair(0, 0))).first; - } - + // case where the current router was provided while parsing the connections of another router if (router_updated_as_a_connection) { - // since we are within the case where the current router is being processed as a connection to another router we just increment its number of connections (curr_router_info->second.second)++; - } - else { - + } else { // since we are within the case where the current router is processed from a tag, we just increment its number of declarations (curr_router_info->second.first)++; - } return; - } /* - Verify each router in the noc by checking whether they satisfy the following conditions: - - The router has only one declaration in the arch file - - The router has atleast one connection to another router - If any of the conditions above are not met, then an error is thrown. -*/ -static void verify_noc_topology(std::map>&routers_in_arch_info) -{ - - for (auto router_info = routers_in_arch_info.begin(); router_info != routers_in_arch_info.end(); router_info++) - { + * Verify each router in the noc by checking whether they satisfy the following conditions: + * - The router has only one declaration in the arch file + * - The router has atleast one connection to another router + * If any of the conditions above are not met, then an error is thrown. + */ +static void verify_noc_topology(std::map>& routers_in_arch_info) { + for (auto router_info = routers_in_arch_info.begin(); router_info != routers_in_arch_info.end(); router_info++) { // case where the router was included in the architecture and had no connections to other routers if ((router_info->second.first == 1) && (router_info->second.second == 0)) { - - archfpga_throw("",-1, - "The router with id:'%d' is not connected to any other router in the NoC.", router_info->first); - - } // case where a router was found to be connected to another router but not declared using the tag in the arch file (ie. missing) - else if ((router_info->second.first == 0) && (router_info->second.second > 0)){ + archfpga_throw("", -1, + "The router with id:'%d' is not connected to any other router in the NoC.", router_info->first); - archfpga_throw("",-1, - "The router with id:'%d' was found to be connected to another router but missing in the architecture file. Add the router using the tag.", router_info->first); + } // case where a router was found to be connected to another router but not declared using the tag in the arch file (ie. missing) + else if ((router_info->second.first == 0) && (router_info->second.second > 0)) { + archfpga_throw("", -1, + "The router with id:'%d' was found to be connected to another router but missing in the architecture file. Add the router using the tag.", router_info->first); } // case where the router was delcared multiple times in the architecture file (multiple tags for the same router) - else if (router_info->second.first > 1){ - - archfpga_throw("",-1, - "The router with id:'%d' was included more than once in the architecture file. Routers should only be declared once.", router_info->first); - + else if (router_info->second.first > 1) { + archfpga_throw("", -1, + "The router with id:'%d' was included more than once in the architecture file. Routers should only be declared once.", router_info->first); } } return; - } diff --git a/libs/libarchfpga/test/test_read_xml_arch_file.cpp b/libs/libarchfpga/test/test_read_xml_arch_file.cpp index 1ca75f959a8..adc9eab42d1 100644 --- a/libs/libarchfpga/test/test_read_xml_arch_file.cpp +++ b/libs/libarchfpga/test/test_read_xml_arch_file.cpp @@ -8,21 +8,19 @@ // for comparing floats #include "vtr_math.h" -TEST_CASE( "Updating router info in arch", "[NoC Arch Tests]" ) { - +TEST_CASE("Updating router info in arch", "[NoC Arch Tests]") { std::map> test_router_list; std::map>::iterator it; - // initial conditions + // initial conditions int router_id = 1; bool router_is_from_connection_list = false; // we initially need the map to be empty REQUIRE(test_router_list.size() == 0); - SECTION( "Update the number of declarations for a router for the first time " ) { - + SECTION("Update the number of declarations for a router for the first time ") { update_router_info_in_arch(router_id, router_is_from_connection_list, test_router_list); it = test_router_list.find(router_id); @@ -33,10 +31,8 @@ TEST_CASE( "Updating router info in arch", "[NoC Arch Tests]" ) { // no verify the components of the router parameter REQUIRE(it->second.first == 1); REQUIRE(it->second.second == 0); - } - SECTION( "Update the number of connections for a router for the first time" ) { - + SECTION("Update the number of connections for a router for the first time") { router_is_from_connection_list = true; update_router_info_in_arch(router_id, router_is_from_connection_list, test_router_list); @@ -49,10 +45,8 @@ TEST_CASE( "Updating router info in arch", "[NoC Arch Tests]" ) { // no verify the components of the router parameter REQUIRE(it->second.first == 0); REQUIRE(it->second.second == 1); - } - SECTION( "Update the number of declarations for a router when it already exists" ) { - + SECTION("Update the number of declarations for a router when it already exists") { update_router_info_in_arch(router_id, router_is_from_connection_list, test_router_list); // verify that a router was added @@ -68,10 +62,8 @@ TEST_CASE( "Updating router info in arch", "[NoC Arch Tests]" ) { // no verify the components of the router parameter REQUIRE(it->second.first == 2); REQUIRE(it->second.second == 0); - } - SECTION( "Update the number of connections for a router when it already exists" ) { - + SECTION("Update the number of connections for a router when it already exists") { router_is_from_connection_list = true; update_router_info_in_arch(router_id, router_is_from_connection_list, test_router_list); @@ -89,75 +81,65 @@ TEST_CASE( "Updating router info in arch", "[NoC Arch Tests]" ) { // no verify the components of the router parameter REQUIRE(it->second.first == 0); REQUIRE(it->second.second == 2); - } - } -TEST_CASE( "Verifying a parsed NoC topology", "[NoC Arch Tests]" ) { - +TEST_CASE("Verifying a parsed NoC topology", "[NoC Arch Tests]") { std::map> test_router_list; REQUIRE(test_router_list.size() == 0); - SECTION( "Check the error where a router in the NoC is not connected to other routers." ) { - + SECTION("Check the error where a router in the NoC is not connected to other routers.") { // error router - test_router_list.insert(std::pair>(1, std::pair(1,0))); + test_router_list.insert(std::pair>(1, std::pair(1, 0))); // sonme normal routers - test_router_list.insert(std::pair>(2, std::pair(1,5))); + test_router_list.insert(std::pair>(2, std::pair(1, 5))); - test_router_list.insert(std::pair>(3, std::pair(1,6))); + test_router_list.insert(std::pair>(3, std::pair(1, 6))); REQUIRE(test_router_list.size() == 3); REQUIRE_THROWS_WITH(verify_noc_topology(test_router_list), "The router with id:'1' is not connected to any other router in the NoC."); - } - SECTION( "Check the error where a router in the NoC is connected to other routers but missing a declaration in the arch file." ) { - + SECTION("Check the error where a router in the NoC is connected to other routers but missing a declaration in the arch file.") { // normal routers - test_router_list.insert(std::pair>(1, std::pair(1,5))); + test_router_list.insert(std::pair>(1, std::pair(1, 5))); - test_router_list.insert(std::pair>(2, std::pair(1,3))); + test_router_list.insert(std::pair>(2, std::pair(1, 3))); // error router - test_router_list.insert(std::pair>(3, std::pair(0,5))); + test_router_list.insert(std::pair>(3, std::pair(0, 5))); - test_router_list.insert(std::pair>(4, std::pair(1,10))); + test_router_list.insert(std::pair>(4, std::pair(1, 10))); REQUIRE(test_router_list.size() == 4); REQUIRE_THROWS_WITH(verify_noc_topology(test_router_list), "The router with id:'3' was found to be connected to another router but missing in the architecture file. Add the router using the tag."); - } - SECTION( "Check the error where the router is included more than once in the architecture file." ) { - + SECTION("Check the error where the router is included more than once in the architecture file.") { // normal routers - test_router_list.insert(std::pair>(1, std::pair(1,5))); + test_router_list.insert(std::pair>(1, std::pair(1, 5))); - test_router_list.insert(std::pair>(2, std::pair(1,3))); + test_router_list.insert(std::pair>(2, std::pair(1, 3))); - test_router_list.insert(std::pair>(3, std::pair(1,10))); + test_router_list.insert(std::pair>(3, std::pair(1, 10))); // error routers - test_router_list.insert(std::pair>(4, std::pair(2,10))); + test_router_list.insert(std::pair>(4, std::pair(2, 10))); // normal routers - test_router_list.insert(std::pair>(5, std::pair(1,3))); + test_router_list.insert(std::pair>(5, std::pair(1, 3))); - test_router_list.insert(std::pair>(6, std::pair(1,10))); + test_router_list.insert(std::pair>(6, std::pair(1, 10))); REQUIRE(test_router_list.size() == 6); REQUIRE_THROWS_WITH(verify_noc_topology(test_router_list), "The router with id:'4' was included more than once in the architecture file. Routers should only be declared once."); - } } -TEST_CASE ("Verifying mesh topology creation", "[NoC Arch Tests]") { - +TEST_CASE("Verifying mesh topology creation", "[NoC Arch Tests]") { // data for the xml parsing pugi::xml_node test; pugiutil::loc_data test_location; @@ -165,7 +147,6 @@ TEST_CASE ("Verifying mesh topology creation", "[NoC Arch Tests]") { // the noc storage t_noc_inf test_noc; - // mesh parameters double mesh_start_x = 10; double mesh_start_y = 10; @@ -173,19 +154,15 @@ TEST_CASE ("Verifying mesh topology creation", "[NoC Arch Tests]") { double mesh_end_y = 56; double mesh_size = 0; - SECTION( "Check the error where a mesh size was illegal." ) { - + SECTION("Check the error where a mesh size was illegal.") { REQUIRE_THROWS_WITH(generate_noc_mesh(test, test_location, &test_noc, mesh_start_x, mesh_end_x, mesh_start_y, mesh_end_y, mesh_size), "The NoC mesh size cannot be 0."); - } - SECTION( "Check the error where a mesh region size was invalid." ) { - + SECTION("Check the error where a mesh region size was invalid.") { mesh_size = 3; REQUIRE_THROWS_WITH(generate_noc_mesh(test, test_location, &test_noc, mesh_start_x, mesh_end_x, mesh_start_y, mesh_end_y, mesh_size), "The NoC region is invalid."); } - SECTION( "Check the mesh creation for integer precision coordinates." ) { - + SECTION("Check the mesh creation for integer precision coordinates.") { // define test parameters mesh_size = 3; @@ -226,8 +203,7 @@ TEST_CASE ("Verifying mesh topology creation", "[NoC Arch Tests]") { generate_noc_mesh(test, test_location, &test_noc, mesh_start_x, mesh_end_x, mesh_start_y, mesh_end_y, mesh_size); // go through all the expected routers - for (int expected_router_id = 0; expected_router_id < (mesh_size * mesh_size); expected_router_id++) - { + for (int expected_router_id = 0; expected_router_id < (mesh_size * mesh_size); expected_router_id++) { // make sure the router ids match REQUIRE(test_noc.router_list[expected_router_id].id == expected_router_id); @@ -238,8 +214,7 @@ TEST_CASE ("Verifying mesh topology creation", "[NoC Arch Tests]") { REQUIRE(golden_results_y[expected_router_id] == test_noc.router_list[expected_router_id].device_y_position); } } - SECTION( "Check the mesh creation for double precision coordinates." ) { - + SECTION("Check the mesh creation for double precision coordinates.") { // define test parameters mesh_size = 3; @@ -249,7 +224,6 @@ TEST_CASE ("Verifying mesh topology creation", "[NoC Arch Tests]") { mesh_end_x = 10.8; mesh_end_y = 6.4; - // create the golden golden results double golden_results_x[9]; double golden_results_y[9]; @@ -281,8 +255,7 @@ TEST_CASE ("Verifying mesh topology creation", "[NoC Arch Tests]") { generate_noc_mesh(test, test_location, &test_noc, mesh_start_x, mesh_end_x, mesh_start_y, mesh_end_y, mesh_size); // go through all the expected routers - for (int expected_router_id = 0; expected_router_id < (mesh_size * mesh_size); expected_router_id++) - { + for (int expected_router_id = 0; expected_router_id < (mesh_size * mesh_size); expected_router_id++) { // make sure the router ids match REQUIRE(test_noc.router_list[expected_router_id].id == expected_router_id); diff --git a/vpr/src/base/SetupVPR.cpp b/vpr/src/base/SetupVPR.cpp index cccc195f754..52e7670c7ed 100644 --- a/vpr/src/base/SetupVPR.cpp +++ b/vpr/src/base/SetupVPR.cpp @@ -36,7 +36,7 @@ static void SetupAnnealSched(const t_options& Options, t_annealing_sched* AnnealSched); static void SetupRouterOpts(const t_options& Options, t_router_opts* RouterOpts); static void SetupNocOpts(const t_options& Options, - t_noc_opts* NocOpts); + t_noc_opts* NocOpts); static void SetupRoutingArch(const t_arch& Arch, t_det_routing_arch* RoutingArch); static void SetupTiming(const t_options& Options, const bool TimingEnabled, t_timing_inf* Timing); static void SetupSwitches(const t_arch& Arch, @@ -659,8 +659,10 @@ static void SetupPowerOpts(const t_options& Options, t_power_opts* power_opts, t } } +/* + * Go through all the NoC options supplied by the user and store them internally. + */ static void SetupNocOpts(const t_options& Options, t_noc_opts* NocOpts) { - // assign the noc specific options from the command line NocOpts->noc = Options.noc; diff --git a/vpr/src/base/ShowSetup.cpp b/vpr/src/base/ShowSetup.cpp index cc49576f2f3..d2570f1f4cb 100644 --- a/vpr/src/base/ShowSetup.cpp +++ b/vpr/src/base/ShowSetup.cpp @@ -769,8 +769,7 @@ static void ShowPackerOpts(const t_packer_opts& PackerOpts) { VTR_LOG("\n"); } -static void ShowNocOpts(const t_noc_opts& NocOpts) -{ +static void ShowNocOpts(const t_noc_opts& NocOpts) { // show options such as routing algorithm used // name of the flows file // etc... diff --git a/vpr/src/base/noc_data_types.h b/vpr/src/base/noc_data_types.h index 0f0a9e29ba9..ba6962dea6b 100644 --- a/vpr/src/base/noc_data_types.h +++ b/vpr/src/base/noc_data_types.h @@ -1,16 +1,14 @@ #ifndef NOC_DATA_TYPES_H #define NOC_DATA_TYPES_H - #include "vtr_strong_id.h" - // definitins data types used to index the routers and links within the noc struct noc_router_id_tag; struct noc_link_id_tag; -typedef vtr::StrongId NocRouterId; -typedef vtr::StrongId NocLinkId; +typedef vtr::StrongId NocRouterId; +typedef vtr::StrongId NocLinkId; #endif \ No newline at end of file diff --git a/vpr/src/base/noc_link.cpp b/vpr/src/base/noc_link.cpp index e11f707e4f0..7655dc7e9a4 100644 --- a/vpr/src/base/noc_link.cpp +++ b/vpr/src/base/noc_link.cpp @@ -1,39 +1,55 @@ -#include "noc_link.h" +/* + * The NocLink defines a connection between two routers in the NoC. + * The NocLink contains the following information: + * - The source router and destination router the link connects + * - The number of seperate traffic flows that use the link. By + * flows, this is when a router in the NoC transmits information + * to another router in the NoC and the link was used within the + * communication path between both routers. + * - The bandwidth usage of the link. When a link is used within a + * traffic flow, each link in the communication path needs to + * support a predefined bandwidth of the flow. Every time a link + * is used in a flow, its bandwidth usage increases based on the + * bandwidth needed by this link. This is useful to track as it + * can indicate when a link is bein overused (the bandwidth usage + * exceeds the links supported capability). + * There are also a number of functions defined here that can be used + * to access the above information or modify them. + */ +#include "noc_link.h" -// this represents a link in the NoC -NocLink::NocLink(NocRouterId source, NocRouterId sink):source_router(source), sink_router(sink) -{ +// constructor +NocLink::NocLink(NocRouterId source, NocRouterId sink) + : source_router(source) + , sink_router(sink) { // initialize variables bandwidth_usage = 0.0; number_of_connections = 0; - } // getters -NocRouterId NocLink::get_source_router(void) const{ +NocRouterId NocLink::get_source_router(void) const { return source_router; } -NocRouterId NocLink::get_sink_router(void) const{ +NocRouterId NocLink::get_sink_router(void) const { return sink_router; } -double NocLink::get_bandwidth_usage(void) const{ +double NocLink::get_bandwidth_usage(void) const { return bandwidth_usage; } -int NocLink::get_number_of_connections(void) const{ +int NocLink::get_number_of_connections(void) const { return number_of_connections; } //setters -void NocLink::set_bandwidth_usage(double new_bandwidth_usage) -{ +void NocLink::set_bandwidth_usage(double new_bandwidth_usage) { bandwidth_usage = new_bandwidth_usage; } -void NocLink::set_number_of_connections(int new_number_of_connections) -{ +void NocLink::set_number_of_connections(int new_number_of_connections) { number_of_connections = new_number_of_connections; } \ No newline at end of file diff --git a/vpr/src/base/noc_link.h b/vpr/src/base/noc_link.h index 4467452b255..90d021ff9f4 100644 --- a/vpr/src/base/noc_link.h +++ b/vpr/src/base/noc_link.h @@ -1,44 +1,45 @@ #ifndef NOC_LINK_H #define NOC_LINK_H +/* + * The NocLink class description header file. + * + * The NocLink class describes a connection between two + * routers (NocRouters). This file contains the definition + * of what a NocLink object is. This includes the properties + * of a link and a set of functions to access and modify the + * properties. + * + */ + #include #include "noc_router.h" #include "noc_data_types.h" +class NocLink { + private: + // the two routers that are connected by this link + NocRouterId source_router; + NocRouterId sink_router; -class NocLink -{ - private: - // the two routers that are connected by this link - NocRouterId source_router; - NocRouterId sink_router; - - double bandwidth_usage; + double bandwidth_usage; - // represents the number of routed communication paths between routers that use - // this link. Congestion is proportional to this variable. - int number_of_connections; + // represents the number of routed communication paths between routers that use + // this link Congestion is proportional to this variable. + int number_of_connections; - public: - NocLink(NocRouterId source_router, NocRouterId sink_router); + public: + NocLink(NocRouterId source_router, NocRouterId sink_router); - // getters - NocRouterId get_source_router(void) const; - NocRouterId get_sink_router(void) const; - double get_bandwidth_usage(void) const; - int get_number_of_connections(void) const; - - // setters - void set_bandwidth_usage(double new_bandwidth_usage); - void set_number_of_connections(int new_number_of_connections); + // getters + NocRouterId get_source_router(void) const; + NocRouterId get_sink_router(void) const; + double get_bandwidth_usage(void) const; + int get_number_of_connections(void) const; + // setters + void set_bandwidth_usage(double new_bandwidth_usage); + void set_number_of_connections(int new_number_of_connections); }; - - - - - - - #endif \ No newline at end of file diff --git a/vpr/src/base/noc_router.cpp b/vpr/src/base/noc_router.cpp index 922bc72547f..789be80373f 100644 --- a/vpr/src/base/noc_router.cpp +++ b/vpr/src/base/noc_router.cpp @@ -1,32 +1,56 @@ -#include "noc_router.h" +/* + * The NocRouter defines a router in the NoC. + * The NocRouter contains the following information: + * - The router id. This represents the unique ID given by the + * user in the architecture description file when describing a + * router. THe purpose of this is to help the user identify the + * router when loggin information or displaying errors. + * - The grid position of the physical router tile this object + * represents. Each router in the NoC represents a physical router + * tile in the FPGA device. By storing the grid positions, we can quickly + * get the corresponding physical router tile information by seaching + * the DeviceGrid in the device context. + * - The design module currently occupying this tile. Within the user + * design there will be a number of instations of NoC routers. The user + * will also provide information about which routers modules will be + * communication with each other. During placement, it is possible for + * the router modules to move between the physical router tiles, so + * by storing the module reference, we can determine which physical router tiles are communicating between each other and find a router + * between them. + * There are also a number of functions defined here that can be used + * to access the above information or modify them. + */ +#include "noc_router.h" -NocRouter::NocRouter(int id, int grid_position_x, int grid_position_y):router_id(id), router_grid_position_x(grid_position_x), router_grid_position_y(grid_position_y) -{ +// constructor +NocRouter::NocRouter(int id, int grid_position_x, int grid_position_y) + : router_id(id) + , router_grid_position_x(grid_position_x) + , router_grid_position_y(grid_position_y) { // initialize variables router_design_module_ref = ""; } // getters -int NocRouter::get_router_id(void) const{ +int NocRouter::get_router_id(void) const { return router_id; } -int NocRouter::get_router_grid_position_x(void) const{ +int NocRouter::get_router_grid_position_x(void) const { return router_grid_position_x; } -int NocRouter::get_router_grid_position_y(void) const{ +int NocRouter::get_router_grid_position_y(void) const { return router_grid_position_y; } -std::string NocRouter::get_router_design_module_ref(void) const{ +std::string NocRouter::get_router_design_module_ref(void) const { return router_design_module_ref; } // setters -void NocRouter::set_router_design_module_ref(std::string design_module_ref) -{ +void NocRouter::set_router_design_module_ref(std::string design_module_ref) { router_design_module_ref.assign(design_module_ref); return; diff --git a/vpr/src/base/noc_router.h b/vpr/src/base/noc_router.h index b0761c5e5c9..9227b6a4e1d 100644 --- a/vpr/src/base/noc_router.h +++ b/vpr/src/base/noc_router.h @@ -1,49 +1,43 @@ #ifndef NOC_ROUTER_H #define NOC_ROUTER_H +/* + * The NocRouter class description header file. + * + * The NocRouter class describes a router in the NoC. This file contains the definition of what a NocRouter object is. This includes the properties + * of a router and a set of functions to access and modify the + * properties. + * + */ + #include #include // this represents a physical router on the chip class NocRouter { + private: + // this represents the id provided by the user when describing + // the NoC in the architecture description file + int router_id; + int router_grid_position_x; + int router_grid_position_y; - private: - // this represents the id provided by the user when describing - // the NoC in the architecture description file - int router_id; - int router_grid_position_x; - int router_grid_position_y; - - // atom id and clustering block id can be used to identigy which router moduleswe are using - // atom id is faster than string - std::string router_design_module_ref; - - // traffic flow information will be providedin an input file through - // module names and how the trffic flows between them - - public: - NocRouter(int id, int grid_position_x, int grid_position_y); + // atom id and clustering block id can be used to identify which router modules the current router represents + // atom id is faster than string + std::string router_design_module_ref; - int get_router_id(void) const; - int get_router_grid_position_x(void) const; - int get_router_grid_position_y(void) const; - - std::string get_router_design_module_ref(void) const; - - // setters - void set_router_design_module_ref(std::string design_module_ref); + public: + NocRouter(int id, int grid_position_x, int grid_position_y); + int get_router_id(void) const; + int get_router_grid_position_x(void) const; + int get_router_grid_position_y(void) const; + std::string get_router_design_module_ref(void) const; + // setters + void set_router_design_module_ref(std::string design_module_ref); }; - - - - - - - - #endif \ No newline at end of file diff --git a/vpr/src/base/noc_storage.cpp b/vpr/src/base/noc_storage.cpp index c7077388945..140d822b04c 100644 --- a/vpr/src/base/noc_storage.cpp +++ b/vpr/src/base/noc_storage.cpp @@ -1,90 +1,90 @@ +/* + * The NocStorage defines the embedded NoC in the FPGA device. + * The NocStorage contains the following information: + * - A list of all the routers in the NoC (NocRouter objects) + * - A list of all the links in the NoC (NocLink objects) + * - A connections list for each router. This is simply a list + * of outgoing links of each router. + * There are also a number of functions defined here that can be used + * to access the above information or modify them. + */ + #include "noc_storage.h" -// clear all the graph data structures +// clear all the graph data structures NocStorage::NocStorage() { - clear_noc(); } // getters for the NoC // get the outgoing links for a router in the NoC -const std::vector& NocStorage::get_noc_router_connections(NocRouterId id) const{ - +const std::vector& NocStorage::get_noc_router_connections(NocRouterId id) const { return router_link_list[id]; - } -const vtr::vector& NocStorage::get_noc_routers(void) const{ - +// get the list of all routers in the NoC +const vtr::vector& NocStorage::get_noc_routers(void) const { return router_storage; } -const vtr::vector& NocStorage::get_noc_links(void) const{ - +// get the list of all links in the NoC +const vtr::vector& NocStorage::get_noc_links(void) const { return link_storage; } -int NocStorage::get_noc_router_grid_position_x(NocRouterId id) const{ - +// get router properties +int NocStorage::get_noc_router_grid_position_x(NocRouterId id) const { return router_storage[id].get_router_grid_position_x(); } -int NocStorage::get_noc_router_grid_position_y(NocRouterId id) const{ - +int NocStorage::get_noc_router_grid_position_y(NocRouterId id) const { return router_storage[id].get_router_grid_position_y(); } -int NocStorage::get_noc_router_id(NocRouterId id) const{ - +int NocStorage::get_noc_router_id(NocRouterId id) const { return router_storage[id].get_router_id(); } -std::string NocStorage::get_noc_router_design_module_ref(NocRouterId id) const{ - +std::string NocStorage::get_noc_router_design_module_ref(NocRouterId id) const { return router_storage[id].get_router_design_module_ref(); } -NocRouterId NocStorage::get_noc_link_source_router(NocLinkId id) const{ - +// get link properties +NocRouterId NocStorage::get_noc_link_source_router(NocLinkId id) const { return link_storage[id].get_source_router(); } -NocRouterId NocStorage::get_noc_link_sink_router(NocLinkId id) const{ - +NocRouterId NocStorage::get_noc_link_sink_router(NocLinkId id) const { return link_storage[id].get_sink_router(); } -double NocStorage::get_noc_link_bandwidth_usage(NocLinkId id) const{ - +double NocStorage::get_noc_link_bandwidth_usage(NocLinkId id) const { return link_storage[id].get_bandwidth_usage(); } -int NocStorage::get_noc_link_number_of_connections(NocLinkId id) const{ - +int NocStorage::get_noc_link_number_of_connections(NocLinkId id) const { return link_storage[id].get_number_of_connections(); } -void NocStorage::add_router(int id, int grid_position_x, int grid_posistion_y){ - +void NocStorage::add_router(int id, int grid_position_x, int grid_posistion_y) { VTR_ASSERT_MSG(!built_noc, "NoC already built, cannot modify further."); - + router_storage.emplace_back(id, grid_position_x, grid_posistion_y); /* Get the corresponding NocRouterId for the newly added router and - add it to the conversion table. - Since the router is added at the end of the list, the id is equivalent to the last element index. - We build the conversion table here as it gurantees only unique routers - in the NoC are added. - */ + * add it to the conversion table. + * Since the router is added at the end of the list, the id is equivalent to the last element index. + * We build the conversion table here as it gurantees only unique routers + * in the NoC are added. + */ NocRouterId converted_id((int)(router_storage.size() - 1)); router_id_conversion_table.emplace(id, converted_id); return; } -void NocStorage::add_link(NocRouterId source, NocRouterId sink){ - +void NocStorage::add_link(NocRouterId source, NocRouterId sink) { VTR_ASSERT_MSG(!built_noc, "NoC already built, cannot modify further."); link_storage.emplace_back(source, sink); @@ -95,37 +95,37 @@ void NocStorage::add_link(NocRouterId source, NocRouterId sink){ return; } -void NocStorage::set_noc_router_design_module_ref(NocRouterId id, std::string design_module_ref){ - +// set router properties +void NocStorage::set_noc_router_design_module_ref(NocRouterId id, std::string design_module_ref) { router_storage[id].set_router_design_module_ref(design_module_ref); return; } -void NocStorage::set_noc_link_bandwidth_usage(NocLinkId id, double bandwidth_usage){ - +// set link properties +void NocStorage::set_noc_link_bandwidth_usage(NocLinkId id, double bandwidth_usage) { link_storage[id].set_bandwidth_usage(bandwidth_usage); return; } -void NocStorage::set_noc_link_number_of_connections(NocLinkId id, int number_of_connections){ - +void NocStorage::set_noc_link_number_of_connections(NocLinkId id, int number_of_connections) { link_storage[id].set_number_of_connections(number_of_connections); return; } -void NocStorage::finished_building_noc(void){ - +// assert the flag that indicates whether the noc was built or not +// Once this function is called, the NoC cannot be modified further. +// THis is useful as it ensured the NoC is only modified initially when it is built +void NocStorage::finished_building_noc(void) { VTR_ASSERT_MSG(!built_noc, "NoC already built, cannot modify further."); built_noc = true; return; } -void NocStorage::clear_noc(void){ - +void NocStorage::clear_noc(void) { router_storage.clear(); link_storage.clear(); router_link_list.clear(); @@ -135,48 +135,53 @@ void NocStorage::clear_noc(void){ return; } -NocRouterId NocStorage::convert_router_id(int id) const{ - +/* + * The router IDs provided by the user cannot be used to + * identify the routers inside NocStorage. So, the router ids + * are converted to a NocRouterId that can be used to quickly identify + * a router. When given a router id, it can be converted to the corresponding + * NocRouterId here. + * + */ +NocRouterId NocStorage::convert_router_id(int id) const { std::unordered_map::const_iterator result = router_id_conversion_table.find(id); - if (result == router_id_conversion_table.end()) - { + if (result == router_id_conversion_table.end()) { VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Cannot convert router with id:%d. The router was not found within the NoC.", id); } return result->second; - } -void NocStorage::make_room_for_noc_router_link_list(){ - +void NocStorage::make_room_for_noc_router_link_list() { VTR_ASSERT_MSG(!built_noc, "NoC already built, cannot modify further."); router_link_list.resize(router_storage.size()); } -NocLinkId NocStorage::get_parallel_link(NocLinkId current_link) const{ - +/* + * Two links are considered parallel when the source router of one link + * is the destination router of the second line. And when the desitnantion + * router of one link is the source router of the other link. Sometimes + * it is usful to get the parallel link of a given link. SO, when given + * a link id, the parallel link id is returned here. + */ +NocLinkId NocStorage::get_parallel_link(NocLinkId current_link) const { // get the current source and sink router NocRouterId curr_source_router = link_storage[current_link].get_source_router(); NocRouterId curr_sink_router = link_storage[current_link].get_sink_router(); // get the link list of the sink router - const std::vector *sink_router_links = &(router_link_list[curr_sink_router]); + const std::vector* sink_router_links = &(router_link_list[curr_sink_router]); NocLinkId parallel_link = INVALID_LINK_ID; // go through the links of the sink router and the link that has the current source router as the sink router of the link is the parallel link we are looking for - for (auto link = sink_router_links->begin(); link != sink_router_links->end(); link++){ - - if (link_storage[*link].get_sink_router() == curr_source_router) - { + for (auto link = sink_router_links->begin(); link != sink_router_links->end(); link++) { + if (link_storage[*link].get_sink_router() == curr_source_router) { parallel_link = *link; break; } } return parallel_link; - } - - diff --git a/vpr/src/base/noc_storage.h b/vpr/src/base/noc_storage.h index 295a260411b..87228616102 100644 --- a/vpr/src/base/noc_storage.h +++ b/vpr/src/base/noc_storage.h @@ -1,6 +1,15 @@ #ifndef NOC_STORAGE_H #define NOC_STORAGE_H +/* + * The NocStorage class description header file. + * + * The NocStorage class describes the embedded NoC in the + * FPGA device. This includes all the routers and links in the NoC + * and the connections between routers. Addiitionally, there are functions + * to access/modify the components of the NoC. + * + */ #include #include @@ -13,83 +22,72 @@ #include "vtr_assert.h" #include "vpr_error.h" -// represents the value of a link that does not exist in the NoC +// represents the id of a link that does not exist in the NoC const NocLinkId INVALID_LINK_ID(-1); - -class NocStorage -{ - private: - - // list of routers in the noc - vtr::vector router_storage; - - // list of outgoing links for each router - vtr::vector> router_link_list; - - // list of links in the noc - vtr::vector link_storage; - - // The user provides an id for routers when describing the noc in the architecture file. - // This id system will be different than than the NocRouterIds assigned to each router - // when creating the NoC datastructre. - // A conversion table is created below that maps the user provided router ids to the corresponding - // NocRouterId. - std::unordered_map router_id_conversion_table; - - // flags to keep track of the status - bool built_noc; - - // prevent "copying" of this object - NocStorage(const NocStorage&) = delete; - void operator=(const NocStorage&) = delete; - - public: - - // default contructor (cleare all the elements in the vectors) - NocStorage(); - - // getters for the NoC - const std::vector& get_noc_router_connections(NocRouterId id) const; - const vtr::vector& get_noc_routers(void) const; - const vtr::vector& get_noc_links(void) const; - - // getters for routers - int get_noc_router_grid_position_x(NocRouterId id) const; - int get_noc_router_grid_position_y(NocRouterId id) const; - int get_noc_router_id(NocRouterId id) const; - std::string get_noc_router_design_module_ref(NocRouterId id) const; - - - // getters for links - NocRouterId get_noc_link_source_router(NocLinkId id)const; - NocRouterId get_noc_link_sink_router(NocLinkId id) const; - double get_noc_link_bandwidth_usage(NocLinkId id) const; - int get_noc_link_number_of_connections(NocLinkId id) const; - - // setters for the NoC - void add_router(int id, int grid_position_x, int grid_position_y); - void add_link(NocRouterId source, NocRouterId sink); - - // setters for the noc router - void set_noc_router_design_module_ref(NocRouterId id, std::string design_module_ref); - - // setters for the noc link - void set_noc_link_bandwidth_usage(NocLinkId id, double bandwidth_usage); - void set_noc_link_number_of_connections(NocLinkId id, int number_of_connections); - - // general utiliy functions - void finished_building_noc(); - void clear_noc(); - NocRouterId convert_router_id(int id) const; - void make_room_for_noc_router_link_list(); - NocLinkId get_parallel_link(NocLinkId current_link) const; - - - - +class NocStorage { + private: + // list of routers in the noc + vtr::vector router_storage; + + // list of outgoing links for each router + vtr::vector> router_link_list; + + // list of links in the noc + vtr::vector link_storage; + + // The user provides an id for routers when describing the noc in the architecture file. + // This id system will be different than than the NocRouterIds assigned to each router + // when creating the NoC datastructre. + // A conversion table is created below that maps the user provided router ids to the corresponding + // NocRouterId. + std::unordered_map router_id_conversion_table; + + // flags to keep track of the status + bool built_noc; + + // prevent "copying" of this object + NocStorage(const NocStorage&) = delete; + void operator=(const NocStorage&) = delete; + + public: + // default contructor (cleare all the elements in the vectors) + NocStorage(); + + // getters for the NoC + const std::vector& get_noc_router_connections(NocRouterId id) const; + const vtr::vector& get_noc_routers(void) const; + const vtr::vector& get_noc_links(void) const; + + // getters for routers + int get_noc_router_grid_position_x(NocRouterId id) const; + int get_noc_router_grid_position_y(NocRouterId id) const; + int get_noc_router_id(NocRouterId id) const; + std::string get_noc_router_design_module_ref(NocRouterId id) const; + + // getters for links + NocRouterId get_noc_link_source_router(NocLinkId id) const; + NocRouterId get_noc_link_sink_router(NocLinkId id) const; + double get_noc_link_bandwidth_usage(NocLinkId id) const; + int get_noc_link_number_of_connections(NocLinkId id) const; + + // setters for the NoC + void add_router(int id, int grid_position_x, int grid_position_y); + void add_link(NocRouterId source, NocRouterId sink); + + // setters for the noc router + void set_noc_router_design_module_ref(NocRouterId id, std::string design_module_ref); + + // setters for the noc link + void set_noc_link_bandwidth_usage(NocLinkId id, double bandwidth_usage); + void set_noc_link_number_of_connections(NocLinkId id, int number_of_connections); + + // general utiliy functions + void finished_building_noc(); + void clear_noc(); + NocRouterId convert_router_id(int id) const; + void make_room_for_noc_router_link_list(); + NocLinkId get_parallel_link(NocLinkId current_link) const; }; - - #endif \ No newline at end of file diff --git a/vpr/src/base/read_options.h b/vpr/src/base/read_options.h index 7e40cbbf424..6ea53413637 100644 --- a/vpr/src/base/read_options.h +++ b/vpr/src/base/read_options.h @@ -138,9 +138,8 @@ struct t_options { argparse::ArgValue floorplan_num_horizontal_partitions; argparse::ArgValue floorplan_num_vertical_partitions; - // NoC-driven placement + /*NoC Options*/ argparse::ArgValue noc; - argparse::ArgValue noc_router_tile_name; /* Timing-driven placement options only */ argparse::ArgValue PlaceTimingTradeoff; diff --git a/vpr/src/base/setup_noc.cpp b/vpr/src/base/setup_noc.cpp index 69f155511e5..5c59b32908c 100644 --- a/vpr/src/base/setup_noc.cpp +++ b/vpr/src/base/setup_noc.cpp @@ -1,4 +1,7 @@ - +/* + * This file contains the noc setup function. This function should be used if + * there is a NoC component in the architecture description file, then the function will create a NoC model based on the noc description. There are a number of internal functions that act as helpers in setting up the NoC. + */ #include #include @@ -19,10 +22,17 @@ static void create_noc_links(const t_noc_inf* noc_info, NocStorage* noc_model); static void echo_noc(char* file_name); - -void setup_noc(const t_arch& arch) -{ - +/** + * @brief Based on the NoC information provided by the user in the architecture + * description file, a NoC model is created. The model defines the + * constraints of the NoC as well as its layout on the FPGA device. + * The datastructure used to define the model is "NocStorage" and that + * is created here and stored within the noc_ctx. + * + * @param arch Contains the parsed information from the architecture + * description file. + */ +void setup_noc(const t_arch& arch) { // variable to store all the noc router tiles within the FPGA device std::vector list_of_noc_router_tiles; @@ -32,25 +42,21 @@ void setup_noc(const t_arch& arch) // quick error check that the noc attribute of the arch is not empty // basically, no noc topology information was provided by the user in the arch file - if (arch.noc == nullptr) - { + if (arch.noc == nullptr) { VPR_FATAL_ERROR(VPR_ERROR_OTHER, "No NoC topology information was provided in the architecture file."); } // go through the FPGA grid and find the noc router tiles - // then store the position - identify_and_store_noc_router_tile_positions(device_ctx.grid,list_of_noc_router_tiles, arch.noc->noc_router_tile_name); + // then store the position + identify_and_store_noc_router_tile_positions(device_ctx.grid, list_of_noc_router_tiles, arch.noc->noc_router_tile_name); // check whether the noc topology information provided uses more than the number of available routers in the FPGA - if (list_of_noc_router_tiles.size() < arch.noc->router_list.size()) - { + if (list_of_noc_router_tiles.size() < arch.noc->router_list.size()) { VPR_FATAL_ERROR(VPR_ERROR_OTHER, "The Provided NoC topology information in the architecture file has more number of routers than what is available in the FPGA device."); - } - else if (list_of_noc_router_tiles.size() > arch.noc->router_list.size()) // check whether the noc topology information provided is using all the routers in the FPGA + } else if (list_of_noc_router_tiles.size() > arch.noc->router_list.size()) // check whether the noc topology information provided is using all the routers in the FPGA { - VPR_FATAL_ERROR(VPR_ERROR_OTHER,"The Provided NoC topology information in the architecture file uses less number of routers than what is available in the FPGA device."); - } - else if (list_of_noc_router_tiles.size() == 0) // case where no physical router tiles were found + VPR_FATAL_ERROR(VPR_ERROR_OTHER, "The Provided NoC topology information in the architecture file uses less number of routers than what is available in the FPGA device."); + } else if (list_of_noc_router_tiles.size() == 0) // case where no physical router tiles were found { VPR_FATAL_ERROR(VPR_ERROR_OTHER, "No physical NoC routers were found on the FPGA device. Either the provided name for the physical router tile was incorrect or the FPGA device has no routers."); } @@ -64,17 +70,27 @@ void setup_noc(const t_arch& arch) noc_ctx.noc_router_latency = arch.noc->router_latency; // echo the noc info - if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_NOC_MODEL)) - { - echo_noc(getEchoFileName(E_ECHO_NOC_MODEL)); - } + if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_NOC_MODEL)) { + echo_noc(getEchoFileName(E_ECHO_NOC_MODEL)); + } return; - } -static void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, std::vector& list_of_noc_router_tiles, std::string noc_router_tile_name) -{ +/** + * @brief Goes through the FPGA device and identifies tiles that + * are NoC routers based on the name used to describe + * the router. Every identified routers grid position is + * stored in a list. + * + * @param device_grid The FPGA device description. + * @param list_of_noc_router_tiles Stores the grid position information + * for all NoC router tiles in the FPGA. + * @param noc_router_tile_name The name used when describing the NoC router + * tile in the FPGA architecture description + * file. + */ +static void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, std::vector& list_of_noc_router_tiles, std::string noc_router_tile_name) { int grid_width = device_grid.width(); int grid_height = device_grid.height(); @@ -88,11 +104,8 @@ static void identify_and_store_noc_router_tile_positions(const DeviceGrid& devic double curr_tile_centroid_y; // go through the device - for(int i = 0; i < grid_width; i++) - { - - for (int j = 0; j < grid_height; j++) - { + for (int i = 0; i < grid_width; i++) { + for (int j = 0; j < grid_height; j++) { // get some information from the current tile curr_tile_name.assign(device_grid[i][j].type->name); curr_tile_width_offset = device_grid[i][j].width_offset; @@ -102,36 +115,36 @@ static void identify_and_store_noc_router_tile_positions(const DeviceGrid& devic curr_tile_width = device_grid[i][j].type->width; /* - Only store the tile position if it is a noc router. - Additionally, since a router tile can span multiple grid locations, we only add the tile if the height and width offset are zero (this prevents the router from being added multiple times for each grid location it spans). - */ - if (!(noc_router_tile_name.compare(curr_tile_name)) && !curr_tile_width_offset && !curr_tile_height_offset) - { + * Only store the tile position if it is a noc router. + * Additionally, since a router tile can span multiple grid locations, we only add the tile if the height and width offset are zero (this prevents the router from being added multiple times for each grid location it spans). + */ + if (!(noc_router_tile_name.compare(curr_tile_name)) && !curr_tile_width_offset && !curr_tile_height_offset) { // calculating the centroid position of the current tile - curr_tile_centroid_x = (curr_tile_width - 1)/(double)2 + i; - curr_tile_centroid_y = (curr_tile_height - 1)/(double)2 + j; + curr_tile_centroid_x = (curr_tile_width - 1) / (double)2 + i; + curr_tile_centroid_y = (curr_tile_height - 1) / (double)2 + j; - list_of_noc_router_tiles.push_back({i,j,curr_tile_centroid_x, curr_tile_centroid_y}); + list_of_noc_router_tiles.push_back({i, j, curr_tile_centroid_x, curr_tile_centroid_y}); } - } } return; - } -/* the purpose of this function is to "assign" the logical routers defined in the architecture file to - their corresponding physical routers (represented as router nodes) in the FPGA chip. The router assignments - are done by determining the logical router who's position is the shortest distance to each physical router. - - Once the physical routers are assigned, "links" are created to connect the routers, this - is done based on the connections defines in the architecture file. - - This completes the NoC creation. -*/ -void generate_noc(const t_arch& arch, NocContext& noc_ctx, std::vector& list_of_noc_router_tiles) -{ +/** + * @brief Creates NoC routers and adds them to the NoC model based + * on the routers provided by the user. Then the NoC links are + * created based on the topology. This completes the NoC + * model creation. + * + * @param arch Contains the parsed information from the architecture + * description file. + * @param noc_ctx A global variable that contains the NoC Model and other + * NoC related information. + * @param list_of_noc_router_tiles Stores the grid position information + * for all NoC router tiles in the FPGA. + */ +void generate_noc(const t_arch& arch, NocContext& noc_ctx, std::vector& list_of_noc_router_tiles) { // refrernces to the noc NocStorage* noc_model = &noc_ctx.noc_model; // reference to the noc description @@ -150,11 +163,24 @@ void generate_noc(const t_arch& arch, NocContext& noc_ctx, std::vectorfinished_building_noc(); return; - } -static void create_noc_routers(const t_noc_inf& noc_info, NocStorage* noc_model , std::vector& list_of_noc_router_tiles) -{ +/** + * @brief Go through the list of logical routers (routers described by the user + * in the architecture description file) and assign it a corresponding + * physical router tile in the FPGA. Each logical router has a grid + * location, so the closest physical router to the grid location is then + * assigned to it. Once a physical router is assigned, a NoC router + * is created to represent it and this is added to the NoC model. + * + * @param noc_info Contains the parsed NoC topology information from the + * architecture description file. + * @param noc_model An internal model that describes the NoC. Contains a list of + * routers and links that connect the routers together. + * @param list_of_noc_router_tiles Stores the grid position information + * for all NoC router tiles in the FPGA. + */ +static void create_noc_routers(const t_noc_inf& noc_info, NocStorage* noc_model, std::vector& list_of_noc_router_tiles) { // keep track of the shortest distance between a logical router and the curren physical router tile // also keep track of the corresponding physical router tile index (within the list) double shortest_distance; @@ -173,19 +199,18 @@ static void create_noc_routers(const t_noc_inf& noc_info, NocStorage* noc_model int curr_physical_router_index = 0; // keep track of the ids of the routers that ceate the case where multiple routers - // have the same distance to a physical router tile + // have the same distance to a physical router tile int error_case_physical_router_index_1; int error_case_physical_router_index_2; // keep track of all the logical router and physical router assignments (their pairings) std::vector router_assignments; router_assignments.resize(list_of_noc_router_tiles.size(), PHYSICAL_ROUTER_NOT_ASSIGNED); - + // Below we create all the routers within the NoC // // go through each logical router tile and assign it to a physical router on the FPGA - for (auto logical_router = noc_info.router_list.begin(); logical_router != noc_info.router_list.end(); logical_router++) - { + for (auto logical_router = noc_info.router_list.begin(); logical_router != noc_info.router_list.end(); logical_router++) { // assign the shortest distance to a large value (this is done so that the first distance calculated and we can replace this) shortest_distance = LLONG_MAX; @@ -204,71 +229,73 @@ static void create_noc_routers(const t_noc_inf& noc_info, NocStorage* noc_model error_case_physical_router_index_2 = INVALID_PHYSICAL_ROUTER_INDEX; // determine the physical router tile that is closest to the current logical router - for (auto physical_router = list_of_noc_router_tiles.begin(); physical_router != list_of_noc_router_tiles.end(); physical_router++) - { + for (auto physical_router = list_of_noc_router_tiles.begin(); physical_router != list_of_noc_router_tiles.end(); physical_router++) { // get the position of the current physical router tile on the FPGA device curr_physical_router_pos_x = physical_router->tile_centroid_x; curr_physical_router_pos_y = physical_router->tile_centroid_y; // use euclidean distance to calculate the length between the current logical and physical routers - curr_calculated_distance = sqrt(pow(abs(curr_physical_router_pos_x - curr_logical_router_position_x),2.0) + - pow(abs(curr_physical_router_pos_y - curr_logical_router_position_y),2.0)); - + curr_calculated_distance = sqrt(pow(abs(curr_physical_router_pos_x - curr_logical_router_position_x), 2.0) + pow(abs(curr_physical_router_pos_y - curr_logical_router_position_y), 2.0)); + // if the current distance is the same as the previous shortest distance - if (vtr::isclose(curr_calculated_distance, shortest_distance)) - { + if (vtr::isclose(curr_calculated_distance, shortest_distance)) { // store the ids of the two physical routers error_case_physical_router_index_1 = closest_physical_router; error_case_physical_router_index_2 = curr_physical_router_index; - - } - else if (curr_calculated_distance < shortest_distance) // case where the current logical router is closest to the physical router tile + + } else if (curr_calculated_distance < shortest_distance) // case where the current logical router is closest to the physical router tile { // update the shortest distance and then the closest router shortest_distance = curr_calculated_distance; closest_physical_router = curr_physical_router_index; - } // update the index for the next physical router curr_physical_router_index++; - } // check the case where two physical router tiles have the same distance to the given logical router - if (error_case_physical_router_index_1 == closest_physical_router) - { - VPR_FATAL_ERROR(VPR_ERROR_OTHER, - "Router with ID:'%d' has the same distance to physical router tiles located at position (%d,%d) and (%d,%d). Therefore, no router assignment could be made.", - logical_router->id, list_of_noc_router_tiles[error_case_physical_router_index_1].grid_width_position, list_of_noc_router_tiles[error_case_physical_router_index_1].grid_height_position, - list_of_noc_router_tiles[error_case_physical_router_index_2].grid_width_position, list_of_noc_router_tiles[error_case_physical_router_index_2].grid_height_position); + if (error_case_physical_router_index_1 == closest_physical_router) { + VPR_FATAL_ERROR(VPR_ERROR_OTHER, + "Router with ID:'%d' has the same distance to physical router tiles located at position (%d,%d) and (%d,%d). Therefore, no router assignment could be made.", + logical_router->id, list_of_noc_router_tiles[error_case_physical_router_index_1].grid_width_position, list_of_noc_router_tiles[error_case_physical_router_index_1].grid_height_position, + list_of_noc_router_tiles[error_case_physical_router_index_2].grid_width_position, list_of_noc_router_tiles[error_case_physical_router_index_2].grid_height_position); } // check if the current physical router was already assigned previously, if so then throw an error - if (router_assignments[closest_physical_router] != PHYSICAL_ROUTER_NOT_ASSIGNED) - { - VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Routers with IDs:'%d' and '%d' are both closest to physical router tile located at (%d,%d) and the physical router could not be assigned multiple times.", - logical_router->id, router_assignments[closest_physical_router], list_of_noc_router_tiles[closest_physical_router].grid_width_position, + if (router_assignments[closest_physical_router] != PHYSICAL_ROUTER_NOT_ASSIGNED) { + VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Routers with IDs:'%d' and '%d' are both closest to physical router tile located at (%d,%d) and the physical router could not be assigned multiple times.", + logical_router->id, router_assignments[closest_physical_router], list_of_noc_router_tiles[closest_physical_router].grid_width_position, list_of_noc_router_tiles[closest_physical_router].grid_height_position); } // at this point, the closest logical router to the current physical router was found // so add the router to the NoC - noc_model->add_router(logical_router->id, list_of_noc_router_tiles[closest_physical_router].grid_width_position, - list_of_noc_router_tiles[closest_physical_router].grid_height_position); + noc_model->add_router(logical_router->id, list_of_noc_router_tiles[closest_physical_router].grid_width_position, + list_of_noc_router_tiles[closest_physical_router].grid_height_position); // add the new assignment to the tracker router_assignments[closest_physical_router] = logical_router->id; - } return; } -static void create_noc_links(const t_noc_inf* noc_info, NocStorage* noc_model){ +/** + * @brief Goes through the topology information as described in the FPGA + * architecture description file and creates NoC links that are stored + * into the NoC Model. All the created NoC links describe how the routers + * are connected to each other. + * + * @param noc_info Contains the parsed NoC topology information from the + * architecture description file. + * @param noc_model An internal model that describes the NoC. Contains a list of + * routers and links that connect the routers together. + */ +static void create_noc_links(const t_noc_inf* noc_info, NocStorage* noc_model) { // the ids used to represent the routers in the NoC are not the same as the ones provided by the user in the arch desc file. // while going through the router connections, the user provided router ids are converted and then stored below before being used - // in the links. + // in the links. NocRouterId source_router; NocRouterId sink_router; @@ -279,28 +306,32 @@ static void create_noc_links(const t_noc_inf* noc_info, NocStorage* noc_model){ noc_model->make_room_for_noc_router_link_list(); // go through each router and add its outgoing links to the NoC - for (auto router = noc_info->router_list.begin(); router != noc_info->router_list.end(); router++) - { + for (auto router = noc_info->router_list.begin(); router != noc_info->router_list.end(); router++) { // get the converted id of the current source router source_router = noc_model->convert_router_id(router->id); // go through all the routers connected to the current one and add links to the noc - for (auto conn_router_id = router->connection_list.begin(); conn_router_id != router->connection_list.end(); conn_router_id++) - { + for (auto conn_router_id = router->connection_list.begin(); conn_router_id != router->connection_list.end(); conn_router_id++) { // get the converted id of the currently connected sink router sink_router = noc_model->convert_router_id(*conn_router_id); // add the link to the Noc - noc_model->add_link(source_router, sink_router);; + noc_model->add_link(source_router, sink_router); + ; } } return; - } -static void echo_noc(char* file_name) -{ +/** + * @brief Writes out the NoC model infromation to a file. This includes + * the noc constraints, the list of routers and their connections + * to other routers in the NoC. + * + * @param file_name The name of the file that contains the NoC model info. + */ +static void echo_noc(char* file_name) { FILE* fp; fp = vtr::fopen(file_name, "w"); @@ -330,18 +361,16 @@ static void echo_noc(char* file_name) auto& noc_routers = noc_ctx.noc_model.get_noc_routers(); // go through each router and print its information - for (auto router = noc_routers.begin(); router != noc_routers.end(); router++) - { - fprintf(fp,"Router %d:\n", router->get_router_id()); + for (auto router = noc_routers.begin(); router != noc_routers.end(); router++) { + fprintf(fp, "Router %d:\n", router->get_router_id()); // if the router tile is larger than a single grid, the position represents the bottom left corner of the tile - fprintf(fp,"Equivalent Physical Tile Grid Position -> (%d,%d)\n", router->get_router_grid_position_x(), router->get_router_grid_position_y()); + fprintf(fp, "Equivalent Physical Tile Grid Position -> (%d,%d)\n", router->get_router_grid_position_x(), router->get_router_grid_position_y()); fprintf(fp, "Router Connections ->"); auto& router_connections = noc_ctx.noc_model.get_noc_router_connections(noc_ctx.noc_model.convert_router_id(router->get_router_id())); // go through the links of the current router and add the connecting router to the list - for (auto router_link = router_connections.begin(); router_link != router_connections.end(); router_link++) - { + for (auto router_link = router_connections.begin(); router_link != router_connections.end(); router_link++) { fprintf(fp, " %d", noc_ctx.noc_model.get_noc_router_id(noc_ctx.noc_model.get_noc_link_sink_router(*router_link))); } @@ -351,7 +380,4 @@ static void echo_noc(char* file_name) fclose(fp); return; - } - - diff --git a/vpr/src/base/setup_noc.h b/vpr/src/base/setup_noc.h index bce77b64267..cafa2dcd79a 100644 --- a/vpr/src/base/setup_noc.h +++ b/vpr/src/base/setup_noc.h @@ -1,35 +1,38 @@ #ifndef SETUP_NOC #define SETUP_NOC +/* + * THis file contains functions and datatypes that help setup the NoC model datastructure from the user NoC description in the arch file. + * + * During VPR setup, the functions here should be used to setup the NoC. + * + */ + #include #include #include - #include "physical_types.h" #include "device_grid.h" #include "globals.h" #include "noc_storage.h" #include "vpr_error.h" +// a default condition that helps keep track of whether a physical router has been assigned to a logical router or not #define PHYSICAL_ROUTER_NOT_ASSIGNED -1 -#define INVALID_PHYSICAL_ROUTER_INDEX -1 - +// a deafult index used for initiailization purposes. No router will have a negative index +#define INVALID_PHYSICAL_ROUTER_INDEX -1 // a data structure to store the position information of a noc router in the FPGA device struct t_noc_router_tile_position { - int grid_width_position; int grid_height_position; - + double tile_centroid_x; double tile_centroid_y; - }; - void setup_noc(const t_arch& arch); - #endif \ No newline at end of file diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index 26776c9dd67..deb678f4a02 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -491,13 +491,23 @@ void vpr_setup_clock_networks(t_vpr_setup& vpr_setup, const t_arch& Arch) { } } -void vpr_setup_noc(const t_vpr_setup& vpr_setup, const t_arch& arch) -{ +/** + * @brief If the user provided the "--noc on" option then the noc is + * setup by creating an internal model and storing the NoC + * constraints. Additionally, the graphics state is updated + * to include a NoC button to display it. + * + * @param vpr_setup A datastructure that stores all the user provided option + * to vpr. + * @param arch Contains the parsed information from the architecture + * description file. + */ +void vpr_setup_noc(const t_vpr_setup& vpr_setup, const t_arch& arch) { t_draw_state* draw_state = get_draw_state_vars(); // check if the user provided the option to model the noc - if (vpr_setup.NocOpts.noc == true) - { + if (vpr_setup.NocOpts.noc == true) { + // create the NoC model based on the user description from the arch file setup_noc(arch); // setup the graphics diff --git a/vpr/src/base/vpr_api.h b/vpr/src/base/vpr_api.h index 8d11d136331..f3a0c0f1c9c 100644 --- a/vpr/src/base/vpr_api.h +++ b/vpr/src/base/vpr_api.h @@ -126,8 +126,9 @@ void vpr_init_graphics(const t_vpr_setup& vpr_setup, const t_arch& arch); void vpr_close_graphics(const t_vpr_setup& vpr_setup); void vpr_setup_clock_networks(t_vpr_setup& vpr_setup, const t_arch& Arch); -// @brief Create the NoC + void vpr_setup_noc(const t_vpr_setup& vpr_setup, const t_arch& arch); + void vpr_free_vpr_data_structures(t_arch& Arch, t_vpr_setup& vpr_setup); void vpr_free_all(t_arch& Arch, t_vpr_setup& vpr_setup); diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index 0036da66ed6..2f63d450c9e 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -1269,9 +1269,9 @@ struct t_analysis_opts { e_timing_update_type timing_update_type; }; +// used to store NoC specific options, when supplied as an input by the user struct t_noc_opts { - bool noc; ///show_noc_button) - { + if (!draw_state->show_noc_button) { return; } - // if we are here then the user turned the "noc" option on, so create a radio button to allow the user to display the noc + // if we are here then the user turned the "noc" option on, so create a button to allow the user to display the noc - //combo box for toggle_crit_path + //combo box for toggle_noc_display GtkWidget* toggle_noc_display_widget = gtk_combo_box_text_new(); GtkWidget* toggle_noc_display_label = gtk_label_new("Toggle NoC Display:"); gtk_combo_box_text_append_text(GTK_COMBO_BOX_TEXT(toggle_noc_display_widget), "None"); @@ -271,7 +269,7 @@ void button_for_displaying_noc() { //attach to the grid gtk_grid_attach((GtkGrid*)main_window_grid, toggle_noc_display_label, label_left_start_col, button_row++, box_width, box_height); gtk_grid_attach((GtkGrid*)main_window_grid, toggle_noc_display_widget, box_left_start_col, button_row++, box_width, box_height); - + // show the newy added check box gtk_widget_show_all((GtkWidget*)main_window); @@ -282,7 +280,6 @@ void button_for_displaying_noc() { toggle_noc_display_widget); } - void button_for_toggle_rr() { GObject* main_window = application.get_object(application.get_main_window_id().c_str()); GObject* main_window_grid = application.get_object("InnerGrid"); diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 77b5af2f587..089c2a1db4e 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -920,8 +920,7 @@ void toggle_router_expansion_costs(GtkWidget* /*widget*/, gint /*response_id*/, application.refresh_drawing(); } -void toggle_noc_display(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) -{ +void toggle_noc_display(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/) { /* this is the callback function for runtime created toggle_noc_display button * which is written in button.cpp */ t_draw_state* draw_state = get_draw_state_vars(); @@ -3682,11 +3681,10 @@ static void draw_routed_timing_edge(tatum::NodeId start_tnode, } /* - This function draws the NoC by drawing the links of the NoC and highlights the connection points between links.The drawing is done on top of all the placment and routing, so this acts as an overlay. - -*/ -static void draw_noc(ezgl::renderer *g) -{ + * Draw the NoC by drawing the links of the NoC and highlights the connection points between links.The drawing is done on top of all the placment and routing, so this acts as an overlay. + * + */ +static void draw_noc(ezgl::renderer* g) { t_draw_state* draw_state = get_draw_state_vars(); auto& noc_ctx = g_vpr_ctx.noc(); auto& device_ctx = g_vpr_ctx.device(); @@ -3695,7 +3693,7 @@ static void draw_noc(ezgl::renderer *g) vtr::vector router_list = noc_ctx.noc_model.get_noc_routers(); // a vector of colors to use for the NoC links, determines the colors used when drawing each link - vtr::vector noc_link_colors; + vtr::vector noc_link_colors; // initialize all the link colors to black and set the vector size to the total number of links noc_link_colors.resize(noc_ctx.noc_model.get_noc_links().size(), ezgl::BLACK); @@ -3708,18 +3706,16 @@ static void draw_noc(ezgl::renderer *g) // start by checking to see if the NoC display button was selected // if the noc display option was not selected then don't draw the noc - if (draw_state->draw_noc == DRAW_NO_NOC) - { + if (draw_state->draw_noc == DRAW_NO_NOC) { return; } // check that the NoC tile has a capacity greater than 0 (can we assume it always will?) and if not then we cant draw anythign as the NoC tile wont be drawn /* since the vector of routers all have a reference positions on the grid to the corresponding physical tile, just use the first router in the vector and get its position, then use this to get the capcity of a noc router tile - */ + */ int num_subtiles = device_ctx.grid[router_list.begin()->get_router_grid_position_x()][router_list.begin()->get_router_grid_position_y()].type->capacity; - if (num_subtiles == 0) - { + if (num_subtiles == 0) { return; } @@ -3731,9 +3727,8 @@ static void draw_noc(ezgl::renderer *g) // only draw the noc useage if the user selected the option if (draw_state->draw_noc == DRAW_NOC_LINK_USAGE) { - draw_noc_usage(noc_link_colors); - + // draw the color map legend draw_color_map_legend(*(draw_state->noc_usage_color_map), g); } @@ -3749,8 +3744,10 @@ static void draw_noc(ezgl::renderer *g) return; } -static void draw_noc_usage(vtr::vector& noc_link_colors) -{ +/* + * Go through each NoC link and assign a color based on how much the link is being used (its bandwidth). The colors are determined from the PLasma colormap. + */ +static void draw_noc_usage(vtr::vector& noc_link_colors) { t_draw_state* draw_state = get_draw_state_vars(); auto& noc_ctx = g_vpr_ctx.noc(); @@ -3758,8 +3755,7 @@ static void draw_noc_usage(vtr::vector& noc_link_colors) double max_noc_link_bandwidth = noc_ctx.noc_link_bandwidth; // check to see if a color map was already created previously - if (draw_state->noc_usage_color_map == nullptr) - { + if (draw_state->noc_usage_color_map == nullptr) { // we havent created a color map yet for the noc link usage, so create it here // the color map creates a color spectrum that gradually changes from a dark to light color. Where a dark color represents low noc link usage (low bandwidth) and a light color represents high noc link usage (high bandwidth) // The color map needs a min and max value to generate the color range. @@ -3778,36 +3774,29 @@ static void draw_noc_usage(vtr::vector& noc_link_colors) // represents the color to draw each noc link ezgl::color current_noc_link_color; - // now we need to determine the colors for each link - for (int link = 0; link < (int)link_list.size(); link++) - { + for (int link = 0; link < (int)link_list.size(); link++) { // get the current link id NocLinkId link_id(link); // only update the color of the link if it wasnt updated previously - if (noc_link_colors[link_id] == ezgl::BLACK) - { + if (noc_link_colors[link_id] == ezgl::BLACK) { // if we are here then the link was not updated previously, so assign the color here //get the current link bandwidth usage (ratio calculation) link_bandwidth_usage = (link_list[link_id].get_bandwidth_usage()) / max_noc_link_bandwidth; // check if the link is being overused and if it is then cap it at 1.0 - if (link_bandwidth_usage > 1.0) - { + if (link_bandwidth_usage > 1.0) { link_bandwidth_usage = 1.0; } // get the corresponding color that represents the link bandwidth usgae current_noc_link_color = to_ezgl_color(draw_state->noc_usage_color_map->color(link_bandwidth_usage)); - // set the colors of the link noc_link_colors[link_id] = current_noc_link_color; - } - } return; @@ -3816,10 +3805,9 @@ static void draw_noc_usage(vtr::vector& noc_link_colors) /************* draw_noc helper functions below *************/ /* - This function calculates the position of the marker that will be drawn inside the noc router tile on the FPGA. This marker will be located in the center of the tile and represents a connection point between links that connect to the router. -*/ -static ezgl::rectangle get_noc_connection_marker_bbox(const t_logical_block_type_ptr noc_router_logical_block_type) -{ + * This function calculates the position of the marker that will be drawn inside the noc router tile on the FPGA. This marker will be located in the center of the tile and represents a connection point between links that connect to the router. + */ +static ezgl::rectangle get_noc_connection_marker_bbox(const t_logical_block_type_ptr noc_router_logical_block_type) { t_draw_coords* draw_coords = get_draw_coords_vars(); // get the drawing information for a noc router @@ -3830,34 +3818,34 @@ static ezgl::rectangle get_noc_connection_marker_bbox(const t_logical_block_type ezgl::rectangle noc_router_pb_bbox = blk_type_info.get_pb_bbox(pb_gnode); /* - The connection marker will be positioned at the center of the noc router tile. For example it will look like below: - - ********************* - * * - * * - * **** * - * * * * - * **** * - * * - * * - ********************* - - We do the following to calculate the position of the marker: - 1. Get the area of the larger router tile - 2. Calculate the area of the marker (based on a predefined percentage of the area of the larger noc tile) - 3. The marker is a square, so we can can calculate the lengths - of the sides of the marker - 4. Divide the side length by 2 and subtract this from the x & y coordinates of the center of the larger noc router tile. This is the bottom left corner of the rectangle. - 5. Then add the side length to the x & y coordinate of the center of the larger noc router tile. THis is the top right corner of the rectangle. - */ + * The connection marker will be positioned at the center of the noc router tile. For example it will look like below: + * + ********************* + * * + * * + * **** * + * * * * + * **** * + * * + * * + ********************* + * + * We do the following to calculate the position of the marker: + * 1. Get the area of the larger router tile + * 2. Calculate the area of the marker (based on a predefined percentage of the area of the larger noc tile) + * 3. The marker is a square, so we can can calculate the lengths + * of the sides of the marker + * 4. Divide the side length by 2 and subtract this from the x & y coordinates of the center of the larger noc router tile. This is the bottom left corner of the rectangle. + * 5. Then add the side length to the x & y coordinate of the center of the larger noc router tile. THis is the top right corner of the rectangle. + */ double noc_router_bbox_area = noc_router_pb_bbox.area(); ezgl::point2d noc_router_bbox_center = noc_router_pb_bbox.center(); double connection_marker_bbox_area = noc_router_bbox_area * SIZE_OF_NOC_MARKER; double connection_marker_bbox_side_length = sqrt(connection_marker_bbox_area); - double half_of_connection_marker_bbox_side_length = connection_marker_bbox_side_length/2; - + double half_of_connection_marker_bbox_side_length = connection_marker_bbox_side_length / 2; + // calculate bottom left corner coordinate of marker ezgl::point2d connection_marker_origin_pt(noc_router_bbox_center.x - half_of_connection_marker_bbox_side_length, noc_router_bbox_center.y - half_of_connection_marker_bbox_side_length); // calculate upper right corner coordinate of marker @@ -3866,14 +3854,12 @@ static ezgl::rectangle get_noc_connection_marker_bbox(const t_logical_block_type ezgl::rectangle connection_marker_bbox(connection_marker_origin_pt, connection_marker_top_right_pt); return connection_marker_bbox; - } /* - This function draws the markers inside the noc router tiles. This marker represents a connection that is an intersection points between multiple links. -*/ -static void draw_noc_connection_marker(ezgl::renderer* g,const vtr::vector& router_list, ezgl::rectangle connection_marker_bbox) -{ + * This function draws the markers inside the noc router tiles. This marker represents a connection that is an intersection points between multiple links. + */ +static void draw_noc_connection_marker(ezgl::renderer* g, const vtr::vector& router_list, ezgl::rectangle connection_marker_bbox) { t_draw_coords* draw_coords = get_draw_coords_vars(); //set the color of the marker @@ -3885,8 +3871,7 @@ static void draw_noc_connection_marker(ezgl::renderer* g,const vtr::vectorget_router_grid_position_x(); router_grid_position_y = router->get_router_grid_position_y(); @@ -3895,17 +3880,15 @@ static void draw_noc_connection_marker(ezgl::renderer* g,const vtr::vectorfill_rectangle(updated_connection_marker_bbox); - } return; } /* - This function draws the links within the noc. So based on a given noc topology, this function draws the links that connect the routers in the noc together. -*/ -static void draw_noc_links(ezgl::renderer* g, const t_logical_block_type_ptr noc_router_logical_block_type, vtr::vector& noc_link_colors, ezgl::rectangle noc_connection_marker_bbox, const vtr::vector& list_of_noc_link_shift_directions) -{ + * This function draws the links within the noc. So based on a given noc topology, this function draws the links that connect the routers in the noc together. + */ +static void draw_noc_links(ezgl::renderer* g, const t_logical_block_type_ptr noc_router_logical_block_type, vtr::vector& noc_link_colors, ezgl::rectangle noc_connection_marker_bbox, const vtr::vector& list_of_noc_link_shift_directions) { t_draw_coords* draw_coords = get_draw_coords_vars(); auto& noc_ctx = g_vpr_ctx.noc(); @@ -3916,7 +3899,7 @@ static void draw_noc_links(ezgl::renderer* g, const t_logical_block_type_ptr noc vtr::vector link_list = noc_ctx.noc_model.get_noc_links(); // set the width of the link - g->set_line_width(3); + g->set_line_width(2); // routers connecting links NocRouterId source_router; @@ -3942,13 +3925,11 @@ static void draw_noc_links(ezgl::renderer* g, const t_logical_block_type_ptr noc // get half the width and height of the noc connection marker // we will shift the links based on this parameters since the links will be drawn at the boundaries of connection marker instead of the center - double noc_connection_marker_quarter_width = (noc_connection_marker_bbox.center().x - noc_connection_marker_bbox.bottom_left().x)/2; - double noc_connection_marker_quarter_height = (noc_connection_marker_bbox.center().y - noc_connection_marker_bbox.bottom_left().y)/2; - + double noc_connection_marker_quarter_width = (noc_connection_marker_bbox.center().x - noc_connection_marker_bbox.bottom_left().x) / 2; + double noc_connection_marker_quarter_height = (noc_connection_marker_bbox.center().y - noc_connection_marker_bbox.bottom_left().y) / 2; // loop through the links and draw them - for(int link = 0; link < (int)link_list.size(); link++) - { + for (int link = 0; link < (int)link_list.size(); link++) { // get the converted link if NocLinkId link_id(link); @@ -3965,14 +3946,14 @@ static void draw_noc_links(ezgl::renderer* g, const t_logical_block_type_ptr noc // get the initial drawing coordinates of the noc link // it will be drawn from the center of two routers it connects - link_coords.start = draw_coords->get_absolute_clb_bbox(source_router_x_position, source_router_y_position, 0,noc_router_logical_block_type).center(); - link_coords.end = draw_coords->get_absolute_clb_bbox(sink_router_x_position, sink_router_y_position, 0,noc_router_logical_block_type).center(); + link_coords.start = draw_coords->get_absolute_clb_bbox(source_router_x_position, source_router_y_position, 0, noc_router_logical_block_type).center(); + link_coords.end = draw_coords->get_absolute_clb_bbox(sink_router_x_position, sink_router_y_position, 0, noc_router_logical_block_type).center(); // determine the current noc link type link_type = determine_noc_link_type(link_coords.start, link_coords.end); shift_noc_link(link_coords, list_of_noc_link_shift_directions[link_id], link_type, noc_connection_marker_quarter_width, noc_connection_marker_quarter_height); - + // set the color to draw the current link g->set_color(noc_link_colors[link_id]); @@ -3982,6 +3963,9 @@ static void draw_noc_links(ezgl::renderer* g, const t_logical_block_type_ptr noc return; } + +/************* end of draw_noc helper functions *************/ + //Collect all the drawing locations associated with the timing edge between start and end static void draw_routed_timing_edge_connection(tatum::NodeId src_tnode, tatum::NodeId sink_tnode, diff --git a/vpr/src/draw/draw_noc.cpp b/vpr/src/draw/draw_noc.cpp index 33f37a1087e..a3ad2475de2 100644 --- a/vpr/src/draw/draw_noc.cpp +++ b/vpr/src/draw/draw_noc.cpp @@ -18,8 +18,7 @@ * shift each link in the NoC when * drawn. */ -void determine_direction_to_shift_noc_links(vtr::vector& list_of_noc_link_shift_directions){ - +void determine_direction_to_shift_noc_links(vtr::vector& list_of_noc_link_shift_directions) { auto& noc_ctx = g_vpr_ctx.noc(); //const NocStorage* noc_model = &noc_ctx.noc_model; @@ -29,14 +28,12 @@ void determine_direction_to_shift_noc_links(vtr::vector& NocLinkId parallel_link; // go through all the noc links and assign how the link should be shifted - for (int link = 0; link < number_of_links; link++){ - + for (int link = 0; link < number_of_links; link++) { // convert the link to a link id NocLinkId link_id(link); // only assign a shift direction if we havent already - if (list_of_noc_link_shift_directions[link_id] == NocLinkShift::NO_SHIFT){ - + if (list_of_noc_link_shift_directions[link_id] == NocLinkShift::NO_SHIFT) { // the current link will always have a TOP_shift list_of_noc_link_shift_directions[link_id] = NocLinkShift::TOP_SHIFT; @@ -44,8 +41,7 @@ void determine_direction_to_shift_noc_links(vtr::vector& parallel_link = noc_ctx.noc_model.get_parallel_link(link_id); // check first if a legal link id was found - if (parallel_link == INVALID_LINK_ID) - { + if (parallel_link == INVALID_LINK_ID) { // if we are here, then a parallel link wasnt found, so that means there is only a single link and there is no need to perform any shifting on the single link list_of_noc_link_shift_directions[link_id] = NocLinkShift::NO_SHIFT; @@ -53,15 +49,12 @@ void determine_direction_to_shift_noc_links(vtr::vector& } list_of_noc_link_shift_directions[parallel_link] = NocLinkShift::BOTTOM_SHIFT; - } - } return; } - /** * @brief The type (orientation) of a line is determine here. A second * horizontal line is created that connects to the starting point of the @@ -73,9 +66,8 @@ void determine_direction_to_shift_noc_links(vtr::vector& * @param link_start_point The starting point of a line that represents a NoC * link. * @param link_end_point THe end point of a line that represent a NoC link. -*/ -NocLinkType determine_noc_link_type(ezgl::point2d link_start_point, ezgl::point2d link_end_point){ - + */ +NocLinkType determine_noc_link_type(ezgl::point2d link_start_point, ezgl::point2d link_end_point) { // get the coordinates of the provided line double x_coord_start = link_start_point.x; double y_coord_start = link_start_point.y; @@ -96,51 +88,44 @@ NocLinkType determine_noc_link_type(ezgl::point2d link_start_point, ezgl::point2 // we can check quickly if the line is vertical or horizontal without calculating the cross product. If it is vertical or horizontal then we just return. Otherwise we have to calculate it. // check if the line is vertical by determining if there is any horizontal change - if (vtr::isclose(x_coord_end - x_coord_start, 0.0)){ + if (vtr::isclose(x_coord_end - x_coord_start, 0.0)) { result = NocLinkType::VERTICAL; return result; } // check if the line is horizontal by determinig if there is any vertical shift - if (vtr::isclose(y_coord_end - y_coord_start, 0.0)){ + if (vtr::isclose(y_coord_end - y_coord_start, 0.0)) { result = NocLinkType::HORIZONTAL; return result; } - // if we are here then the line has a slope, so we use the cross product to determine the angle + // if we are here then the line has a slope, so we use the cross product to determine the angle double angle = acos(((x_coord_end - x_coord_start) * (x_coord_horziontal_end - x_coord_horizontal_start) + (y_coord_end - y_coord_start) * (y_coord_horizontal_end - y_coord_horizontal_start)) / (sqrt(pow(x_coord_end - x_coord_start, 2.0) + pow(y_coord_end - y_coord_start, 2.0)) * sqrt(pow(x_coord_horziontal_end - x_coord_horizontal_start, 2.0) + pow(y_coord_horizontal_end - y_coord_horizontal_start, 2.0)))); // the angle is in the first or fourth quandrant of the unit circle - if ((angle > 0) && (angle < (PI_RADIAN/2))){ - + if ((angle > 0) && (angle < (PI_RADIAN / 2))) { // if it is a positive sloped line, then the y coordinate of the end point is higher the y-coordinate of the horizontal line - if (y_coord_end > y_coord_horizontal_end){ - + if (y_coord_end > y_coord_horizontal_end) { result = NocLinkType::POSITVE_SLOPE; - } - else{ // if the end y-coordinate is less than the horizontal line then we have a negative sloped line + } else { // if the end y-coordinate is less than the horizontal line then we have a negative sloped line result = NocLinkType::NEGATIVE_SLOPE; } - } - else{ // the case where the angle is in the 3rd and 4th quandrant of the unit cirle + } else { // the case where the angle is in the 3rd and 4th quandrant of the unit cirle // if the line is positive sloped, then the y-coordinate of the end point is lower than the y-coordinate of the horizontal line - if (y_coord_end < y_coord_horizontal_end){ - + if (y_coord_end < y_coord_horizontal_end) { result = NocLinkType::POSITVE_SLOPE; - } - else{ // if the end y-coordinate of is greater than the horizontal line then we have a negative sloped line + } else { // if the end y-coordinate of is greater than the horizontal line then we have a negative sloped line result = NocLinkType::NEGATIVE_SLOPE; } } return result; - } /** @@ -159,30 +144,28 @@ NocLinkType determine_noc_link_type(ezgl::point2d link_start_point, ezgl::point2 * @param noc_connection_marker_quarter_height The distance to shift the NoC * link in the vertical direction. */ -void shift_noc_link(noc_link_draw_coords& link_coords, NocLinkShift link_shift_direction, NocLinkType link_type, double noc_connection_marker_quarter_width, double noc_connection_marker_quarter_height){ - +void shift_noc_link(noc_link_draw_coords& link_coords, NocLinkShift link_shift_direction, NocLinkType link_type, double noc_connection_marker_quarter_width, double noc_connection_marker_quarter_height) { // determine the type of link and based on that shift the link accordingly /* - Vertical line: shift the link left and right and the distance is equal to half the width of the connection marker - - horizontal line: shift the link up and down and the distance is equal to half the width of the connection marker - - positive slope line: shift the link to the bottom right and top left corners of the connection marker - - negative slope line: shift the link to the bottom left and top roght corners of the connection marker - - */ - - switch (link_type){ + * Vertical line: shift the link left and right and the distance is equal to half the width of the connection marker + * + * horizontal line: shift the link up and down and the distance is equal to half the width of the connection marker + * + * positive slope line: shift the link to the bottom right and top left corners of the connection marker + * + * negative slope line: shift the link to the bottom left and top roght corners of the connection marker + * + */ + + switch (link_type) { case NocLinkType::INVALID_TYPE: break; case NocLinkType::VERTICAL: - if (link_shift_direction == NocLinkShift::TOP_SHIFT){ + if (link_shift_direction == NocLinkShift::TOP_SHIFT) { // shift the link left link_coords.start.x -= noc_connection_marker_quarter_width; link_coords.end.x -= noc_connection_marker_quarter_width; - } - else if (link_shift_direction == NocLinkShift::BOTTOM_SHIFT){ + } else if (link_shift_direction == NocLinkShift::BOTTOM_SHIFT) { // shift to the right link_coords.start.x += noc_connection_marker_quarter_width; link_coords.end.x += noc_connection_marker_quarter_width; @@ -190,12 +173,11 @@ void shift_noc_link(noc_link_draw_coords& link_coords, NocLinkShift link_shift_d // dont change anything if we arent shifting at all break; case NocLinkType::HORIZONTAL: - if (link_shift_direction == NocLinkShift::TOP_SHIFT){ + if (link_shift_direction == NocLinkShift::TOP_SHIFT) { // shift the link up link_coords.start.y += noc_connection_marker_quarter_height; link_coords.end.y += noc_connection_marker_quarter_height; - } - else if (link_shift_direction == NocLinkShift::BOTTOM_SHIFT){ + } else if (link_shift_direction == NocLinkShift::BOTTOM_SHIFT) { // shift to the down link_coords.start.y -= noc_connection_marker_quarter_height; link_coords.end.y -= noc_connection_marker_quarter_height; @@ -203,15 +185,14 @@ void shift_noc_link(noc_link_draw_coords& link_coords, NocLinkShift link_shift_d // dont change anything if we arent shifting at all break; case NocLinkType::POSITVE_SLOPE: - if (link_shift_direction == NocLinkShift::TOP_SHIFT){ + if (link_shift_direction == NocLinkShift::TOP_SHIFT) { // shift link up and left to the top left corner link_coords.start.x -= noc_connection_marker_quarter_width; link_coords.end.x -= noc_connection_marker_quarter_width; link_coords.start.y += noc_connection_marker_quarter_height; link_coords.end.y += noc_connection_marker_quarter_height; - } - else if (link_shift_direction == NocLinkShift::BOTTOM_SHIFT){ + } else if (link_shift_direction == NocLinkShift::BOTTOM_SHIFT) { // shift link down and right to the bottom right corner link_coords.start.x += noc_connection_marker_quarter_width; link_coords.end.x += noc_connection_marker_quarter_width; @@ -222,15 +203,14 @@ void shift_noc_link(noc_link_draw_coords& link_coords, NocLinkShift link_shift_d // dont change anything if we arent shifting at all break; case NocLinkType::NEGATIVE_SLOPE: - if (link_shift_direction == NocLinkShift::TOP_SHIFT){ + if (link_shift_direction == NocLinkShift::TOP_SHIFT) { // shift link down and left to the bottom left corner link_coords.start.x -= noc_connection_marker_quarter_width; link_coords.end.x -= noc_connection_marker_quarter_width; link_coords.start.y -= noc_connection_marker_quarter_height; link_coords.end.y -= noc_connection_marker_quarter_height; - } - else if (link_shift_direction == NocLinkShift::BOTTOM_SHIFT){ + } else if (link_shift_direction == NocLinkShift::BOTTOM_SHIFT) { // shift link up and right to the top right corner link_coords.start.x += noc_connection_marker_quarter_width; link_coords.end.x += noc_connection_marker_quarter_width; @@ -242,11 +222,7 @@ void shift_noc_link(noc_link_draw_coords& link_coords, NocLinkShift link_shift_d break; default: break; - } + } return; } - - - - diff --git a/vpr/src/draw/draw_noc.h b/vpr/src/draw/draw_noc.h index ef5f7c0c236..5465966f067 100644 --- a/vpr/src/draw/draw_noc.h +++ b/vpr/src/draw/draw_noc.h @@ -1,11 +1,11 @@ #ifndef DRAW_NOC_H #define DRAW_NOC_H /* - THis file contains functions and data types related to drawing the NoC in the canvas. - - The functions here should be used to determine how the NoC links should be drawn. - -*/ + * THis file contains functions and data types related to drawing the NoC in the canvas. + * + * The functions here should be used to determine how the NoC links should be drawn. + * + */ #include #include @@ -23,7 +23,6 @@ struct noc_link_draw_coords { ezgl::point2d end; }; - // define the types of orientations we will see links draw in in the canvas // vertical defines a vertical line // horizontal defines a horizontal line @@ -38,44 +37,18 @@ enum NocLinkType { }; /* - Since the noc links run in both directions between any two routers, we want to draw them parallel to each other instead of ovrelapping them. So the idea is to shift one link in one direction and shift the other link in the opposite direction. THe enum below defines the direction a link was shifted, so for example if we had a vertical line, top would be mean shift left and Bottom would mean shift right. SImilarily, if we had a horizontal line, top would mean shift up and bottom would mean shift down. -*/ + * Since the noc links run in both directions between any two routers, we want to draw them parallel to each other instead of ovrelapping them. So the idea is to shift one link in one direction and shift the other link in the opposite direction. THe enum below defines the direction a link was shifted, so for example if we had a vertical line, top would be mean shift left and Bottom would mean shift right. SImilarily, if we had a horizontal line, top would mean shift up and bottom would mean shift down. + */ enum NocLinkShift { NO_SHIFT, // initially there is no shift TOP_SHIFT, BOTTOM_SHIFT }; -void determine_direction_to_shift_noc_links(vtr::vector& list_of_noc_link_shift_directions); +void determine_direction_to_shift_noc_links(vtr::vector& list_of_noc_link_shift_directions); NocLinkType determine_noc_link_type(ezgl::point2d link_start_point, ezgl::point2d link_end_point); void shift_noc_link(noc_link_draw_coords& link_coords, NocLinkShift link_shift_direction, NocLinkType link_type, double noc_connection_marker_quarter_width, double noc_connection_marker_quarter_height); - - - - - - - - - - - - - - - - - - - - - - - - - - #endif \ No newline at end of file diff --git a/vpr/src/draw/draw_types.h b/vpr/src/draw/draw_types.h index 091c4b287c6..6c7d74bf596 100644 --- a/vpr/src/draw/draw_types.h +++ b/vpr/src/draw/draw_types.h @@ -119,11 +119,11 @@ enum e_edge_dir { }; /* - Defines the type of drawings that can be generated for the NoC. - DRAW_NO_NOC -> user did not select the option to draw the NoC - DRAW_NOC_LINKS -> display the NoC links and how they are connected to each other - DRAW_NOC_LINK_USAGE -> Display the NoC links (same as DRAW_NOC_LINKS) and color the links based on their bandwidth usage -*/ + * Defines the type of drawings that can be generated for the NoC. + * DRAW_NO_NOC -> user did not select the option to draw the NoC + * DRAW_NOC_LINKS -> display the NoC links and how they are connected to each other + * DRAW_NOC_LINK_USAGE -> Display the NoC links (same as DRAW_NOC_LINKS) and color the links based on their bandwidth usage + */ enum e_draw_noc { DRAW_NO_NOC = 0, DRAW_NOC_LINKS, @@ -212,7 +212,7 @@ struct t_draw_state { ManualMovesState manual_moves_state; bool show_noc_button = false; e_draw_noc draw_noc = DRAW_NO_NOC; - std::shared_ptr noc_usage_color_map = nullptr; + std::shared_ptr noc_usage_color_map = nullptr; // color map used to display noc link bandwidth usage std::vector list_of_breakpoints; diff --git a/vpr/test/test_noc_storage.cpp b/vpr/test/test_noc_storage.cpp index be64c65ebea..7ec1719a45a 100644 --- a/vpr/test/test_noc_storage.cpp +++ b/vpr/test/test_noc_storage.cpp @@ -11,271 +11,234 @@ // range [1, NUM_OF_ROUTERS - 1] #define NOC_CONNECTIVITY 10 - namespace { - TEST_CASE("test_adding_routers_to_noc_storage", "[vpr_noc]") { - - // setup random number generation - std::random_device device; - std::mt19937 rand_num_gen(device()); - std::uniform_int_distribution dist(0,NUM_OF_ROUTERS); - - // create a vector routers that we will use as the golden vector set - std::vector golden_set; - - // individual router parameters - int curr_router_id; - int router_grid_position_x; - int router_grid_position_y; - - // testing datastructure - NocStorage test_noc; +TEST_CASE("test_adding_routers_to_noc_storage", "[vpr_noc]") { + // setup random number generation + std::random_device device; + std::mt19937 rand_num_gen(device()); + std::uniform_int_distribution dist(0, NUM_OF_ROUTERS); - NocRouterId converted_id; + // create a vector routers that we will use as the golden vector set + std::vector golden_set; + // individual router parameters + int curr_router_id; + int router_grid_position_x; + int router_grid_position_y; - // add all the routers to noc_storage and populate the golden router set - for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++) - { - // determine the current router parameters - curr_router_id = router_number; - router_grid_position_x = router_number + dist(rand_num_gen); - router_grid_position_y = router_number + dist(rand_num_gen); - - // add router to the golden vector - golden_set.emplace_back(router_number, router_grid_position_x, router_grid_position_y); - - // add tje router to the noc - test_noc.add_router(curr_router_id, router_grid_position_x, router_grid_position_y); - - } - - // now verify that the routers were added properly by reading the routers back from the noc and comparing them to the golden set - for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++) - { - // get the converted router id - converted_id = (NocRouterId)router_number; + // testing datastructure + NocStorage test_noc; - // compare all the router properties - REQUIRE(golden_set[router_number].get_router_id() == test_noc.get_noc_router_id(converted_id)); + NocRouterId converted_id; - REQUIRE(golden_set[router_number].get_router_grid_position_x() == test_noc.get_noc_router_grid_position_x(converted_id)); + // add all the routers to noc_storage and populate the golden router set + for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++) { + // determine the current router parameters + curr_router_id = router_number; + router_grid_position_x = router_number + dist(rand_num_gen); + router_grid_position_y = router_number + dist(rand_num_gen); - REQUIRE(golden_set[router_number].get_router_grid_position_y() == test_noc.get_noc_router_grid_position_y(converted_id)); - } + // add router to the golden vector + golden_set.emplace_back(router_number, router_grid_position_x, router_grid_position_y); + // add tje router to the noc + test_noc.add_router(curr_router_id, router_grid_position_x, router_grid_position_y); } - TEST_CASE("test_router_id_conversion", "[vpr_noc]") { - - // setup random number generation - std::random_device device; - std::mt19937 rand_num_gen(device()); - std::uniform_int_distribution dist(0,NUM_OF_ROUTERS); - - // create a vector routers that we will use as the golden vector set - std::vector golden_set; - - // individual router parameters - int curr_router_id; - int router_grid_position_x; - int router_grid_position_y; - - // testing datastructure - NocStorage test_noc; - - NocRouterId converted_id; - - - // add all the routers to noc_storage and populate the golden router set - for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++) - { - // determine the current router parameters - curr_router_id = router_number; - router_grid_position_x = router_number + dist(rand_num_gen); - router_grid_position_y = router_number + dist(rand_num_gen); - - // add router to the golden vector - golden_set.emplace_back(router_number, router_grid_position_x, router_grid_position_y); - - // add tje router to the noc - test_noc.add_router(curr_router_id, router_grid_position_x, router_grid_position_y); - } - - // now verify that the routers were added properly by reading the routers back from the noc and comparing them to the golden set - for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++) - { - // get the converted router id - converted_id = test_noc.convert_router_id(router_number); + // now verify that the routers were added properly by reading the routers back from the noc and comparing them to the golden set + for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++) { + // get the converted router id + converted_id = (NocRouterId)router_number; - // compare all the router properties - REQUIRE(golden_set[router_number].get_router_id() == test_noc.get_noc_router_id(converted_id)); + // compare all the router properties + REQUIRE(golden_set[router_number].get_router_id() == test_noc.get_noc_router_id(converted_id)); - REQUIRE(golden_set[router_number].get_router_grid_position_x() == test_noc.get_noc_router_grid_position_x(converted_id)); - - REQUIRE(golden_set[router_number].get_router_grid_position_y() == test_noc.get_noc_router_grid_position_y(converted_id)); - } + REQUIRE(golden_set[router_number].get_router_grid_position_x() == test_noc.get_noc_router_grid_position_x(converted_id)); + REQUIRE(golden_set[router_number].get_router_grid_position_y() == test_noc.get_noc_router_grid_position_y(converted_id)); + } +} +TEST_CASE("test_router_id_conversion", "[vpr_noc]") { + // setup random number generation + std::random_device device; + std::mt19937 rand_num_gen(device()); + std::uniform_int_distribution dist(0, NUM_OF_ROUTERS); + + // create a vector routers that we will use as the golden vector set + std::vector golden_set; + + // individual router parameters + int curr_router_id; + int router_grid_position_x; + int router_grid_position_y; + + // testing datastructure + NocStorage test_noc; + + NocRouterId converted_id; + + // add all the routers to noc_storage and populate the golden router set + for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++) { + // determine the current router parameters + curr_router_id = router_number; + router_grid_position_x = router_number + dist(rand_num_gen); + router_grid_position_y = router_number + dist(rand_num_gen); + + // add router to the golden vector + golden_set.emplace_back(router_number, router_grid_position_x, router_grid_position_y); + + // add tje router to the noc + test_noc.add_router(curr_router_id, router_grid_position_x, router_grid_position_y); } - TEST_CASE("test_add_link", "[vpr_noc]") { - // create a vector to store the golden links - std::vector golden_set; + // now verify that the routers were added properly by reading the routers back from the noc and comparing them to the golden set + for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++) { + // get the converted router id + converted_id = test_noc.convert_router_id(router_number); - // temp variables that hold the noc link properties - NocRouterId source; - NocRouterId sink; + // compare all the router properties + REQUIRE(golden_set[router_number].get_router_id() == test_noc.get_noc_router_id(converted_id)); - NocLinkId link_id; + REQUIRE(golden_set[router_number].get_router_grid_position_x() == test_noc.get_noc_router_grid_position_x(converted_id)); - // testing datastructure - NocStorage test_noc; + REQUIRE(golden_set[router_number].get_router_grid_position_y() == test_noc.get_noc_router_grid_position_y(converted_id)); + } +} +TEST_CASE("test_add_link", "[vpr_noc]") { + // create a vector to store the golden links + std::vector golden_set; - int total_num_of_links = NUM_OF_ROUTERS * NOC_CONNECTIVITY; + // temp variables that hold the noc link properties + NocRouterId source; + NocRouterId sink; - // noc router stuff (we need routers before being able to add links) - int router_id = 0; - int curr_router_x_pos = 0; - int curr_router_y_pos = 0; + NocLinkId link_id; - // add all the routers to noc_storage and populate the golden router set - for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++) - { - // determine the current router parameters - router_id = router_number; + // testing datastructure + NocStorage test_noc; - // add tje router to the noc - test_noc.add_router(router_id, curr_router_x_pos, curr_router_y_pos); + int total_num_of_links = NUM_OF_ROUTERS * NOC_CONNECTIVITY; - } + // noc router stuff (we need routers before being able to add links) + int router_id = 0; + int curr_router_x_pos = 0; + int curr_router_y_pos = 0; - // allocate the size for the links - test_noc.make_room_for_noc_router_link_list(); + // add all the routers to noc_storage and populate the golden router set + for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++) { + // determine the current router parameters + router_id = router_number; - for (int source_router_id = 0; source_router_id < NUM_OF_ROUTERS; source_router_id++) - { - source = (NocRouterId)source_router_id; + // add tje router to the noc + test_noc.add_router(router_id, curr_router_x_pos, curr_router_y_pos); + } + // allocate the size for the links + test_noc.make_room_for_noc_router_link_list(); - for (int sink_router_id = 0; sink_router_id < NOC_CONNECTIVITY; sink_router_id++) - { - sink = (NocRouterId)sink_router_id; + for (int source_router_id = 0; source_router_id < NUM_OF_ROUTERS; source_router_id++) { + source = (NocRouterId)source_router_id; - // makes sure we do not create a link for a router who acts as a sink and source - if (source_router_id != sink_router_id) - { - // add link to the golden reference - golden_set.emplace_back(source, sink); + for (int sink_router_id = 0; sink_router_id < NOC_CONNECTIVITY; sink_router_id++) { + sink = (NocRouterId)sink_router_id; - // add the link to the NoC - test_noc.add_link(source, sink); - } + // makes sure we do not create a link for a router who acts as a sink and source + if (source_router_id != sink_router_id) { + // add link to the golden reference + golden_set.emplace_back(source, sink); + // add the link to the NoC + test_noc.add_link(source, sink); } } - - // verify that the links were added properly to the NoC - for (int link_number = 0; link_number < total_num_of_links; link_number++) - { - link_id = (NocLinkId)link_number; - - // verify the link by checking its properties - REQUIRE(golden_set[link_number].get_source_router() == test_noc.get_noc_link_source_router(link_id)); - - REQUIRE(golden_set[link_number].get_sink_router() == test_noc.get_noc_link_sink_router(link_id)); - } - } - TEST_CASE("test_router_link_list", "[vpr_noc]") - { - // create a vector to store the golden links - vtr::vector> golden_set; - // list of router connections returned from the NoC - std::vector router_links; + // verify that the links were added properly to the NoC + for (int link_number = 0; link_number < total_num_of_links; link_number++) { + link_id = (NocLinkId)link_number; - golden_set.resize(NUM_OF_ROUTERS); + // verify the link by checking its properties + REQUIRE(golden_set[link_number].get_source_router() == test_noc.get_noc_link_source_router(link_id)); - // temp variables that hold the noc link properties - NocRouterId source; - NocRouterId sink; + REQUIRE(golden_set[link_number].get_sink_router() == test_noc.get_noc_link_sink_router(link_id)); + } +} +TEST_CASE("test_router_link_list", "[vpr_noc]") { + // create a vector to store the golden links + vtr::vector> golden_set; - NocLinkId link_id; + // list of router connections returned from the NoC + std::vector router_links; - // testing datastructure - NocStorage test_noc; + golden_set.resize(NUM_OF_ROUTERS); - // need to assign + // temp variables that hold the noc link properties + NocRouterId source; + NocRouterId sink; - int curr_link_number = 0; + NocLinkId link_id; - int connection_size; + // testing datastructure + NocStorage test_noc; - // noc router stuff (we need routers before being able to add links) - int router_id = 0; - int curr_router_x_pos = 0; - int curr_router_y_pos = 0; + // need to assign - // add all the routers to noc_storage and populate the golden router set - for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++) - { - // determine the current router parameters - router_id = router_number; + int curr_link_number = 0; - // add tje router to the noc - test_noc.add_router(router_id, curr_router_x_pos, curr_router_y_pos); + int connection_size; - } + // noc router stuff (we need routers before being able to add links) + int router_id = 0; + int curr_router_x_pos = 0; + int curr_router_y_pos = 0; - // allocate the size for the links - test_noc.make_room_for_noc_router_link_list(); + // add all the routers to noc_storage and populate the golden router set + for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++) { + // determine the current router parameters + router_id = router_number; - for (int source_router_id = 0; source_router_id < NUM_OF_ROUTERS; source_router_id++) - { - source = (NocRouterId)source_router_id; + // add tje router to the noc + test_noc.add_router(router_id, curr_router_x_pos, curr_router_y_pos); + } - for (int sink_router_id = 0; sink_router_id < NOC_CONNECTIVITY; sink_router_id++) - { - sink = (NocRouterId)sink_router_id; + // allocate the size for the links + test_noc.make_room_for_noc_router_link_list(); - // makes sure we do not create a link for a router who acts as a sink and source - if (source_router_id != sink_router_id) - { - // add the link to the NoC - test_noc.add_link(source, sink); + for (int source_router_id = 0; source_router_id < NUM_OF_ROUTERS; source_router_id++) { + source = (NocRouterId)source_router_id; - // add the link id to the golden set - golden_set[source].push_back((NocLinkId)curr_link_number); + for (int sink_router_id = 0; sink_router_id < NOC_CONNECTIVITY; sink_router_id++) { + sink = (NocRouterId)sink_router_id; - curr_link_number++; - } + // makes sure we do not create a link for a router who acts as a sink and source + if (source_router_id != sink_router_id) { + // add the link to the NoC + test_noc.add_link(source, sink); - + // add the link id to the golden set + golden_set[source].push_back((NocLinkId)curr_link_number); + curr_link_number++; } } + } - // now verify that the connection lists were created correctly - for (int id = 0; id < NUM_OF_ROUTERS; id++) - { - // get the current router id - source = (NocRouterId)id; + // now verify that the connection lists were created correctly + for (int id = 0; id < NUM_OF_ROUTERS; id++) { + // get the current router id + source = (NocRouterId)id; - // get the router connections from the - router_links = test_noc.get_noc_router_connections(source); - - // get the size of the current router connection list - connection_size = golden_set[source].size(); + // get the router connections from the + router_links = test_noc.get_noc_router_connections(source); - // go through the links from the noc and make sure they match the golden set - for (int link_index = 0; link_index < connection_size; link_index++) - { - REQUIRE(golden_set[source][link_index] == router_links[link_index]); - - } + // get the size of the current router connection list + connection_size = golden_set[source].size(); + // go through the links from the noc and make sure they match the golden set + for (int link_index = 0; link_index < connection_size; link_index++) { + REQUIRE(golden_set[source][link_index] == router_links[link_index]); } - } -} \ No newline at end of file +} +} // namespace \ No newline at end of file diff --git a/vpr/test/test_setup_noc.cpp b/vpr/test/test_setup_noc.cpp index 430fdf9f880..d26582186b8 100644 --- a/vpr/test/test_setup_noc.cpp +++ b/vpr/test/test_setup_noc.cpp @@ -8,996 +8,948 @@ // for comparing floats #include "vtr_math.h" -namespace{ - - TEST_CASE("test_identify_and_store_noc_router_tile_positions", "[vpr_setup_noc]"){ +namespace { - // test device grid name - std::string device_grid_name = "test"; - - // creating a reference for the empty tile name and router name - char empty_tile_name[6] = "empty"; - char router_tile_name[7] = "router"; - - // device grid parameters - int test_grid_width = 10; - int test_grid_height = 10; - - // create the test device grid (10x10) - auto test_grid = vtr::Matrix({10, 10}); +TEST_CASE("test_identify_and_store_noc_router_tile_positions", "[vpr_setup_noc]") { + // test device grid name + std::string device_grid_name = "test"; - // create an empty physical tile and assign its parameters - t_physical_tile_type empty_tile; - empty_tile.name = empty_tile_name; - empty_tile.height = 1; - empty_tile.width = 1; - - // create a router tile and assign its parameters - // the router will take up 4 grid spaces and be named "router" - t_physical_tile_type router_tile; - router_tile.name = router_tile_name; - router_tile.height = 2; - router_tile.width = 2; + // creating a reference for the empty tile name and router name + char empty_tile_name[6] = "empty"; + char router_tile_name[7] = "router"; - // name of the router physical tile - //std::string router_tile_name_string("router"); - - // results from the test function - std::vector list_of_routers; - - // make sure the test result is not corrupted - REQUIRE(list_of_routers.size() == 0); - - - SECTION("All routers are seperated by one or more grid spaces"){ - - // in this test, the routers will be on the 4 corners of the FPGA - - // bottom left corner - test_grid[0][0].type = &router_tile; - test_grid[0][0].height_offset = 0; - test_grid[0][0].width_offset = 0; - - test_grid[1][0].type = &router_tile; - test_grid[1][0].height_offset = 0; - test_grid[1][0].width_offset = 1; - - test_grid[0][1].type = &router_tile; - test_grid[0][1].height_offset = 1; - test_grid[0][1].width_offset = 0; - - test_grid[1][1].type = &router_tile; - test_grid[1][1].height_offset = 1; - test_grid[1][1].width_offset = 1; - - // bottom right corner - test_grid[8][0].type = &router_tile; - test_grid[8][0].height_offset = 0; - test_grid[8][0].width_offset = 0; - - test_grid[9][0].type = &router_tile; - test_grid[9][0].height_offset = 0; - test_grid[9][0].width_offset = 1; - - test_grid[8][1].type = &router_tile; - test_grid[8][1].height_offset = 1; - test_grid[8][1].width_offset = 0; - - test_grid[9][1].type = &router_tile; - test_grid[9][1].height_offset = 1; - test_grid[9][1].width_offset = 1; - - // top left corner - test_grid[0][8].type = &router_tile; - test_grid[0][8].height_offset = 0; - test_grid[0][8].width_offset = 0; - - test_grid[1][8].type = &router_tile; - test_grid[1][8].height_offset = 0; - test_grid[1][8].width_offset = 1; - - test_grid[0][9].type = &router_tile; - test_grid[0][9].height_offset = 1; - test_grid[0][9].width_offset = 0; - - test_grid[1][9].type = &router_tile; - test_grid[1][9].height_offset = 1; - test_grid[1][9].width_offset = 1; - - // top right corner - test_grid[8][8].type = &router_tile; - test_grid[8][8].height_offset = 0; - test_grid[8][8].width_offset = 0; - - test_grid[9][8].type = &router_tile; - test_grid[9][8].height_offset = 0; - test_grid[9][8].width_offset = 1; - - test_grid[8][9].type = &router_tile; - test_grid[8][9].height_offset = 1; - test_grid[8][9].width_offset = 0; - - test_grid[9][9].type = &router_tile; - test_grid[9][9].height_offset = 1; - test_grid[9][9].width_offset = 1; - - for(int i = 0; i < test_grid_width; i++) - { - for(int j = 0; j < test_grid_height; j++) - { - // make sure the current tyle is not a router - if (test_grid[i][j].type == nullptr) - { - // assign the non-router tile as empty - test_grid[i][j].type = &empty_tile; - test_grid[i][j].width_offset = 0; - test_grid[i][j].height_offset = 0; - } + // device grid parameters + int test_grid_width = 10; + int test_grid_height = 10; + + // create the test device grid (10x10) + auto test_grid = vtr::Matrix({10, 10}); + + // create an empty physical tile and assign its parameters + t_physical_tile_type empty_tile; + empty_tile.name = empty_tile_name; + empty_tile.height = 1; + empty_tile.width = 1; + + // create a router tile and assign its parameters + // the router will take up 4 grid spaces and be named "router" + t_physical_tile_type router_tile; + router_tile.name = router_tile_name; + router_tile.height = 2; + router_tile.width = 2; + + // name of the router physical tile + //std::string router_tile_name_string("router"); + + // results from the test function + std::vector list_of_routers; + + // make sure the test result is not corrupted + REQUIRE(list_of_routers.size() == 0); + + SECTION("All routers are seperated by one or more grid spaces") { + // in this test, the routers will be on the 4 corners of the FPGA + + // bottom left corner + test_grid[0][0].type = &router_tile; + test_grid[0][0].height_offset = 0; + test_grid[0][0].width_offset = 0; + + test_grid[1][0].type = &router_tile; + test_grid[1][0].height_offset = 0; + test_grid[1][0].width_offset = 1; + + test_grid[0][1].type = &router_tile; + test_grid[0][1].height_offset = 1; + test_grid[0][1].width_offset = 0; + + test_grid[1][1].type = &router_tile; + test_grid[1][1].height_offset = 1; + test_grid[1][1].width_offset = 1; + + // bottom right corner + test_grid[8][0].type = &router_tile; + test_grid[8][0].height_offset = 0; + test_grid[8][0].width_offset = 0; + + test_grid[9][0].type = &router_tile; + test_grid[9][0].height_offset = 0; + test_grid[9][0].width_offset = 1; + + test_grid[8][1].type = &router_tile; + test_grid[8][1].height_offset = 1; + test_grid[8][1].width_offset = 0; + + test_grid[9][1].type = &router_tile; + test_grid[9][1].height_offset = 1; + test_grid[9][1].width_offset = 1; + + // top left corner + test_grid[0][8].type = &router_tile; + test_grid[0][8].height_offset = 0; + test_grid[0][8].width_offset = 0; + + test_grid[1][8].type = &router_tile; + test_grid[1][8].height_offset = 0; + test_grid[1][8].width_offset = 1; + + test_grid[0][9].type = &router_tile; + test_grid[0][9].height_offset = 1; + test_grid[0][9].width_offset = 0; + + test_grid[1][9].type = &router_tile; + test_grid[1][9].height_offset = 1; + test_grid[1][9].width_offset = 1; + + // top right corner + test_grid[8][8].type = &router_tile; + test_grid[8][8].height_offset = 0; + test_grid[8][8].width_offset = 0; + + test_grid[9][8].type = &router_tile; + test_grid[9][8].height_offset = 0; + test_grid[9][8].width_offset = 1; + + test_grid[8][9].type = &router_tile; + test_grid[8][9].height_offset = 1; + test_grid[8][9].width_offset = 0; + + test_grid[9][9].type = &router_tile; + test_grid[9][9].height_offset = 1; + test_grid[9][9].width_offset = 1; + + for (int i = 0; i < test_grid_width; i++) { + for (int j = 0; j < test_grid_height; j++) { + // make sure the current tyle is not a router + if (test_grid[i][j].type == nullptr) { + // assign the non-router tile as empty + test_grid[i][j].type = &empty_tile; + test_grid[i][j].width_offset = 0; + test_grid[i][j].height_offset = 0; } } - - // create a new device grid - DeviceGrid test_device = DeviceGrid(device_grid_name, test_grid); - - // call the test function - identify_and_store_noc_router_tile_positions(test_device, list_of_routers, std::string(router_tile_name)); - - // check that the physocal router tile positions were correctly determined - // make sure that only 4 router tiles were found - REQUIRE(list_of_routers.size() == 4); - - // 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)); - - // 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)); - - // 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)); - - // 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)); } - SECTION("All routers are horizontally connected to another router"){ - - // in this test, the routers will be on the 4 corners of the FPGA - - // bottom left corner - test_grid[3][0].type = &router_tile; - test_grid[3][0].height_offset = 0; - test_grid[3][0].width_offset = 0; - - test_grid[4][0].type = &router_tile; - test_grid[4][0].height_offset = 0; - test_grid[4][0].width_offset = 1; - - test_grid[3][1].type = &router_tile; - test_grid[3][1].height_offset = 1; - test_grid[3][1].width_offset = 0; - - test_grid[4][1].type = &router_tile; - test_grid[4][1].height_offset = 1; - test_grid[4][1].width_offset = 1; - - // bottom right corner - test_grid[5][0].type = &router_tile; - test_grid[5][0].height_offset = 0; - test_grid[5][0].width_offset = 0; - - test_grid[6][0].type = &router_tile; - test_grid[6][0].height_offset = 0; - test_grid[6][0].width_offset = 1; - - test_grid[5][1].type = &router_tile; - test_grid[5][1].height_offset = 1; - test_grid[5][1].width_offset = 0; - - test_grid[6][1].type = &router_tile; - test_grid[6][1].height_offset = 1; - test_grid[6][1].width_offset = 1; - - // top left corner - test_grid[0][5].type = &router_tile; - test_grid[0][5].height_offset = 0; - test_grid[0][5].width_offset = 0; - - test_grid[1][5].type = &router_tile; - test_grid[1][5].height_offset = 0; - test_grid[1][5].width_offset = 1; - - test_grid[0][6].type = &router_tile; - test_grid[0][6].height_offset = 1; - test_grid[0][6].width_offset = 0; - - test_grid[1][6].type = &router_tile; - test_grid[1][6].height_offset = 1; - test_grid[1][6].width_offset = 1; - - // top right corner - test_grid[2][5].type = &router_tile; - test_grid[2][5].height_offset = 0; - test_grid[2][5].width_offset = 0; - - test_grid[3][5].type = &router_tile; - test_grid[3][5].height_offset = 0; - test_grid[3][5].width_offset = 1; - - test_grid[2][6].type = &router_tile; - test_grid[2][6].height_offset = 1; - test_grid[2][6].width_offset = 0; - - test_grid[3][6].type = &router_tile; - test_grid[3][6].height_offset = 1; - test_grid[3][6].width_offset = 1; - - for(int i = 0; i < test_grid_width; i++) - { - for(int j = 0; j < test_grid_height; j++) - { - // make sure the current tyle is not a router - if (test_grid[i][j].type == nullptr) - { - // assign the non-router tile as empty - test_grid[i][j].type = &empty_tile; - test_grid[i][j].width_offset = 0; - test_grid[i][j].height_offset = 0; - } - } - } - // create a new device grid - DeviceGrid test_device = DeviceGrid(device_grid_name, test_grid); - - // call the test function - identify_and_store_noc_router_tile_positions(test_device, list_of_routers, std::string(router_tile_name)); - - // check that the physocal router tile positions were correctly determined - // make sure that only 4 router tiles were found - REQUIRE(list_of_routers.size() == 4); - - // 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)); - - // 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)); - - // 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)); - - // 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)); - } - SECTION("All routers are vertically connected to another router"){ - - // in this test, the routers will be on the 4 corners of the FPGA - - // bottom left corner - test_grid[0][2].type = &router_tile; - test_grid[0][2].height_offset = 0; - test_grid[0][2].width_offset = 0; - - test_grid[1][2].type = &router_tile; - test_grid[1][2].height_offset = 0; - test_grid[1][2].width_offset = 1; - - test_grid[0][3].type = &router_tile; - test_grid[0][3].height_offset = 1; - test_grid[0][3].width_offset = 0; - - test_grid[1][3].type = &router_tile; - test_grid[1][3].height_offset = 1; - test_grid[1][3].width_offset = 1; - - // bottom right corner - test_grid[0][4].type = &router_tile; - test_grid[0][4].height_offset = 0; - test_grid[0][4].width_offset = 0; - - test_grid[1][4].type = &router_tile; - test_grid[1][4].height_offset = 0; - test_grid[1][4].width_offset = 1; - - test_grid[0][5].type = &router_tile; - test_grid[0][5].height_offset = 1; - test_grid[0][5].width_offset = 0; - - test_grid[1][5].type = &router_tile; - test_grid[1][5].height_offset = 1; - test_grid[1][5].width_offset = 1; - - // top left corner - test_grid[7][6].type = &router_tile; - test_grid[7][6].height_offset = 0; - test_grid[7][6].width_offset = 0; - - test_grid[8][6].type = &router_tile; - test_grid[8][6].height_offset = 0; - test_grid[8][6].width_offset = 1; - - test_grid[7][7].type = &router_tile; - test_grid[7][7].height_offset = 1; - test_grid[7][7].width_offset = 0; - - test_grid[8][7].type = &router_tile; - test_grid[8][7].height_offset = 1; - test_grid[8][7].width_offset = 1; - - // top right corner - test_grid[7][8].type = &router_tile; - test_grid[7][8].height_offset = 0; - test_grid[7][8].width_offset = 0; - - test_grid[8][8].type = &router_tile; - test_grid[8][8].height_offset = 0; - test_grid[8][8].width_offset = 1; - - test_grid[7][9].type = &router_tile; - test_grid[7][9].height_offset = 1; - test_grid[7][9].width_offset = 0; - - test_grid[8][9].type = &router_tile; - test_grid[8][9].height_offset = 1; - test_grid[8][9].width_offset = 1; - - for(int i = 0; i < test_grid_width; i++) - { - for(int j = 0; j < test_grid_height; j++) - { - // make sure the current tyle is not a router - if (test_grid[i][j].type == nullptr) - { - // assign the non-router tile as empty - test_grid[i][j].type = &empty_tile; - test_grid[i][j].width_offset = 0; - test_grid[i][j].height_offset = 0; - } + // create a new device grid + DeviceGrid test_device = DeviceGrid(device_grid_name, test_grid); + + // call the test function + identify_and_store_noc_router_tile_positions(test_device, list_of_routers, std::string(router_tile_name)); + + // check that the physocal router tile positions were correctly determined + // make sure that only 4 router tiles were found + REQUIRE(list_of_routers.size() == 4); + + // 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)); + + // 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)); + + // 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)); + + // 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)); + } + SECTION("All routers are horizontally connected to another router") { + // in this test, the routers will be on the 4 corners of the FPGA + + // bottom left corner + test_grid[3][0].type = &router_tile; + test_grid[3][0].height_offset = 0; + test_grid[3][0].width_offset = 0; + + test_grid[4][0].type = &router_tile; + test_grid[4][0].height_offset = 0; + test_grid[4][0].width_offset = 1; + + test_grid[3][1].type = &router_tile; + test_grid[3][1].height_offset = 1; + test_grid[3][1].width_offset = 0; + + test_grid[4][1].type = &router_tile; + test_grid[4][1].height_offset = 1; + test_grid[4][1].width_offset = 1; + + // bottom right corner + test_grid[5][0].type = &router_tile; + test_grid[5][0].height_offset = 0; + test_grid[5][0].width_offset = 0; + + test_grid[6][0].type = &router_tile; + test_grid[6][0].height_offset = 0; + test_grid[6][0].width_offset = 1; + + test_grid[5][1].type = &router_tile; + test_grid[5][1].height_offset = 1; + test_grid[5][1].width_offset = 0; + + test_grid[6][1].type = &router_tile; + test_grid[6][1].height_offset = 1; + test_grid[6][1].width_offset = 1; + + // top left corner + test_grid[0][5].type = &router_tile; + test_grid[0][5].height_offset = 0; + test_grid[0][5].width_offset = 0; + + test_grid[1][5].type = &router_tile; + test_grid[1][5].height_offset = 0; + test_grid[1][5].width_offset = 1; + + test_grid[0][6].type = &router_tile; + test_grid[0][6].height_offset = 1; + test_grid[0][6].width_offset = 0; + + test_grid[1][6].type = &router_tile; + test_grid[1][6].height_offset = 1; + test_grid[1][6].width_offset = 1; + + // top right corner + test_grid[2][5].type = &router_tile; + test_grid[2][5].height_offset = 0; + test_grid[2][5].width_offset = 0; + + test_grid[3][5].type = &router_tile; + test_grid[3][5].height_offset = 0; + test_grid[3][5].width_offset = 1; + + test_grid[2][6].type = &router_tile; + test_grid[2][6].height_offset = 1; + test_grid[2][6].width_offset = 0; + + test_grid[3][6].type = &router_tile; + test_grid[3][6].height_offset = 1; + test_grid[3][6].width_offset = 1; + + for (int i = 0; i < test_grid_width; i++) { + for (int j = 0; j < test_grid_height; j++) { + // make sure the current tyle is not a router + if (test_grid[i][j].type == nullptr) { + // assign the non-router tile as empty + test_grid[i][j].type = &empty_tile; + test_grid[i][j].width_offset = 0; + test_grid[i][j].height_offset = 0; } } - - // create a new device grid - DeviceGrid test_device = DeviceGrid(device_grid_name, test_grid); - - // call the test function - identify_and_store_noc_router_tile_positions(test_device, list_of_routers, std::string(router_tile_name)); - - // check that the physocal router tile positions were correctly determined - // make sure that only 4 router tiles were found - REQUIRE(list_of_routers.size() == 4); - - // 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)); - - // 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)); - - // 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)); - - // 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)); } + // create a new device grid + DeviceGrid test_device = DeviceGrid(device_grid_name, test_grid); + + // call the test function + identify_and_store_noc_router_tile_positions(test_device, list_of_routers, std::string(router_tile_name)); + + // check that the physocal router tile positions were correctly determined + // make sure that only 4 router tiles were found + REQUIRE(list_of_routers.size() == 4); + + // 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)); + + // 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)); + + // 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)); + + // 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)); } - TEST_CASE("test_create_noc_routers", "[vpr_setup_noc]"){ - - // datastructure to hold the list of physical tiles - std::vector list_of_routers; - - /* - Setup: - - The router will take over a 2x3 grid area - - The NoC will be a 3x3 Mesh topology and located at - the following positions: - - router 1: (0,0) - - router 2: (4,0) - - router 3: (8,0) - - router 4: (0,4) - - router 5: (4,4) - - router 6: (8,4) - - router 7: (0,8) - - router 8: (4,8) - - router 9: (8,8) - */ - list_of_routers.push_back({0,0,0.5,1}); - list_of_routers.push_back({4,0,4.5,1}); - list_of_routers.push_back({8,0,8.5,1}); - - list_of_routers.push_back({0,4,0.5,5}); - list_of_routers.push_back({4,4,4.5,5}); - list_of_routers.push_back({8,4,8.5,5}); - - list_of_routers.push_back({0,8,0.5,9}); - list_of_routers.push_back({4,8,4.5,9}); - list_of_routers.push_back({8,8,8.5,9}); - - // create the noc model (to store the routers) - NocStorage noc_model; - - // create the logical router list - t_noc_inf noc_info; - - // pointer to each logical router - t_router* temp_router = NULL; - - const vtr::vector* noc_routers = NULL; - - SECTION("Test create routers when logical routers match to exactly one physical router. The number of routers is less than whats on the FPGA."){ - - // start by creating all the logical routers - // this is similiar to the user provided a config file - temp_router = new t_router; - - NocRouterId noc_router_id; - - for (int router_id = 1; router_id < 7; router_id++){ - - // we will have 6 logical routers that will take up the bottom and middle physical routers of the mesh - temp_router->device_x_position = list_of_routers[router_id-1].tile_centroid_x; - temp_router->device_y_position = list_of_routers[router_id-1].tile_centroid_y; - temp_router->id = router_id; - noc_info.router_list.push_back(*temp_router); + SECTION("All routers are vertically connected to another router") { + // in this test, the routers will be on the 4 corners of the FPGA + + // bottom left corner + test_grid[0][2].type = &router_tile; + test_grid[0][2].height_offset = 0; + test_grid[0][2].width_offset = 0; + + test_grid[1][2].type = &router_tile; + test_grid[1][2].height_offset = 0; + test_grid[1][2].width_offset = 1; + + test_grid[0][3].type = &router_tile; + test_grid[0][3].height_offset = 1; + test_grid[0][3].width_offset = 0; + + test_grid[1][3].type = &router_tile; + test_grid[1][3].height_offset = 1; + test_grid[1][3].width_offset = 1; + + // bottom right corner + test_grid[0][4].type = &router_tile; + test_grid[0][4].height_offset = 0; + test_grid[0][4].width_offset = 0; + + test_grid[1][4].type = &router_tile; + test_grid[1][4].height_offset = 0; + test_grid[1][4].width_offset = 1; + + test_grid[0][5].type = &router_tile; + test_grid[0][5].height_offset = 1; + test_grid[0][5].width_offset = 0; + + test_grid[1][5].type = &router_tile; + test_grid[1][5].height_offset = 1; + test_grid[1][5].width_offset = 1; + + // top left corner + test_grid[7][6].type = &router_tile; + test_grid[7][6].height_offset = 0; + test_grid[7][6].width_offset = 0; + + test_grid[8][6].type = &router_tile; + test_grid[8][6].height_offset = 0; + test_grid[8][6].width_offset = 1; + + test_grid[7][7].type = &router_tile; + test_grid[7][7].height_offset = 1; + test_grid[7][7].width_offset = 0; + + test_grid[8][7].type = &router_tile; + test_grid[8][7].height_offset = 1; + test_grid[8][7].width_offset = 1; + + // top right corner + test_grid[7][8].type = &router_tile; + test_grid[7][8].height_offset = 0; + test_grid[7][8].width_offset = 0; + + test_grid[8][8].type = &router_tile; + test_grid[8][8].height_offset = 0; + test_grid[8][8].width_offset = 1; + + test_grid[7][9].type = &router_tile; + test_grid[7][9].height_offset = 1; + test_grid[7][9].width_offset = 0; + + test_grid[8][9].type = &router_tile; + test_grid[8][9].height_offset = 1; + test_grid[8][9].width_offset = 1; + + for (int i = 0; i < test_grid_width; i++) { + for (int j = 0; j < test_grid_height; j++) { + // make sure the current tyle is not a router + if (test_grid[i][j].type == nullptr) { + // assign the non-router tile as empty + test_grid[i][j].type = &empty_tile; + test_grid[i][j].width_offset = 0; + test_grid[i][j].height_offset = 0; + } } + } - // delete the router struct - delete temp_router; - - // call the router creation - create_noc_routers(noc_info, &noc_model, list_of_routers); - - // get the routers from the noc - noc_routers = &(noc_model.get_noc_routers()); - - // first check that only 6 routers were created - REQUIRE(noc_routers->size() == 6); - - // now we got through the noc model and confirm that the correct - for (int router_id = 1; router_id < 7; router_id++) - { - // covert the router id - noc_router_id = noc_model.convert_router_id(router_id); + // create a new device grid + DeviceGrid test_device = DeviceGrid(device_grid_name, test_grid); + + // call the test function + identify_and_store_noc_router_tile_positions(test_device, list_of_routers, std::string(router_tile_name)); + + // check that the physocal router tile positions were correctly determined + // make sure that only 4 router tiles were found + REQUIRE(list_of_routers.size() == 4); + + // 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)); + + // 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)); + + // 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)); + + // 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)); + } +} +TEST_CASE("test_create_noc_routers", "[vpr_setup_noc]") { + // datastructure to hold the list of physical tiles + std::vector list_of_routers; + + /* + * Setup: + * - The router will take over a 2x3 grid area + * - The NoC will be a 3x3 Mesh topology and located at + * the following positions: + * - router 1: (0,0) + * - router 2: (4,0) + * - router 3: (8,0) + * - router 4: (0,4) + * - router 5: (4,4) + * - router 6: (8,4) + * - router 7: (0,8) + * - router 8: (4,8) + * - router 9: (8,8) + */ + list_of_routers.push_back({0, 0, 0.5, 1}); + list_of_routers.push_back({4, 0, 4.5, 1}); + list_of_routers.push_back({8, 0, 8.5, 1}); + + list_of_routers.push_back({0, 4, 0.5, 5}); + list_of_routers.push_back({4, 4, 4.5, 5}); + list_of_routers.push_back({8, 4, 8.5, 5}); + + list_of_routers.push_back({0, 8, 0.5, 9}); + list_of_routers.push_back({4, 8, 4.5, 9}); + list_of_routers.push_back({8, 8, 8.5, 9}); + + // create the noc model (to store the routers) + NocStorage noc_model; + + // create the logical router list + t_noc_inf noc_info; + + // pointer to each logical router + t_router* temp_router = NULL; + + const vtr::vector* noc_routers = NULL; + + SECTION("Test create routers when logical routers match to exactly one physical router. The number of routers is less than whats on the FPGA.") { + // start by creating all the logical routers + // this is similiar to the user provided a config file + temp_router = new t_router; - // now check that the proper physical router was assigned to - REQUIRE(noc_model.get_noc_router_grid_position_x(noc_router_id) == list_of_routers[router_id-1].grid_width_position); - REQUIRE(noc_model.get_noc_router_grid_position_y(noc_router_id) == list_of_routers[router_id-1].grid_height_position); + NocRouterId noc_router_id; - } + for (int router_id = 1; router_id < 7; router_id++) { + // we will have 6 logical routers that will take up the bottom and middle physical routers of the mesh + temp_router->device_x_position = list_of_routers[router_id - 1].tile_centroid_x; + temp_router->device_y_position = list_of_routers[router_id - 1].tile_centroid_y; + temp_router->id = router_id; + noc_info.router_list.push_back(*temp_router); } - SECTION("Test create routers when logical routers match to exactly one physical router. The number of routers is exacrly the same as on the FPGA."){ - // start by creating all the logical routers - // this is similiar to the user provided a config file - temp_router = new t_router; - - NocRouterId noc_router_id; - - for (int router_id = 1; router_id < 10; router_id++){ - - // we will have 6 logical routers that will take up the bottom and middle physical routers of the mesh - temp_router->device_x_position = list_of_routers[router_id-1].tile_centroid_x; - temp_router->device_y_position = list_of_routers[router_id-1].tile_centroid_y; - temp_router->id = router_id; - noc_info.router_list.push_back(*temp_router); - } + // delete the router struct + delete temp_router; - // delete the router struct - delete temp_router; + // call the router creation + create_noc_routers(noc_info, &noc_model, list_of_routers); - // call the router creation - create_noc_routers(noc_info, &noc_model, list_of_routers); + // get the routers from the noc + noc_routers = &(noc_model.get_noc_routers()); - // get the routers from the noc - noc_routers = &(noc_model.get_noc_routers()); + // first check that only 6 routers were created + REQUIRE(noc_routers->size() == 6); - // first check that only 6 routers were created - REQUIRE(noc_routers->size() == 9); + // now we got through the noc model and confirm that the correct + for (int router_id = 1; router_id < 7; router_id++) { + // covert the router id + noc_router_id = noc_model.convert_router_id(router_id); - // now we got through the noc model and confirm that the correct - for (int router_id = 1; router_id < 10; router_id++) - { - // covert the router id - noc_router_id = noc_model.convert_router_id(router_id); + // now check that the proper physical router was assigned to + REQUIRE(noc_model.get_noc_router_grid_position_x(noc_router_id) == list_of_routers[router_id - 1].grid_width_position); + REQUIRE(noc_model.get_noc_router_grid_position_y(noc_router_id) == list_of_routers[router_id - 1].grid_height_position); + } + } + SECTION("Test create routers when logical routers match to exactly one physical router. The number of routers is exacrly the same as on the FPGA.") { + // start by creating all the logical routers + // this is similiar to the user provided a config file + temp_router = new t_router; - // now check that the proper physical router was assigned to - REQUIRE(noc_model.get_noc_router_grid_position_x(noc_router_id) == list_of_routers[router_id-1].grid_width_position); - REQUIRE(noc_model.get_noc_router_grid_position_y(noc_router_id) == list_of_routers[router_id-1].grid_height_position); + NocRouterId noc_router_id; - } + for (int router_id = 1; router_id < 10; router_id++) { + // we will have 6 logical routers that will take up the bottom and middle physical routers of the mesh + temp_router->device_x_position = list_of_routers[router_id - 1].tile_centroid_x; + temp_router->device_y_position = list_of_routers[router_id - 1].tile_centroid_y; + temp_router->id = router_id; + noc_info.router_list.push_back(*temp_router); } - SECTION("Test create routers when a logical router can be matched to two physical routers. The number of routers is exactly the same as on the FPGA."){ - // start by creating all the logical routers - // this is similiar to the user provided a config file - temp_router = new t_router; + // delete the router struct + delete temp_router; - NocRouterId noc_router_id; + // call the router creation + create_noc_routers(noc_info, &noc_model, list_of_routers); - for (int router_id = 1; router_id < 9; router_id++){ - - // we will have 6 logical routers that will take up the bottom and middle physical routers of the mesh - temp_router->device_x_position = list_of_routers[router_id-1].tile_centroid_x; - temp_router->device_y_position = list_of_routers[router_id-1].tile_centroid_y; - temp_router->id = router_id; - noc_info.router_list.push_back(*temp_router); - } + // get the routers from the noc + noc_routers = &(noc_model.get_noc_routers()); - // the top right logical router will be between the top right and top center physical routers in the mesh - temp_router->device_x_position = 6.5; - temp_router->device_y_position = 9; - temp_router->id = 9; - noc_info.router_list.push_back(*temp_router); + // first check that only 6 routers were created + REQUIRE(noc_routers->size() == 9); - // delete the router struct - delete temp_router; + // now we got through the noc model and confirm that the correct + for (int router_id = 1; router_id < 10; router_id++) { + // covert the router id + noc_router_id = noc_model.convert_router_id(router_id); - // call the router creation - REQUIRE_THROWS_WITH(create_noc_routers(noc_info, &noc_model, list_of_routers), "Router with ID:'9' has the same distance to physical router tiles located at position (4,8) and (8,8). Therefore, no router assignment could be made."); + // now check that the proper physical router was assigned to + REQUIRE(noc_model.get_noc_router_grid_position_x(noc_router_id) == list_of_routers[router_id - 1].grid_width_position); + REQUIRE(noc_model.get_noc_router_grid_position_y(noc_router_id) == list_of_routers[router_id - 1].grid_height_position); } - SECTION("Test create routers when a physical router can be matched to two logical routers. The number of routers is exactly the same as on the FPGA."){ - - // start by creating all the logical routers - // this is similiar to the user provided a config file - temp_router = new t_router; - - NocRouterId noc_router_id; + } + SECTION("Test create routers when a logical router can be matched to two physical routers. The number of routers is exactly the same as on the FPGA.") { + // start by creating all the logical routers + // this is similiar to the user provided a config file + temp_router = new t_router; - for (int router_id = 1; router_id < 9; router_id++){ - - // we will have 6 logical routers that will take up the bottom and middle physical routers of the mesh - temp_router->device_x_position = list_of_routers[router_id-1].tile_centroid_x; - temp_router->device_y_position = list_of_routers[router_id-1].tile_centroid_y; - temp_router->id = router_id; - noc_info.router_list.push_back(*temp_router); - } + NocRouterId noc_router_id; - // the top right logical router will be between the top right and top center physical routers in the mesh - temp_router->device_x_position = 4.8; - temp_router->device_y_position = 5.1; - temp_router->id = 9; + for (int router_id = 1; router_id < 9; router_id++) { + // we will have 6 logical routers that will take up the bottom and middle physical routers of the mesh + temp_router->device_x_position = list_of_routers[router_id - 1].tile_centroid_x; + temp_router->device_y_position = list_of_routers[router_id - 1].tile_centroid_y; + temp_router->id = router_id; noc_info.router_list.push_back(*temp_router); + } - // delete the router struct - delete temp_router; + // the top right logical router will be between the top right and top center physical routers in the mesh + temp_router->device_x_position = 6.5; + temp_router->device_y_position = 9; + temp_router->id = 9; + noc_info.router_list.push_back(*temp_router); - // call the router creation - REQUIRE_THROWS_WITH(create_noc_routers(noc_info, &noc_model, list_of_routers), "Routers with IDs:'9' and '5' are both closest to physical router tile located at (4,4) and the physical router could not be assigned multiple times."); - } - + // delete the router struct + delete temp_router; + // call the router creation + REQUIRE_THROWS_WITH(create_noc_routers(noc_info, &noc_model, list_of_routers), "Router with ID:'9' has the same distance to physical router tiles located at position (4,8) and (8,8). Therefore, no router assignment could be made."); } - TEST_CASE("test_create_noc_links", "[vpr_setup_noc]"){ - - // datastructure to hold the list of physical tiles - std::vector list_of_routers; - - /* - Setup: - - The router will take over a 2x3 grid area - - The NoC will be a 3x3 Mesh topology and located at - the following positions: - - router 1: (0,0) - - router 2: (4,0) - - router 3: (8,0) - - router 4: (0,4) - - router 5: (4,4) - - router 6: (8,4) - - router 7: (0,8) - - router 8: (4,8) - - router 9: (8,8) - */ - list_of_routers.push_back({0,0,0.5,1}); - list_of_routers.push_back({4,0,4.5,1}); - list_of_routers.push_back({8,0,8.5,1}); - - list_of_routers.push_back({0,4,0.5,5}); - list_of_routers.push_back({4,4,4.5,5}); - list_of_routers.push_back({8,4,8.5,5}); - - list_of_routers.push_back({0,8,0.5,9}); - list_of_routers.push_back({4,8,4.5,9}); - list_of_routers.push_back({8,8,8.5,9}); - - // create the noc model (to store the routers) - NocStorage noc_model; - - // create the logical router list - t_noc_inf noc_info; - - // pointer to each logical router - t_router* temp_router = NULL; - + SECTION("Test create routers when a physical router can be matched to two logical routers. The number of routers is exactly the same as on the FPGA.") { // start by creating all the logical routers - // this is similiar to the user provided a config file + // this is similiar to the user provided a config file temp_router = new t_router; - for (int router_id = 1; router_id < 10; router_id++){ - - // we will have 9 logical routers that will take up all physical routers - temp_router->device_x_position = list_of_routers[router_id-1].tile_centroid_x; - temp_router->device_y_position = list_of_routers[router_id-1].tile_centroid_y; + NocRouterId noc_router_id; + + for (int router_id = 1; router_id < 9; router_id++) { + // we will have 6 logical routers that will take up the bottom and middle physical routers of the mesh + temp_router->device_x_position = list_of_routers[router_id - 1].tile_centroid_x; + temp_router->device_y_position = list_of_routers[router_id - 1].tile_centroid_y; temp_router->id = router_id; noc_info.router_list.push_back(*temp_router); - - // add the router to the NoC - noc_model.add_router(router_id, list_of_routers[router_id-1].grid_width_position, list_of_routers[router_id-1].grid_height_position); } + // the top right logical router will be between the top right and top center physical routers in the mesh + temp_router->device_x_position = 4.8; + temp_router->device_y_position = 5.1; + temp_router->id = 9; + noc_info.router_list.push_back(*temp_router); + + // delete the router struct delete temp_router; - // need to add the links to the noc_info - // this will be a mesh structure - noc_info.router_list[0].connection_list.push_back(2); - noc_info.router_list[0].connection_list.push_back(4); + // call the router creation + REQUIRE_THROWS_WITH(create_noc_routers(noc_info, &noc_model, list_of_routers), "Routers with IDs:'9' and '5' are both closest to physical router tile located at (4,4) and the physical router could not be assigned multiple times."); + } +} +TEST_CASE("test_create_noc_links", "[vpr_setup_noc]") { + // datastructure to hold the list of physical tiles + std::vector list_of_routers; + + /* + * Setup: + * - The router will take over a 2x3 grid area + * - The NoC will be a 3x3 Mesh topology and located at + * the following positions: + * - router 1: (0,0) + * - router 2: (4,0) + * - router 3: (8,0) + * - router 4: (0,4) + * - router 5: (4,4) + * - router 6: (8,4) + * - router 7: (0,8) + * - router 8: (4,8) + * - router 9: (8,8) + */ + list_of_routers.push_back({0, 0, 0.5, 1}); + list_of_routers.push_back({4, 0, 4.5, 1}); + list_of_routers.push_back({8, 0, 8.5, 1}); + + list_of_routers.push_back({0, 4, 0.5, 5}); + list_of_routers.push_back({4, 4, 4.5, 5}); + list_of_routers.push_back({8, 4, 8.5, 5}); + + list_of_routers.push_back({0, 8, 0.5, 9}); + list_of_routers.push_back({4, 8, 4.5, 9}); + list_of_routers.push_back({8, 8, 8.5, 9}); + + // create the noc model (to store the routers) + NocStorage noc_model; + + // create the logical router list + t_noc_inf noc_info; + + // pointer to each logical router + t_router* temp_router = NULL; + + // start by creating all the logical routers + // this is similiar to the user provided a config file + temp_router = new t_router; + + for (int router_id = 1; router_id < 10; router_id++) { + // we will have 9 logical routers that will take up all physical routers + temp_router->device_x_position = list_of_routers[router_id - 1].tile_centroid_x; + temp_router->device_y_position = list_of_routers[router_id - 1].tile_centroid_y; + temp_router->id = router_id; + noc_info.router_list.push_back(*temp_router); + + // add the router to the NoC + noc_model.add_router(router_id, list_of_routers[router_id - 1].grid_width_position, list_of_routers[router_id - 1].grid_height_position); + } - noc_info.router_list[1].connection_list.push_back(1); - noc_info.router_list[1].connection_list.push_back(3); - noc_info.router_list[1].connection_list.push_back(5); + delete temp_router; - noc_info.router_list[2].connection_list.push_back(2); - noc_info.router_list[2].connection_list.push_back(6); + // need to add the links to the noc_info + // this will be a mesh structure + noc_info.router_list[0].connection_list.push_back(2); + noc_info.router_list[0].connection_list.push_back(4); - noc_info.router_list[3].connection_list.push_back(1); - noc_info.router_list[3].connection_list.push_back(5); - noc_info.router_list[3].connection_list.push_back(7); + noc_info.router_list[1].connection_list.push_back(1); + noc_info.router_list[1].connection_list.push_back(3); + noc_info.router_list[1].connection_list.push_back(5); - noc_info.router_list[4].connection_list.push_back(2); - noc_info.router_list[4].connection_list.push_back(4); - noc_info.router_list[4].connection_list.push_back(6); - noc_info.router_list[4].connection_list.push_back(8); + noc_info.router_list[2].connection_list.push_back(2); + noc_info.router_list[2].connection_list.push_back(6); - noc_info.router_list[5].connection_list.push_back(3); - noc_info.router_list[5].connection_list.push_back(5); - noc_info.router_list[5].connection_list.push_back(9); + noc_info.router_list[3].connection_list.push_back(1); + noc_info.router_list[3].connection_list.push_back(5); + noc_info.router_list[3].connection_list.push_back(7); - noc_info.router_list[6].connection_list.push_back(4); - noc_info.router_list[6].connection_list.push_back(8); + noc_info.router_list[4].connection_list.push_back(2); + noc_info.router_list[4].connection_list.push_back(4); + noc_info.router_list[4].connection_list.push_back(6); + noc_info.router_list[4].connection_list.push_back(8); - noc_info.router_list[7].connection_list.push_back(5); - noc_info.router_list[7].connection_list.push_back(7); - noc_info.router_list[7].connection_list.push_back(9); + noc_info.router_list[5].connection_list.push_back(3); + noc_info.router_list[5].connection_list.push_back(5); + noc_info.router_list[5].connection_list.push_back(9); - noc_info.router_list[8].connection_list.push_back(6); - noc_info.router_list[8].connection_list.push_back(8); + noc_info.router_list[6].connection_list.push_back(4); + noc_info.router_list[6].connection_list.push_back(8); - // call the function to test - create_noc_links(&noc_info, &noc_model); + noc_info.router_list[7].connection_list.push_back(5); + noc_info.router_list[7].connection_list.push_back(7); + noc_info.router_list[7].connection_list.push_back(9); - NocRouterId current_source_router; - NocRouterId current_destination_router; + noc_info.router_list[8].connection_list.push_back(6); + noc_info.router_list[8].connection_list.push_back(8); - std::vector::iterator router_connection; + // call the function to test + create_noc_links(&noc_info, &noc_model); - // now verify the created links - for(int router_id = 1; router_id < 10; router_id++) - { - current_source_router = noc_model.convert_router_id(router_id); + NocRouterId current_source_router; + NocRouterId current_destination_router; - router_connection = noc_info.router_list[router_id-1].connection_list.begin(); + std::vector::iterator router_connection; - for (auto noc_link = noc_model.get_noc_router_connections(current_source_router).begin(); noc_link != noc_model.get_noc_router_connections(current_source_router).begin(); noc_link++) - { - current_destination_router = noc_model.get_noc_link_sink_router(*noc_link); + // now verify the created links + for (int router_id = 1; router_id < 10; router_id++) { + current_source_router = noc_model.convert_router_id(router_id); - REQUIRE((noc_model.get_noc_router_id(current_destination_router)) == (*router_connection)); + router_connection = noc_info.router_list[router_id - 1].connection_list.begin(); - router_connection++; - } + for (auto noc_link = noc_model.get_noc_router_connections(current_source_router).begin(); noc_link != noc_model.get_noc_router_connections(current_source_router).begin(); noc_link++) { + current_destination_router = noc_model.get_noc_link_sink_router(*noc_link); + + REQUIRE((noc_model.get_noc_router_id(current_destination_router)) == (*router_connection)); + + router_connection++; } } - TEST_CASE("test_setup_noc", "[vpr_setup_noc]"){ +} +TEST_CASE("test_setup_noc", "[vpr_setup_noc]") { + // create the architecture object + t_arch arch; + + // create the logical router list + t_noc_inf noc_info; + + // pointer to each logical router + t_router* temp_router = NULL; + + // start by creating all the logical routers + // this is similiar to the user provided a config file + temp_router = new t_router; + + // datastructure to hold the list of physical tiles + std::vector list_of_routers; + + // get a mutable to the device context + auto& device_ctx = g_vpr_ctx.mutable_device(); + + // delete any previous device grid + device_ctx.grid.clear(); + + /* + * Setup: + * - The router will take over a 2x3 grid area + * - The NoC will be a 3x3 Mesh topology and located at + * the following positions: + * - router 1: (0,0) + * - router 2: (4,0) + * - router 3: (8,0) + * - router 4: (0,4) + * - router 5: (4,4) + * - router 6: (8,4) + * - router 7: (0,8) + * - router 8: (4,8) + * - router 9: (8,8) + */ + list_of_routers.push_back({0, 0, 0.5, 1}); + list_of_routers.push_back({4, 0, 4.5, 1}); + list_of_routers.push_back({8, 0, 8.5, 1}); + + list_of_routers.push_back({0, 4, 0.5, 5}); + list_of_routers.push_back({4, 4, 4.5, 5}); + list_of_routers.push_back({8, 4, 8.5, 5}); + + list_of_routers.push_back({0, 8, 0.5, 9}); + list_of_routers.push_back({4, 8, 4.5, 9}); + list_of_routers.push_back({8, 8, 8.5, 9}); + + for (int router_id = 1; router_id < 10; router_id++) { + // we will have 9 logical routers that will take up all physical routers + temp_router->device_x_position = list_of_routers[router_id - 1].tile_centroid_x; + temp_router->device_y_position = list_of_routers[router_id - 1].tile_centroid_y; + temp_router->id = router_id; + noc_info.router_list.push_back(*temp_router); + } - // create the architecture object - t_arch arch; + delete temp_router; - // create the logical router list - t_noc_inf noc_info; - - // pointer to each logical router - t_router* temp_router = NULL; - - // start by creating all the logical routers - // this is similiar to the user provided a config file - temp_router = new t_router; + // need to add the links to the noc_info + // this will be a mesh structure + noc_info.router_list[0].connection_list.push_back(2); + noc_info.router_list[0].connection_list.push_back(4); - // datastructure to hold the list of physical tiles - std::vector list_of_routers; - - // get a mutable to the device context - auto& device_ctx = g_vpr_ctx.mutable_device(); - - // delete any previous device grid - device_ctx.grid.clear(); - - /* - Setup: - - The router will take over a 2x3 grid area - - The NoC will be a 3x3 Mesh topology and located at - the following positions: - - router 1: (0,0) - - router 2: (4,0) - - router 3: (8,0) - - router 4: (0,4) - - router 5: (4,4) - - router 6: (8,4) - - router 7: (0,8) - - router 8: (4,8) - - router 9: (8,8) - */ - list_of_routers.push_back({0,0,0.5,1}); - list_of_routers.push_back({4,0,4.5,1}); - list_of_routers.push_back({8,0,8.5,1}); - - list_of_routers.push_back({0,4,0.5,5}); - list_of_routers.push_back({4,4,4.5,5}); - list_of_routers.push_back({8,4,8.5,5}); - - list_of_routers.push_back({0,8,0.5,9}); - list_of_routers.push_back({4,8,4.5,9}); - list_of_routers.push_back({8,8,8.5,9}); - - for (int router_id = 1; router_id < 10; router_id++){ - - // we will have 9 logical routers that will take up all physical routers - temp_router->device_x_position = list_of_routers[router_id-1].tile_centroid_x; - temp_router->device_y_position = list_of_routers[router_id-1].tile_centroid_y; - temp_router->id = router_id; - noc_info.router_list.push_back(*temp_router); + noc_info.router_list[1].connection_list.push_back(1); + noc_info.router_list[1].connection_list.push_back(3); + noc_info.router_list[1].connection_list.push_back(5); - } + noc_info.router_list[2].connection_list.push_back(2); + noc_info.router_list[2].connection_list.push_back(6); - delete temp_router; + noc_info.router_list[3].connection_list.push_back(1); + noc_info.router_list[3].connection_list.push_back(5); + noc_info.router_list[3].connection_list.push_back(7); - // need to add the links to the noc_info - // this will be a mesh structure - noc_info.router_list[0].connection_list.push_back(2); - noc_info.router_list[0].connection_list.push_back(4); - - noc_info.router_list[1].connection_list.push_back(1); - noc_info.router_list[1].connection_list.push_back(3); - noc_info.router_list[1].connection_list.push_back(5); - - noc_info.router_list[2].connection_list.push_back(2); - noc_info.router_list[2].connection_list.push_back(6); - - noc_info.router_list[3].connection_list.push_back(1); - noc_info.router_list[3].connection_list.push_back(5); - noc_info.router_list[3].connection_list.push_back(7); - - noc_info.router_list[4].connection_list.push_back(2); - noc_info.router_list[4].connection_list.push_back(4); - noc_info.router_list[4].connection_list.push_back(6); - noc_info.router_list[4].connection_list.push_back(8); - - noc_info.router_list[5].connection_list.push_back(3); - noc_info.router_list[5].connection_list.push_back(5); - noc_info.router_list[5].connection_list.push_back(9); - - noc_info.router_list[6].connection_list.push_back(4); - noc_info.router_list[6].connection_list.push_back(8); - - noc_info.router_list[7].connection_list.push_back(5); - noc_info.router_list[7].connection_list.push_back(7); - noc_info.router_list[7].connection_list.push_back(9); - - noc_info.router_list[8].connection_list.push_back(6); - noc_info.router_list[8].connection_list.push_back(8); - - //assign the noc_info to the arch - arch.noc = &noc_info; - - // the architecture file has been setup to include the noc topology and we set the parameters below - noc_info.link_bandwidth = 67.8; - noc_info.link_latency = 56.7; - noc_info.router_latency = 2.3; - - SECTION("Test setup_noc when the number of logical routers is more than the number of physical routers in the FPGA."){ - - // test device grid name - std::string device_grid_name = "test"; - - // creating a reference for the empty tile name and router name - char empty_tile_name[6] = "empty"; - char router_tile_name[7] = "router"; - - // device grid parameters - int test_grid_width = 10; - int test_grid_height = 10; - - // create the test device grid (10x10) - auto test_grid = vtr::Matrix({10, 10}); - - // create an empty physical tile and assign its parameters - t_physical_tile_type empty_tile; - empty_tile.name = empty_tile_name; - empty_tile.height = 1; - empty_tile.width = 1; - - // create a router tile and assign its parameters - // the router will take up 4 grid spaces and be named "router" - t_physical_tile_type router_tile; - router_tile.name = router_tile_name; - router_tile.height = 2; - router_tile.width = 2; - - // in this test, the routers will be on the 4 corners of the FPGA - - // bottom left corner - test_grid[0][0].type = &router_tile; - test_grid[0][0].height_offset = 0; - test_grid[0][0].width_offset = 0; - - test_grid[1][0].type = &router_tile; - test_grid[1][0].height_offset = 0; - test_grid[1][0].width_offset = 1; - - test_grid[0][1].type = &router_tile; - test_grid[0][1].height_offset = 1; - test_grid[0][1].width_offset = 0; - - test_grid[1][1].type = &router_tile; - test_grid[1][1].height_offset = 1; - test_grid[1][1].width_offset = 1; - - // bottom right corner - test_grid[8][0].type = &router_tile; - test_grid[8][0].height_offset = 0; - test_grid[8][0].width_offset = 0; - - test_grid[9][0].type = &router_tile; - test_grid[9][0].height_offset = 0; - test_grid[9][0].width_offset = 1; - - test_grid[8][1].type = &router_tile; - test_grid[8][1].height_offset = 1; - test_grid[8][1].width_offset = 0; - - test_grid[9][1].type = &router_tile; - test_grid[9][1].height_offset = 1; - test_grid[9][1].width_offset = 1; - - // top left corner - test_grid[0][8].type = &router_tile; - test_grid[0][8].height_offset = 0; - test_grid[0][8].width_offset = 0; - - test_grid[1][8].type = &router_tile; - test_grid[1][8].height_offset = 0; - test_grid[1][8].width_offset = 1; - - test_grid[0][9].type = &router_tile; - test_grid[0][9].height_offset = 1; - test_grid[0][9].width_offset = 0; - - test_grid[1][9].type = &router_tile; - test_grid[1][9].height_offset = 1; - test_grid[1][9].width_offset = 1; - - // top right corner - test_grid[8][8].type = &router_tile; - test_grid[8][8].height_offset = 0; - test_grid[8][8].width_offset = 0; - - test_grid[9][8].type = &router_tile; - test_grid[9][8].height_offset = 0; - test_grid[9][8].width_offset = 1; - - test_grid[8][9].type = &router_tile; - test_grid[8][9].height_offset = 1; - test_grid[8][9].width_offset = 0; - - test_grid[9][9].type = &router_tile; - test_grid[9][9].height_offset = 1; - test_grid[9][9].width_offset = 1; - - for(int i = 0; i < test_grid_width; i++) - { - for(int j = 0; j < test_grid_height; j++) - { - // make sure the current tyle is not a router - if (test_grid[i][j].type == nullptr) - { - // assign the non-router tile as empty - test_grid[i][j].type = &empty_tile; - test_grid[i][j].width_offset = 0; - test_grid[i][j].height_offset = 0; - } - } - } + noc_info.router_list[4].connection_list.push_back(2); + noc_info.router_list[4].connection_list.push_back(4); + noc_info.router_list[4].connection_list.push_back(6); + noc_info.router_list[4].connection_list.push_back(8); - device_ctx.grid = DeviceGrid(device_grid_name, test_grid); + noc_info.router_list[5].connection_list.push_back(3); + noc_info.router_list[5].connection_list.push_back(5); + noc_info.router_list[5].connection_list.push_back(9); - REQUIRE_THROWS_WITH(setup_noc(arch, router_tile_name), "The Provided NoC topology information in the architecture file has more number of routers than what is available in the FPGA device."); + noc_info.router_list[6].connection_list.push_back(4); + noc_info.router_list[6].connection_list.push_back(8); - } - SECTION("Test setup_noc when there are no physical NoC routers on the FPGA."){ - - // test device grid name - std::string device_grid_name = "test"; - - // creating a reference for the empty tile name and router name - char empty_tile_name[6] = "empty"; - char router_tile_name[7] = "router"; - - // device grid parameters - int test_grid_width = 10; - int test_grid_height = 10; - - // create the test device grid (10x10) - auto test_grid = vtr::Matrix({10, 10}); - - // create an empty physical tile and assign its parameters - t_physical_tile_type empty_tile; - empty_tile.name = empty_tile_name; - empty_tile.height = 1; - empty_tile.width = 1; - - // create a router tile and assign its parameters - // the router will take up 4 grid spaces and be named "router" - t_physical_tile_type router_tile; - router_tile.name = router_tile_name; - router_tile.height = 2; - router_tile.width = 2; - - // in this test, there should be no physical router tiles ih the FPGA device and there should be no routers in the topology description - - for(int i = 0; i < test_grid_width; i++) - { - for(int j = 0; j < test_grid_height; j++) - { - // make sure the current tyle is not a router - if (test_grid[i][j].type == nullptr) - { - // assign the non-router tile as empty - test_grid[i][j].type = &empty_tile; - test_grid[i][j].width_offset = 0; - test_grid[i][j].height_offset = 0; - } + noc_info.router_list[7].connection_list.push_back(5); + noc_info.router_list[7].connection_list.push_back(7); + noc_info.router_list[7].connection_list.push_back(9); + + noc_info.router_list[8].connection_list.push_back(6); + noc_info.router_list[8].connection_list.push_back(8); + + //assign the noc_info to the arch + arch.noc = &noc_info; + + // the architecture file has been setup to include the noc topology and we set the parameters below + noc_info.link_bandwidth = 67.8; + noc_info.link_latency = 56.7; + noc_info.router_latency = 2.3; + + SECTION("Test setup_noc when the number of logical routers is more than the number of physical routers in the FPGA.") { + // test device grid name + std::string device_grid_name = "test"; + + // creating a reference for the empty tile name and router name + char empty_tile_name[6] = "empty"; + char router_tile_name[7] = "router"; + + // device grid parameters + int test_grid_width = 10; + int test_grid_height = 10; + + // create the test device grid (10x10) + auto test_grid = vtr::Matrix({10, 10}); + + // create an empty physical tile and assign its parameters + t_physical_tile_type empty_tile; + empty_tile.name = empty_tile_name; + empty_tile.height = 1; + empty_tile.width = 1; + + // create a router tile and assign its parameters + // the router will take up 4 grid spaces and be named "router" + t_physical_tile_type router_tile; + router_tile.name = router_tile_name; + router_tile.height = 2; + router_tile.width = 2; + + // in this test, the routers will be on the 4 corners of the FPGA + + // bottom left corner + test_grid[0][0].type = &router_tile; + test_grid[0][0].height_offset = 0; + test_grid[0][0].width_offset = 0; + + test_grid[1][0].type = &router_tile; + test_grid[1][0].height_offset = 0; + test_grid[1][0].width_offset = 1; + + test_grid[0][1].type = &router_tile; + test_grid[0][1].height_offset = 1; + test_grid[0][1].width_offset = 0; + + test_grid[1][1].type = &router_tile; + test_grid[1][1].height_offset = 1; + test_grid[1][1].width_offset = 1; + + // bottom right corner + test_grid[8][0].type = &router_tile; + test_grid[8][0].height_offset = 0; + test_grid[8][0].width_offset = 0; + + test_grid[9][0].type = &router_tile; + test_grid[9][0].height_offset = 0; + test_grid[9][0].width_offset = 1; + + test_grid[8][1].type = &router_tile; + test_grid[8][1].height_offset = 1; + test_grid[8][1].width_offset = 0; + + test_grid[9][1].type = &router_tile; + test_grid[9][1].height_offset = 1; + test_grid[9][1].width_offset = 1; + + // top left corner + test_grid[0][8].type = &router_tile; + test_grid[0][8].height_offset = 0; + test_grid[0][8].width_offset = 0; + + test_grid[1][8].type = &router_tile; + test_grid[1][8].height_offset = 0; + test_grid[1][8].width_offset = 1; + + test_grid[0][9].type = &router_tile; + test_grid[0][9].height_offset = 1; + test_grid[0][9].width_offset = 0; + + test_grid[1][9].type = &router_tile; + test_grid[1][9].height_offset = 1; + test_grid[1][9].width_offset = 1; + + // top right corner + test_grid[8][8].type = &router_tile; + test_grid[8][8].height_offset = 0; + test_grid[8][8].width_offset = 0; + + test_grid[9][8].type = &router_tile; + test_grid[9][8].height_offset = 0; + test_grid[9][8].width_offset = 1; + + test_grid[8][9].type = &router_tile; + test_grid[8][9].height_offset = 1; + test_grid[8][9].width_offset = 0; + + test_grid[9][9].type = &router_tile; + test_grid[9][9].height_offset = 1; + test_grid[9][9].width_offset = 1; + + for (int i = 0; i < test_grid_width; i++) { + for (int j = 0; j < test_grid_height; j++) { + // make sure the current tyle is not a router + if (test_grid[i][j].type == nullptr) { + // assign the non-router tile as empty + test_grid[i][j].type = &empty_tile; + test_grid[i][j].width_offset = 0; + test_grid[i][j].height_offset = 0; } } + } + + device_ctx.grid = DeviceGrid(device_grid_name, test_grid); + + REQUIRE_THROWS_WITH(setup_noc(arch, router_tile_name), "The Provided NoC topology information in the architecture file has more number of routers than what is available in the FPGA device."); + } + SECTION("Test setup_noc when there are no physical NoC routers on the FPGA.") { + // test device grid name + std::string device_grid_name = "test"; + + // creating a reference for the empty tile name and router name + char empty_tile_name[6] = "empty"; + char router_tile_name[7] = "router"; + + // device grid parameters + int test_grid_width = 10; + int test_grid_height = 10; - noc_info.router_list.clear(); + // create the test device grid (10x10) + auto test_grid = vtr::Matrix({10, 10}); - device_ctx.grid = DeviceGrid(device_grid_name, test_grid); + // create an empty physical tile and assign its parameters + t_physical_tile_type empty_tile; + empty_tile.name = empty_tile_name; + empty_tile.height = 1; + empty_tile.width = 1; + + // create a router tile and assign its parameters + // the router will take up 4 grid spaces and be named "router" + t_physical_tile_type router_tile; + router_tile.name = router_tile_name; + router_tile.height = 2; + router_tile.width = 2; - REQUIRE_THROWS_WITH(setup_noc(arch, router_tile_name), "No physical NoC routers were found on the FPGA device. Either the provided name for the physical router tile was incorrect or the FPGA device has no routers."); + // in this test, there should be no physical router tiles ih the FPGA device and there should be no routers in the topology description + for (int i = 0; i < test_grid_width; i++) { + for (int j = 0; j < test_grid_height; j++) { + // make sure the current tyle is not a router + if (test_grid[i][j].type == nullptr) { + // assign the non-router tile as empty + test_grid[i][j].type = &empty_tile; + test_grid[i][j].width_offset = 0; + test_grid[i][j].height_offset = 0; + } + } } + noc_info.router_list.clear(); + + device_ctx.grid = DeviceGrid(device_grid_name, test_grid); + + REQUIRE_THROWS_WITH(setup_noc(arch, router_tile_name), "No physical NoC routers were found on the FPGA device. Either the provided name for the physical router tile was incorrect or the FPGA device has no routers."); } +} -} \ No newline at end of file +} // namespace \ No newline at end of file From e6332d9be560c41c4fe3387fec54d93042ff424d Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 11 Apr 2022 22:45:52 -0400 Subject: [PATCH 059/128] Revert "added a function to log the options used when the NoC is enabled" This reverts commit fa16da2cea7f118d70b186b9514119b0b43b937a. --- vpr/src/base/ShowSetup.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/vpr/src/base/ShowSetup.cpp b/vpr/src/base/ShowSetup.cpp index d2570f1f4cb..782038c4a31 100644 --- a/vpr/src/base/ShowSetup.cpp +++ b/vpr/src/base/ShowSetup.cpp @@ -20,7 +20,6 @@ static void ShowPlacerOpts(const t_placer_opts& PlacerOpts, const t_annealing_sched& AnnealSched); static void ShowRouterOpts(const t_router_opts& RouterOpts); static void ShowAnalysisOpts(const t_analysis_opts& AnalysisOpts); -static void ShowNocOpts(const t_noc_opts& NocOpts); static void ShowAnnealSched(const t_annealing_sched& AnnealSched); @@ -62,9 +61,6 @@ void ShowSetup(const t_vpr_setup& vpr_setup) { if (vpr_setup.AnalysisOpts.doAnalysis) { ShowAnalysisOpts(vpr_setup.AnalysisOpts); } - if (vpr_setup.NocOpts.noc) { - ShowNocOpts(vpr_setup.NocOpts); - } } void ClusteredNetlistStats::writeHuman(std::ostream& output) const { @@ -768,10 +764,3 @@ static void ShowPackerOpts(const t_packer_opts& PackerOpts) { VTR_LOG("\n"); VTR_LOG("\n"); } - -static void ShowNocOpts(const t_noc_opts& NocOpts) { - // show options such as routing algorithm used - // name of the flows file - // etc... - return; -} From a142d1ba996f7b3bf6380533b0e68db8a2643036 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 11 Apr 2022 23:11:35 -0400 Subject: [PATCH 060/128] redefined static functions that were previously tested in test_vpr so its build wouldn't fail --- vpr/test/test_setup_noc.cpp | 191 +++++++++++++++++++++++++++++++++++- 1 file changed, 189 insertions(+), 2 deletions(-) diff --git a/vpr/test/test_setup_noc.cpp b/vpr/test/test_setup_noc.cpp index d26582186b8..051684f4743 100644 --- a/vpr/test/test_setup_noc.cpp +++ b/vpr/test/test_setup_noc.cpp @@ -8,6 +8,187 @@ // for comparing floats #include "vtr_math.h" +/*Re-defining static functions in setup_noc.cpp that are tested here*/ + + +static void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, std::vector& list_of_noc_router_tiles, std::string noc_router_tile_name) { + int grid_width = device_grid.width(); + int grid_height = device_grid.height(); + + int curr_tile_width; + int curr_tile_height; + int curr_tile_width_offset; + int curr_tile_height_offset; + std::string curr_tile_name; + + double curr_tile_centroid_x; + double curr_tile_centroid_y; + + // go through the device + for (int i = 0; i < grid_width; i++) { + for (int j = 0; j < grid_height; j++) { + // get some information from the current tile + curr_tile_name.assign(device_grid[i][j].type->name); + curr_tile_width_offset = device_grid[i][j].width_offset; + curr_tile_height_offset = device_grid[i][j].height_offset; + + curr_tile_height = device_grid[i][j].type->height; + curr_tile_width = device_grid[i][j].type->width; + + /* + * Only store the tile position if it is a noc router. + * Additionally, since a router tile can span multiple grid locations, we only add the tile if the height and width offset are zero (this prevents the router from being added multiple times for each grid location it spans). + */ + if (!(noc_router_tile_name.compare(curr_tile_name)) && !curr_tile_width_offset && !curr_tile_height_offset) { + // calculating the centroid position of the current tile + curr_tile_centroid_x = (curr_tile_width - 1) / (double)2 + i; + curr_tile_centroid_y = (curr_tile_height - 1) / (double)2 + j; + + list_of_noc_router_tiles.push_back({i, j, curr_tile_centroid_x, curr_tile_centroid_y}); + } + } + } + + return; +} + + + +static void create_noc_routers(const t_noc_inf& noc_info, NocStorage* noc_model, std::vector& list_of_noc_router_tiles) { + // keep track of the shortest distance between a logical router and the curren physical router tile + // also keep track of the corresponding physical router tile index (within the list) + double shortest_distance; + double curr_calculated_distance; + int closest_physical_router; + + // information regarding physical router position + double curr_physical_router_pos_x; + double curr_physical_router_pos_y; + + // information regarding logical router position + double curr_logical_router_position_x; + double curr_logical_router_position_y; + + // keep track of the index of each physical router (this helps uniqely identify them) + int curr_physical_router_index = 0; + + // keep track of the ids of the routers that ceate 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; + + // keep track of all the logical router and physical router assignments (their pairings) + std::vector router_assignments; + router_assignments.resize(list_of_noc_router_tiles.size(), PHYSICAL_ROUTER_NOT_ASSIGNED); + + // Below we create all the routers within the NoC // + + // go through each logical router tile and assign it to a physical router on the FPGA + for (auto logical_router = noc_info.router_list.begin(); logical_router != noc_info.router_list.end(); logical_router++) { + // assign the shortest distance to a large value (this is done so that the first distance calculated and we can replace this) + shortest_distance = LLONG_MAX; + + // get position of the current logical router + curr_logical_router_position_x = logical_router->device_x_position; + curr_logical_router_position_y = logical_router->device_y_position; + + closest_physical_router = 0; + + // the starting index of the physical router list + curr_physical_router_index = 0; + + // initialze the router ids that track the error case where two physical router tiles have the same distance to a logical router + // we initialize it to a in-valid index, so that it reflects the situation where we never hit this case + error_case_physical_router_index_1 = INVALID_PHYSICAL_ROUTER_INDEX; + error_case_physical_router_index_2 = INVALID_PHYSICAL_ROUTER_INDEX; + + // determine the physical router tile that is closest to the current logical router + for (auto physical_router = list_of_noc_router_tiles.begin(); physical_router != list_of_noc_router_tiles.end(); physical_router++) { + // get the position of the current physical router tile on the FPGA device + curr_physical_router_pos_x = physical_router->tile_centroid_x; + curr_physical_router_pos_y = physical_router->tile_centroid_y; + + // use euclidean distance to calculate the length between the current logical and physical routers + curr_calculated_distance = sqrt(pow(abs(curr_physical_router_pos_x - curr_logical_router_position_x), 2.0) + pow(abs(curr_physical_router_pos_y - curr_logical_router_position_y), 2.0)); + + // if the current distance is the same as the previous shortest distance + if (vtr::isclose(curr_calculated_distance, shortest_distance)) { + // store the ids of the two physical routers + error_case_physical_router_index_1 = closest_physical_router; + error_case_physical_router_index_2 = curr_physical_router_index; + + } else if (curr_calculated_distance < shortest_distance) // case where the current logical router is closest to the physical router tile + { + // update the shortest distance and then the closest router + shortest_distance = curr_calculated_distance; + closest_physical_router = curr_physical_router_index; + } + + // update the index for the next physical router + curr_physical_router_index++; + } + + // check the case where two physical router tiles have the same distance to the given logical router + if (error_case_physical_router_index_1 == closest_physical_router) { + VPR_FATAL_ERROR(VPR_ERROR_OTHER, + "Router with ID:'%d' has the same distance to physical router tiles located at position (%d,%d) and (%d,%d). Therefore, no router assignment could be made.", + logical_router->id, list_of_noc_router_tiles[error_case_physical_router_index_1].grid_width_position, list_of_noc_router_tiles[error_case_physical_router_index_1].grid_height_position, + list_of_noc_router_tiles[error_case_physical_router_index_2].grid_width_position, list_of_noc_router_tiles[error_case_physical_router_index_2].grid_height_position); + } + + // check if the current physical router was already assigned previously, if so then throw an error + if (router_assignments[closest_physical_router] != PHYSICAL_ROUTER_NOT_ASSIGNED) { + VPR_FATAL_ERROR(VPR_ERROR_OTHER, "Routers with IDs:'%d' and '%d' are both closest to physical router tile located at (%d,%d) and the physical router could not be assigned multiple times.", + logical_router->id, router_assignments[closest_physical_router], list_of_noc_router_tiles[closest_physical_router].grid_width_position, + list_of_noc_router_tiles[closest_physical_router].grid_height_position); + } + + // at this point, the closest logical router to the current physical router was found + // so add the router to the NoC + noc_model->add_router(logical_router->id, list_of_noc_router_tiles[closest_physical_router].grid_width_position, + list_of_noc_router_tiles[closest_physical_router].grid_height_position); + + // add the new assignment to the tracker + router_assignments[closest_physical_router] = logical_router->id; + } + + return; +} + +static void create_noc_links(const t_noc_inf* noc_info, NocStorage* noc_model) { + // the ids used to represent the routers in the NoC are not the same as the ones provided by the user in the arch desc file. + // while going through the router connections, the user provided router ids are converted and then stored below before being used + // in the links. + NocRouterId source_router; + NocRouterId sink_router; + + // store the id of each new link we create + NocLinkId created_link_id; + + // start of by creating enough space for the list of outgoing links for each router in the NoC + noc_model->make_room_for_noc_router_link_list(); + + // go through each router and add its outgoing links to the NoC + for (auto router = noc_info->router_list.begin(); router != noc_info->router_list.end(); router++) { + // get the converted id of the current source router + source_router = noc_model->convert_router_id(router->id); + + // go through all the routers connected to the current one and add links to the noc + for (auto conn_router_id = router->connection_list.begin(); conn_router_id != router->connection_list.end(); conn_router_id++) { + // get the converted id of the currently connected sink router + sink_router = noc_model->convert_router_id(*conn_router_id); + + // add the link to the Noc + noc_model->add_link(source_router, sink_router); + ; + } + } + + return; +} + +/*End of static function re-definition in setup_noc.cpp*/ + namespace { TEST_CASE("test_identify_and_store_noc_router_tile_positions", "[vpr_setup_noc]") { @@ -796,6 +977,9 @@ TEST_CASE("test_setup_noc", "[vpr_setup_noc]") { char empty_tile_name[6] = "empty"; char router_tile_name[7] = "router"; + // assign the name used when describing a router tile in the FPGA architecture description file + arch.noc->noc_router_tile_name.assign(router_tile_name); + // device grid parameters int test_grid_width = 10; int test_grid_height = 10; @@ -900,7 +1084,7 @@ TEST_CASE("test_setup_noc", "[vpr_setup_noc]") { device_ctx.grid = DeviceGrid(device_grid_name, test_grid); - REQUIRE_THROWS_WITH(setup_noc(arch, router_tile_name), "The Provided NoC topology information in the architecture file has more number of routers than what is available in the FPGA device."); + REQUIRE_THROWS_WITH(setup_noc(arch), "The Provided NoC topology information in the architecture file has more number of routers than what is available in the FPGA device."); } SECTION("Test setup_noc when there are no physical NoC routers on the FPGA.") { // test device grid name @@ -910,6 +1094,9 @@ TEST_CASE("test_setup_noc", "[vpr_setup_noc]") { char empty_tile_name[6] = "empty"; char router_tile_name[7] = "router"; + // assign the name used when describing a router tile in the FPGA architecture description file + arch.noc->noc_router_tile_name.assign(router_tile_name); + // device grid parameters int test_grid_width = 10; int test_grid_height = 10; @@ -948,7 +1135,7 @@ TEST_CASE("test_setup_noc", "[vpr_setup_noc]") { device_ctx.grid = DeviceGrid(device_grid_name, test_grid); - REQUIRE_THROWS_WITH(setup_noc(arch, router_tile_name), "No physical NoC routers were found on the FPGA device. Either the provided name for the physical router tile was incorrect or the FPGA device has no routers."); + REQUIRE_THROWS_WITH(setup_noc(arch), "No physical NoC routers were found on the FPGA device. Either the provided name for the physical router tile was incorrect or the FPGA device has no routers."); } } From 3c31e04b68cbbe2421bdd84b80e093c42b9f0432 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 12 Apr 2022 13:13:37 -0400 Subject: [PATCH 061/128] added directives to the draw noc related code so that there is no build failure when graphics isn't enabled --- vpr/src/base/noc_data_types.h | 2 +- vpr/src/base/vpr_api.cpp | 5 +++-- vpr/src/draw/draw_noc.cpp | 14 +++++++++----- vpr/src/draw/draw_noc.h | 6 +++++- vpr/test/test_setup_noc.cpp | 3 --- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/vpr/src/base/noc_data_types.h b/vpr/src/base/noc_data_types.h index ba6962dea6b..c99a57004d5 100644 --- a/vpr/src/base/noc_data_types.h +++ b/vpr/src/base/noc_data_types.h @@ -3,7 +3,7 @@ #include "vtr_strong_id.h" -// definitins data types used to index the routers and links within the noc +// data types used to index the routers and links within the noc struct noc_router_id_tag; struct noc_link_id_tag; diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index deb678f4a02..44565f36aed 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -503,17 +503,18 @@ void vpr_setup_clock_networks(t_vpr_setup& vpr_setup, const t_arch& Arch) { * description file. */ void vpr_setup_noc(const t_vpr_setup& vpr_setup, const t_arch& arch) { - t_draw_state* draw_state = get_draw_state_vars(); - // check if the user provided the option to model the noc if (vpr_setup.NocOpts.noc == true) { // create the NoC model based on the user description from the arch file setup_noc(arch); +#ifndef NO_GRAPHICS // setup the graphics // if the user turned on "noc" in the command line, then we also want them to have the option to display the noc, so set that option here to be able to display it. // if the "noc" was not turned on, then we don't need to provide the user with the option to display it + t_draw_state* draw_state = get_draw_state_vars(); draw_state->show_noc_button = true; +#endif } } diff --git a/vpr/src/draw/draw_noc.cpp b/vpr/src/draw/draw_noc.cpp index a3ad2475de2..72e77b96e7c 100644 --- a/vpr/src/draw/draw_noc.cpp +++ b/vpr/src/draw/draw_noc.cpp @@ -1,9 +1,11 @@ -#include "draw_noc.h" -#include "globals.h" -#include "noc_storage.h" -#include "vpr_error.h" -#include "vtr_math.h" +#ifndef NO_GRAPHICS + +# include "draw_noc.h" +# include "globals.h" +# include "noc_storage.h" +# include "vpr_error.h" +# include "vtr_math.h" /** * @brief For a NoC that is undirected, each connection between routers has two @@ -226,3 +228,5 @@ void shift_noc_link(noc_link_draw_coords& link_coords, NocLinkShift link_shift_d return; } + +#endif \ No newline at end of file diff --git a/vpr/src/draw/draw_noc.h b/vpr/src/draw/draw_noc.h index 5465966f067..abf23913ce8 100644 --- a/vpr/src/draw/draw_noc.h +++ b/vpr/src/draw/draw_noc.h @@ -9,7 +9,9 @@ #include #include -#include "draw.h" +#ifndef NO_GRAPHICS + +# include "draw.h" // defines the length of a reference horizontal line that is used in a cross product to calculate the angle between this line and a noc link to be drawn const double HORIZONTAL_LINE_LENGTH(5.0); @@ -51,4 +53,6 @@ NocLinkType determine_noc_link_type(ezgl::point2d link_start_point, ezgl::point2 void shift_noc_link(noc_link_draw_coords& link_coords, NocLinkShift link_shift_direction, NocLinkType link_type, double noc_connection_marker_quarter_width, double noc_connection_marker_quarter_height); +#endif + #endif \ No newline at end of file diff --git a/vpr/test/test_setup_noc.cpp b/vpr/test/test_setup_noc.cpp index 051684f4743..593bdb2699c 100644 --- a/vpr/test/test_setup_noc.cpp +++ b/vpr/test/test_setup_noc.cpp @@ -10,7 +10,6 @@ /*Re-defining static functions in setup_noc.cpp that are tested here*/ - static void identify_and_store_noc_router_tile_positions(const DeviceGrid& device_grid, std::vector& list_of_noc_router_tiles, std::string noc_router_tile_name) { int grid_width = device_grid.width(); int grid_height = device_grid.height(); @@ -52,8 +51,6 @@ static void identify_and_store_noc_router_tile_positions(const DeviceGrid& devic return; } - - static void create_noc_routers(const t_noc_inf& noc_info, NocStorage* noc_model, std::vector& list_of_noc_router_tiles) { // keep track of the shortest distance between a logical router and the curren physical router tile // also keep track of the corresponding physical router tile index (within the list) From 76342be1d175de77e05457852ea0e4d85098eb53 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 12 Apr 2022 17:41:00 -0400 Subject: [PATCH 062/128] fixed an issue with the NocStorage class unit test that caused a failure when running the Unit tests during a push --- vpr/test/test_noc_storage.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/vpr/test/test_noc_storage.cpp b/vpr/test/test_noc_storage.cpp index 7ec1719a45a..b632a06b35f 100644 --- a/vpr/test/test_noc_storage.cpp +++ b/vpr/test/test_noc_storage.cpp @@ -118,7 +118,8 @@ TEST_CASE("test_add_link", "[vpr_noc]") { // testing datastructure NocStorage test_noc; - int total_num_of_links = NUM_OF_ROUTERS * NOC_CONNECTIVITY; + // keeps track of the number of links created + int total_num_of_links = 0; // noc router stuff (we need routers before being able to add links) int router_id = 0; @@ -150,6 +151,8 @@ TEST_CASE("test_add_link", "[vpr_noc]") { // add the link to the NoC test_noc.add_link(source, sink); + + total_num_of_links++; } } } @@ -159,9 +162,9 @@ TEST_CASE("test_add_link", "[vpr_noc]") { link_id = (NocLinkId)link_number; // verify the link by checking its properties - REQUIRE(golden_set[link_number].get_source_router() == test_noc.get_noc_link_source_router(link_id)); + REQUIRE(test_noc.get_noc_router_id(golden_set[link_number].get_source_router()) == test_noc.get_noc_router_id(test_noc.get_noc_link_source_router(link_id))); - REQUIRE(golden_set[link_number].get_sink_router() == test_noc.get_noc_link_sink_router(link_id)); + REQUIRE(test_noc.get_noc_router_id(golden_set[link_number].get_sink_router()) == test_noc.get_noc_router_id(test_noc.get_noc_link_sink_router(link_id))); } } TEST_CASE("test_router_link_list", "[vpr_noc]") { From 3711019a58819f54458772cf2e7a22f29944431f Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 12 Apr 2022 22:31:07 -0400 Subject: [PATCH 063/128] fixed compiler issue when including catch test framework header --- libs/libarchfpga/test/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/libarchfpga/test/main.cpp b/libs/libarchfpga/test/main.cpp index 7d78b55d895..2a2e12d62b2 100644 --- a/libs/libarchfpga/test/main.cpp +++ b/libs/libarchfpga/test/main.cpp @@ -1,2 +1,2 @@ #define CATCH_CONFIG_MAIN -//#include "catch2/catch_test_macros.hpp" \ No newline at end of file +#include "catch2/catch_test_macros.hpp" \ No newline at end of file From 7b96833df53951a03e86ed2df7c59aaf040864ad Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 13 Apr 2022 12:45:56 -0400 Subject: [PATCH 064/128] modified the build procedure for libarchfpga so that the main.cpp file inside the src directory was used. Not doing this resultedin the main.cpp file inside the test folder also being used and this caused a failure in the github CI. Also note that this how other projects are also setup. --- libs/libarchfpga/CMakeLists.txt | 2 +- libs/libarchfpga/src/physical_types.h | 1 - vpr/src/base/read_options.h | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libs/libarchfpga/CMakeLists.txt b/libs/libarchfpga/CMakeLists.txt index 3901c8025eb..30b3c628ae9 100644 --- a/libs/libarchfpga/CMakeLists.txt +++ b/libs/libarchfpga/CMakeLists.txt @@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.9) project("libarchfpga") -file(GLOB_RECURSE EXEC_SOURCES main.cpp) +file(GLOB_RECURSE EXEC_SOURCES src/main.cpp) file(GLOB_RECURSE LIB_SOURCES src/*.cpp) file(GLOB_RECURSE LIB_HEADERS src/*.h) files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS) diff --git a/libs/libarchfpga/src/physical_types.h b/libs/libarchfpga/src/physical_types.h index 47a2fff04a6..1b11aa7253c 100644 --- a/libs/libarchfpga/src/physical_types.h +++ b/libs/libarchfpga/src/physical_types.h @@ -1771,7 +1771,6 @@ struct t_lut_element { bool operator==(const t_lut_element& other) const { return site_type == other.site_type && width == other.width && lut_bels == other.lut_bels; } - }; /* Network-on-chip(NoC) Router data type used to identify diff --git a/vpr/src/base/read_options.h b/vpr/src/base/read_options.h index 6ea53413637..b995c044b0d 100644 --- a/vpr/src/base/read_options.h +++ b/vpr/src/base/read_options.h @@ -137,7 +137,7 @@ struct t_options { argparse::ArgValue place_constraint_subtile; argparse::ArgValue floorplan_num_horizontal_partitions; argparse::ArgValue floorplan_num_vertical_partitions; - + /*NoC Options*/ argparse::ArgValue noc; From 22b407155b919e796bbc13d5959bbf2cb9bf97cc Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 13 Apr 2022 23:56:28 -0400 Subject: [PATCH 065/128] created a new datastructure to represent a noc traffic flow. Then added a vector of these flows inside the NoC context --- vpr/src/base/noc_data_types.h | 32 +++++++++++++++++++++++++++++++- vpr/src/base/vpr_context.h | 10 ++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/vpr/src/base/noc_data_types.h b/vpr/src/base/noc_data_types.h index c99a57004d5..65bea177336 100644 --- a/vpr/src/base/noc_data_types.h +++ b/vpr/src/base/noc_data_types.h @@ -2,13 +2,43 @@ #define NOC_DATA_TYPES_H #include "vtr_strong_id.h" +#include "atom_netlist_fwd.h" -// data types used to index the routers and links within the noc +#include +// data types used to index the routers and links within the noc struct noc_router_id_tag; struct noc_link_id_tag; typedef vtr::StrongId NocRouterId; typedef vtr::StrongId NocLinkId; +/* + Describes a traffic flow within the NoC, which is the communication between two routers. This description includes the following: + - The module names of the source and destination routers that are communicating with each other. The module name is the name used when instantiating a router module in the HDL design. + - The atom IDs of the router modules. By storing this, we can quickly lookup the router modules instead of identifying them by using their names. + - The bandwidth(size) of data being transferred between the two routers. + - The maximum allowable latency of the data transfer. + + This datastructure will be primarily used during placement to identify which routers inside the NoC(NocStorage) need to be routed to each other.This is important since the router modules can be moved around to different tiles on the FPGA device. Additionaly, once a the routing has been completed, the bandwidht and latency parameters can be used to calculate the cost of the placement of routers. +*/ +struct t_noc_traffic_flow { + + // router module names + std::string source_router_module_name; + std::string sink_router_module_name; + + // router module atom ids + AtomBlockId source_router_atom_id; + AtomBlockId sink_router_atom_id; + + // in bytes/s + double traffic_flow_bandwidth; + + // in seconds + double max_traffic_flow_latency; + +}; + + #endif \ No newline at end of file diff --git a/vpr/src/base/vpr_context.h b/vpr/src/base/vpr_context.h index b456bccaa9a..a76a283e2ac 100644 --- a/vpr/src/base/vpr_context.h +++ b/vpr/src/base/vpr_context.h @@ -416,6 +416,16 @@ struct NocContext : public Context { * @brief Represents the expected delay when going through a router */ double noc_router_latency; + + /** + * @brief Stores all the communication happening betwee routers in the NoC + * + * Contains a list of traffic flows that describe which two routers are communication with each other and also some metrics and constraints on the data transfer between the two routers. + * + * + * This is created from a user supplied .flows file. + */ + std::vector list_of_noc_traffic_flows; }; /** From 89232af21e7db0e0f9838a6c591180e22d706fdb Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 20 Apr 2022 22:13:44 -0400 Subject: [PATCH 066/128] Modified the noc traffic flows datastructure to add some new features --- vpr/src/base/vpr_context.h | 5 ++- vpr/src/noc/noc_traffic_flows.h | 79 +++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 vpr/src/noc/noc_traffic_flows.h diff --git a/vpr/src/base/vpr_context.h b/vpr/src/base/vpr_context.h index a76a283e2ac..2c25986a385 100644 --- a/vpr/src/base/vpr_context.h +++ b/vpr/src/base/vpr_context.h @@ -28,6 +28,7 @@ #include "metadata_storage.h" #include "vpr_constraints.h" #include "noc_storage.h" +#include "noc_traffic_flows.h" /** * @brief A Context is collection of state relating to a particular part of VPR @@ -420,12 +421,12 @@ struct NocContext : public Context { /** * @brief Stores all the communication happening betwee routers in the NoC * - * Contains a list of traffic flows that describe which two routers are communication with each other and also some metrics and constraints on the data transfer between the two routers. + * Contains all of the traffic flows that describe which two routers are communication with each other and also some metrics and constraints on the data transfer between the two routers. * * * This is created from a user supplied .flows file. */ - std::vector list_of_noc_traffic_flows; + NocTrafficFlows noc_traffic_flows_storage; }; /** diff --git a/vpr/src/noc/noc_traffic_flows.h b/vpr/src/noc/noc_traffic_flows.h new file mode 100644 index 00000000000..5e20c6ec6c0 --- /dev/null +++ b/vpr/src/noc/noc_traffic_flows.h @@ -0,0 +1,79 @@ +#ifndef NOC_TRAFFIC_FLOWS_H +#define NOC_TRAFFIC_FLOWS_H + +#include "clustered_netlist_fwd.h" +#include "noc_data_types.h" +#include +#include +#include + +/* + Describes a traffic flow within the NoC, which is the communication between two routers. This description includes the following: + - The module names of the source and destination routers that are communicating with each other. The module name is the name used when instantiating a router module in the HDL design. + - The atom IDs of the router modules. By storing this, we can quickly lookup the router modules instead of identifying them by using their names. + - The bandwidth(size) of data being transferred between the two routers. + - The maximum allowable latency of the data transfer. + + This datastructure will be primarily used during placement to identify which routers inside the NoC(NocStorage) need to be routed to each other.This is important since the router modules can be moved around to different tiles on the FPGA device. Additionaly, once a the routing has been completed, the bandwidht and latency parameters can be used to calculate the cost of the placement of routers. +*/ +struct t_noc_traffic_flow { + + // router module names + std::string source_router_module_name; + std::string sink_router_module_name; + + // router module atom ids + ClusterBlockId source_router_cluster_id; + ClusterBlockId sink_router_cluster_id; + + // in bytes/s + double traffic_flow_bandwidth; + + // in seconds + double max_traffic_flow_latency; + + // constructor + t_noc_traffic_flow(std::string source_router_name, std::string sink_router_name, ClusterBlockId source_router_id, ClusterBlockId sink_router_id, double flow_bandwidth, double max_flow_latency) : source_router_module_name(source_router_name), sink_router_module_name(sink_router_name), source_router_cluster_id(source_router_id), sink_router_cluster_id(sink_router_id), traffic_flow_bandwidth(flow_bandwidth), max_traffic_flow_latency(max_flow_latency) + {} + +}; + +class NocTrafficFlows +{ + private: + + vtr::vector list_of_noc_traffic_flows; + + std::unordered_map> source_router_associated_traffic_flows; + std::unordered_map> sink_router_associated_traffic_flows; + + vtr::vector processed_traffic_flows; + + // shouldnt have access to this functions + void add_traffic_flow_to_associated_source_and_sink_routers(NocTrafficFlowId traffic_flow_id); + + + public: + NocTrafficFlows(); + + //getters + const t_noc_traffic_flow& get_single_noc_traffic_flow(NocTrafficFlowId traffic_flow_id) const; + + const std::vector& get_traffic_flows_associated_to_source_router(ClusterBlockId source_router_id) const; + + const std::vector& get_traffic_flows_associated_to_sink_router(ClusterBlockId sink_router_id) const; + + + // setters + void create_noc_traffic_flow(std::string source_router_module_name, std::string sink_router_module_name, ClusterBlockId source_router_cluster_id, ClusterBlockId sink_router_cluster_id, double traffic_flow_bandwidth, double traffic_flow_latency); + + + //utility functions + void finshed_noc_traffic_flows_setup(void); + void reset_traffic_flows_processed_status(void); + void clear_traffic_flows(void); + +}; + + +#endif \ No newline at end of file From 72b4f96a61869c94cf898396bff23f3d04b35e33 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 20 Apr 2022 22:14:50 -0400 Subject: [PATCH 067/128] added a new strong id to index noc traffic flows --- vpr/src/base/noc_data_types.h | 30 +++--------------------------- 1 file changed, 3 insertions(+), 27 deletions(-) diff --git a/vpr/src/base/noc_data_types.h b/vpr/src/base/noc_data_types.h index 65bea177336..b86ec1b9c26 100644 --- a/vpr/src/base/noc_data_types.h +++ b/vpr/src/base/noc_data_types.h @@ -2,7 +2,6 @@ #define NOC_DATA_TYPES_H #include "vtr_strong_id.h" -#include "atom_netlist_fwd.h" #include @@ -13,32 +12,9 @@ struct noc_link_id_tag; typedef vtr::StrongId NocRouterId; typedef vtr::StrongId NocLinkId; -/* - Describes a traffic flow within the NoC, which is the communication between two routers. This description includes the following: - - The module names of the source and destination routers that are communicating with each other. The module name is the name used when instantiating a router module in the HDL design. - - The atom IDs of the router modules. By storing this, we can quickly lookup the router modules instead of identifying them by using their names. - - The bandwidth(size) of data being transferred between the two routers. - - The maximum allowable latency of the data transfer. - - This datastructure will be primarily used during placement to identify which routers inside the NoC(NocStorage) need to be routed to each other.This is important since the router modules can be moved around to different tiles on the FPGA device. Additionaly, once a the routing has been completed, the bandwidht and latency parameters can be used to calculate the cost of the placement of routers. -*/ -struct t_noc_traffic_flow { - - // router module names - std::string source_router_module_name; - std::string sink_router_module_name; - - // router module atom ids - AtomBlockId source_router_atom_id; - AtomBlockId sink_router_atom_id; - - // in bytes/s - double traffic_flow_bandwidth; - - // in seconds - double max_traffic_flow_latency; - -}; +// data type to index traffic flows within the noc +struct noc_traffic_flow_id_tag; +typedef vtr::StrongId NocTrafficFlowId; #endif \ No newline at end of file From e73fece1367808928525932e2ffcdcbf8a9e176f Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 22 Apr 2022 17:01:03 -0400 Subject: [PATCH 068/128] Added a new variable to keep track of all the 'noc router' cluster blocks and added/modified functions related to Noc traffic flows --- vpr/src/noc/noc_traffic_flows.h | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/vpr/src/noc/noc_traffic_flows.h b/vpr/src/noc/noc_traffic_flows.h index 5e20c6ec6c0..af7893dba73 100644 --- a/vpr/src/noc/noc_traffic_flows.h +++ b/vpr/src/noc/noc_traffic_flows.h @@ -3,10 +3,16 @@ #include "clustered_netlist_fwd.h" #include "noc_data_types.h" +#include "vtr_vector.h" #include #include +#include #include + +constexpr bool PROCESSED = true; +constexpr bool NOT_PROCESSED = false; + /* Describes a traffic flow within the NoC, which is the communication between two routers. This description includes the following: - The module names of the source and destination routers that are communicating with each other. The module name is the name used when instantiating a router module in the HDL design. @@ -49,8 +55,13 @@ class NocTrafficFlows vtr::vector processed_traffic_flows; + // contains the cluster ID of all unique router modules in the design + std::unordered_set noc_router_blocks; + // shouldnt have access to this functions - void add_traffic_flow_to_associated_source_and_sink_routers(NocTrafficFlowId traffic_flow_id); + void add_traffic_flow_to_associated_routers(NocTrafficFlowId traffic_flow_id, ClusterBlockId source_router_id, std::unordered_map>& router_associated_traffic_flows); + + void add_router_to_block_set(ClusterBlockId router_block_id); public: @@ -59,19 +70,23 @@ class NocTrafficFlows //getters const t_noc_traffic_flow& get_single_noc_traffic_flow(NocTrafficFlowId traffic_flow_id) const; - const std::vector& get_traffic_flows_associated_to_source_router(ClusterBlockId source_router_id) const; + const std::vector* get_traffic_flows_associated_to_source_router(ClusterBlockId source_router_id) const; + + const std::vector* get_traffic_flows_associated_to_sink_router(ClusterBlockId sink_router_id) const; - const std::vector& get_traffic_flows_associated_to_sink_router(ClusterBlockId sink_router_id) const; + bool get_traffic_flow_processed_status(NocTrafficFlowId traffic_flow_id); // setters void create_noc_traffic_flow(std::string source_router_module_name, std::string sink_router_module_name, ClusterBlockId source_router_cluster_id, ClusterBlockId sink_router_cluster_id, double traffic_flow_bandwidth, double traffic_flow_latency); + void set_traffic_flow_as_processed(NocTrafficFlowId traffic_flow_id); //utility functions void finshed_noc_traffic_flows_setup(void); void reset_traffic_flows_processed_status(void); void clear_traffic_flows(void); + bool check_if_cluster_block_is_a_noc_router(ClusterBlockId block_id); }; From 9571c5c5e0fd739bac2d3673ed2c66c09325a3a4 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 22 Apr 2022 17:02:13 -0400 Subject: [PATCH 069/128] added definitions for the NocTrafficFlows class functions --- vpr/src/noc/noc_traffic_flows.cpp | 158 ++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 vpr/src/noc/noc_traffic_flows.cpp diff --git a/vpr/src/noc/noc_traffic_flows.cpp b/vpr/src/noc/noc_traffic_flows.cpp new file mode 100644 index 00000000000..1053ba13211 --- /dev/null +++ b/vpr/src/noc/noc_traffic_flows.cpp @@ -0,0 +1,158 @@ + +#include "noc_traffic_flows.h" +#include "vpr_error.h" + +NocTrafficFlows::NocTrafficFlows(void){ + clear_traffic_flows(); +} + +// getters for the traffic flows + +const t_noc_traffic_flow& NocTrafficFlows::get_single_noc_traffic_flow(NocTrafficFlowId traffic_flow_id) const { + + return list_of_noc_traffic_flows[traffic_flow_id]; +} + +const std::vector* NocTrafficFlows::get_traffic_flows_associated_to_source_router(ClusterBlockId source_router_id) const { + + const std::vector* traffic_flow_list = nullptr; + + // get a reference to the list of traffic flows that have the current router as a source + auto source_router_traffic_flows_list = source_router_associated_traffic_flows.find(source_router_id); + + // check if there are any traffic flows associated with the current router + if (source_router_traffic_flows_list != source_router_associated_traffic_flows.end()){ + + // if we are here then there exists atleast 1 traffic flow that includes the current router as a source + traffic_flow_list = &(source_router_traffic_flows_list->second); + } + + return traffic_flow_list; +} + +const std::vector* NocTrafficFlows::get_traffic_flows_associated_to_sink_router(ClusterBlockId source_router_id) const { + + const std::vector* traffic_flow_list = nullptr; + + // get a reference to the list of traffic flows that have the current router as a source + auto sink_router_traffic_flows_list = sink_router_associated_traffic_flows.find(source_router_id); + + // check if there are any traffic flows associated with the current router + if (sink_router_traffic_flows_list != sink_router_associated_traffic_flows.end()){ + + // if we are here then there exists atleast 1 traffic flow that includes the current router as a source + traffic_flow_list = &(sink_router_traffic_flows_list->second); + } + + return traffic_flow_list; +} + +bool NocTrafficFlows::get_traffic_flow_processed_status(NocTrafficFlowId traffic_flow_id){ + + return processed_traffic_flows[traffic_flow_id]; +} + +// setters for the traffic flows + +void NocTrafficFlows::create_noc_traffic_flow(std::string source_router_module_name, std::string sink_router_module_name, ClusterBlockId source_router_cluster_id, ClusterBlockId sink_router_cluster_id, double traffic_flow_bandwidth, double traffic_flow_latency){ + + // create and add the new traffic flow to the list + list_of_noc_traffic_flows.emplace_back(source_router_module_name, sink_router_module_name, source_router_cluster_id, sink_router_cluster_id, traffic_flow_bandwidth, traffic_flow_latency); + + //since the new traffic flow was added to the back of the list, its id will be the index of the last element + NocTrafficFlowId curr_traffic_flow_id = (NocTrafficFlowId)(list_of_noc_traffic_flows.size() - 1); + + // add the source and sink routers to the set of unique router blocks in the design + add_router_to_block_set(source_router_cluster_id); + add_router_to_block_set(sink_router_cluster_id); + + // now add the new traffic flow to flows associated with the current source and sink router + add_traffic_flow_to_associated_routers(curr_traffic_flow_id, source_router_cluster_id, this->source_router_associated_traffic_flows); + add_traffic_flow_to_associated_routers(curr_traffic_flow_id, source_router_cluster_id, this->sink_router_associated_traffic_flows); + + return; + +} + +void NocTrafficFlows::set_traffic_flow_as_processed(NocTrafficFlowId traffic_flow_id){ + + // status is initialized to false, change it to true to reflect that the specified flow has been processed + processed_traffic_flows[traffic_flow_id] = PROCESSED; + + return; +} + +// utility functions for the noc traffic flows + +void NocTrafficFlows::finshed_noc_traffic_flows_setup(void){ + + // get the total number of traffic flows and create a vectorof the same size to hold the "processed status" of each traffic flow + int num_of_traffic_flows = list_of_noc_traffic_flows.size(); + // initialize the status to not processed yet + processed_traffic_flows.resize(num_of_traffic_flows,NOT_PROCESSED); + + return; +} + +void NocTrafficFlows::reset_traffic_flows_processed_status(void){ + + for (auto traffic_flow = processed_traffic_flows.begin(); traffic_flow != processed_traffic_flows.end(); traffic_flow++){ + + *traffic_flow = NOT_PROCESSED; + } + + return; +} + +void NocTrafficFlows::clear_traffic_flows(void){ + + // delete any information from internal datastructures + list_of_noc_traffic_flows.clear(); + source_router_associated_traffic_flows.clear(); + sink_router_associated_traffic_flows.clear(); + processed_traffic_flows.clear(); + noc_router_blocks.clear(); + + return; +} + +bool NocTrafficFlows::check_if_cluster_block_is_a_noc_router(ClusterBlockId block_id){ + + auto router_block = noc_router_blocks.find(block_id); + bool result = false; + + if (router_block != noc_router_blocks.end()){ + result = true; + } + + return result; +} + +// private functions used internally + +void NocTrafficFlows::add_traffic_flow_to_associated_routers(NocTrafficFlowId traffic_flow_id, ClusterBlockId router_id, std::unordered_map>& router_associated_traffic_flows){ + + // get a reference to the list of traffic flows associated with the current router + auto router_traffic_flows = router_associated_traffic_flows.find(router_id); + + // check if a list exists + if (router_traffic_flows == router_associated_traffic_flows.end()){ + // there exists no list of traffic flows for this router, so we add it with the newly created traffic flow id + router_associated_traffic_flows.insert(std::pair>(router_id, {traffic_flow_id})); + } + else{ + // there already is a list of traffic flows for the current router, so add it to the list + router_traffic_flows->second.emplace_back(traffic_flow_id); + } + + + return; + +} + +void NocTrafficFlows::add_router_to_block_set(ClusterBlockId router_block_id){ + + noc_router_blocks.insert(router_block_id); + + return; +} \ No newline at end of file From 3bd81008404601afcf633e25e7d372e08a507db8 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 29 Apr 2022 13:55:40 -0400 Subject: [PATCH 070/128] added a new function to determine the number of unique noc router found in all traffic flows. Also instead of having a function that updates the status of all traffic flows to 'processed', changed the function to have another parameter that contains the current status of the specific traffic flow --- vpr/src/noc/noc_traffic_flows.cpp | 56 ++++++++++++++++++++++++++++--- vpr/src/noc/noc_traffic_flows.h | 36 ++++++++++++++++++-- 2 files changed, 86 insertions(+), 6 deletions(-) diff --git a/vpr/src/noc/noc_traffic_flows.cpp b/vpr/src/noc/noc_traffic_flows.cpp index 1053ba13211..2a68baa4245 100644 --- a/vpr/src/noc/noc_traffic_flows.cpp +++ b/vpr/src/noc/noc_traffic_flows.cpp @@ -1,7 +1,27 @@ +/* + * The NocTrafficFlows contains all the communication + * happening within the NoC. This includes the source + * and destination routers in the communication link, the + * size of the data being tranferred and any constraints + * put on the communication link (ex. maximum latency). All + * this information is stored inside a traffic flow. + * + * The NocTrafficFlows stores a list of all the traffic flows in + * a given design as provided by the user. Additionally it includes + * a number of additional datastructures to quickly retrieve a traffic flow. + * Additionally it provides information about all the routers in the design. + * These include datastructures include: + * - A set of all the routers in the design + * - A list of all traffic flows for every router where the router + * is the source or destination of the traffic flow + * - The processed status of each and every traffic flow + * + */ #include "noc_traffic_flows.h" #include "vpr_error.h" +// constructor clears all the traffic flow datastructures NocTrafficFlows::NocTrafficFlows(void){ clear_traffic_flows(); } @@ -13,6 +33,9 @@ const t_noc_traffic_flow& NocTrafficFlows::get_single_noc_traffic_flow(NocTraffi return list_of_noc_traffic_flows[traffic_flow_id]; } +/* + Given a router ClusterBlockId, return a list of traffic flows where the provided router is the source router of the traffic flow +*/ const std::vector* NocTrafficFlows::get_traffic_flows_associated_to_source_router(ClusterBlockId source_router_id) const { const std::vector* traffic_flow_list = nullptr; @@ -30,6 +53,9 @@ const std::vector* NocTrafficFlows::get_traffic_flows_associat return traffic_flow_list; } +/* + Given a router ClusterBlockId, return a list of traffic flows where the provided router is the sink router of the traffic flow +*/ const std::vector* NocTrafficFlows::get_traffic_flows_associated_to_sink_router(ClusterBlockId source_router_id) const { const std::vector* traffic_flow_list = nullptr; @@ -52,8 +78,21 @@ bool NocTrafficFlows::get_traffic_flow_processed_status(NocTrafficFlowId traffic return processed_traffic_flows[traffic_flow_id]; } +/* + Determines the number of unique router blocks that were used as a source or sink router in all traffic flows. +*/ +int NocTrafficFlows::get_number_of_routers_used_in_traffic_flows(void){ + + return noc_router_blocks.size(); +} + // setters for the traffic flows +/* + Given all the information for a given traffic flow, create it + and add it to all the internal datastructures. Then add the two routers + in the newly created flow to the set of all routers in the design. +*/ void NocTrafficFlows::create_noc_traffic_flow(std::string source_router_module_name, std::string sink_router_module_name, ClusterBlockId source_router_cluster_id, ClusterBlockId sink_router_cluster_id, double traffic_flow_bandwidth, double traffic_flow_latency){ // create and add the new traffic flow to the list @@ -68,22 +107,25 @@ void NocTrafficFlows::create_noc_traffic_flow(std::string source_router_module_n // now add the new traffic flow to flows associated with the current source and sink router add_traffic_flow_to_associated_routers(curr_traffic_flow_id, source_router_cluster_id, this->source_router_associated_traffic_flows); - add_traffic_flow_to_associated_routers(curr_traffic_flow_id, source_router_cluster_id, this->sink_router_associated_traffic_flows); + add_traffic_flow_to_associated_routers(curr_traffic_flow_id, sink_router_cluster_id, this->sink_router_associated_traffic_flows); return; } -void NocTrafficFlows::set_traffic_flow_as_processed(NocTrafficFlowId traffic_flow_id){ +// given a traffic flow and its status, update it +void NocTrafficFlows::set_traffic_flow_status(NocTrafficFlowId traffic_flow_id, bool status){ // status is initialized to false, change it to true to reflect that the specified flow has been processed - processed_traffic_flows[traffic_flow_id] = PROCESSED; + processed_traffic_flows[traffic_flow_id] = status; return; } // utility functions for the noc traffic flows + +//Create the list that stores the status of all traffic flows void NocTrafficFlows::finshed_noc_traffic_flows_setup(void){ // get the total number of traffic flows and create a vectorof the same size to hold the "processed status" of each traffic flow @@ -94,6 +136,7 @@ void NocTrafficFlows::finshed_noc_traffic_flows_setup(void){ return; } +// set the status of all the traffic flows as not processed void NocTrafficFlows::reset_traffic_flows_processed_status(void){ for (auto traffic_flow = processed_traffic_flows.begin(); traffic_flow != processed_traffic_flows.end(); traffic_flow++){ @@ -103,7 +146,7 @@ void NocTrafficFlows::reset_traffic_flows_processed_status(void){ return; } - +// clear all the internal datastructures void NocTrafficFlows::clear_traffic_flows(void){ // delete any information from internal datastructures @@ -116,6 +159,7 @@ void NocTrafficFlows::clear_traffic_flows(void){ return; } +// given a ClusterBlockId, determine whether it is a router block or not bool NocTrafficFlows::check_if_cluster_block_is_a_noc_router(ClusterBlockId block_id){ auto router_block = noc_router_blocks.find(block_id); @@ -130,6 +174,9 @@ bool NocTrafficFlows::check_if_cluster_block_is_a_noc_router(ClusterBlockId bloc // private functions used internally +/* + Given a router, add the current traffic flow to the list of traffic flows for the current router where it is a source or destination of the given flow +*/ void NocTrafficFlows::add_traffic_flow_to_associated_routers(NocTrafficFlowId traffic_flow_id, ClusterBlockId router_id, std::unordered_map>& router_associated_traffic_flows){ // get a reference to the list of traffic flows associated with the current router @@ -150,6 +197,7 @@ void NocTrafficFlows::add_traffic_flow_to_associated_routers(NocTrafficFlowId tr } +// adds a router to the list of all router blocks in the design void NocTrafficFlows::add_router_to_block_set(ClusterBlockId router_block_id){ noc_router_blocks.insert(router_block_id); diff --git a/vpr/src/noc/noc_traffic_flows.h b/vpr/src/noc/noc_traffic_flows.h index af7893dba73..e6b39ded2b9 100644 --- a/vpr/src/noc/noc_traffic_flows.h +++ b/vpr/src/noc/noc_traffic_flows.h @@ -1,6 +1,19 @@ #ifndef NOC_TRAFFIC_FLOWS_H #define NOC_TRAFFIC_FLOWS_H +/* + * The NocTrafficFlows class description header file. + * + * The NocTrafficFlows class contains all the communication within the NoC. So + * this includes the source and destination routers involved in the + * communication link and its properties (size and constraints on the link). + * We call this infor mation a traffic flow. + * + * In addition, the NoCTrafficFlows class includes additional variables and + * functions to quickly access the traffic flows. + * + */ + #include "clustered_netlist_fwd.h" #include "noc_data_types.h" #include "vtr_vector.h" @@ -10,6 +23,11 @@ #include +/* + Whenever a traffic flow is processed (routed a connection between + 2 routers and updated the relevant information) we need to + some way to track it, so that we don't process it again. The flags below indicate whether a traffic flow was processed or not. +*/ constexpr bool PROCESSED = true; constexpr bool NOT_PROCESSED = false; @@ -48,17 +66,29 @@ class NocTrafficFlows { private: + // contains all the traffic flows provided by the user and their information vtr::vector list_of_noc_traffic_flows; + /* + A traffic flow has a source and destination router associated to it. So when either the source or destination router for a given flow is moved, we need to find a new route between them. + + Therefore, during placement if two router blocks are swapped, then the only traffic flows we need to re-route are the flows where the two routers are either the source or destination routers of those flows. + + The datastructures below store a list of traffic flows for each router then its a source router for the traffic flow. Similarily, there is a another datastructure for where a list of traffic flows are stored for each router where its a source router for the traffic flow. The routers are indexed by their ClusterBlockId. + + This is done so that the traffic that need to be re-routed during placement are quickly found. + */ std::unordered_map> source_router_associated_traffic_flows; std::unordered_map> sink_router_associated_traffic_flows; + // keeps track of which traffic flows have already been processed vtr::vector processed_traffic_flows; // contains the cluster ID of all unique router modules in the design + // can quikly determine whether a given cluster is a router module or not std::unordered_set noc_router_blocks; - // shouldnt have access to this functions + // shouldnt have access to these functions void add_traffic_flow_to_associated_routers(NocTrafficFlowId traffic_flow_id, ClusterBlockId source_router_id, std::unordered_map>& router_associated_traffic_flows); void add_router_to_block_set(ClusterBlockId router_block_id); @@ -76,11 +106,13 @@ class NocTrafficFlows bool get_traffic_flow_processed_status(NocTrafficFlowId traffic_flow_id); + int get_number_of_routers_used_in_traffic_flows(void); + // setters void create_noc_traffic_flow(std::string source_router_module_name, std::string sink_router_module_name, ClusterBlockId source_router_cluster_id, ClusterBlockId sink_router_cluster_id, double traffic_flow_bandwidth, double traffic_flow_latency); - void set_traffic_flow_as_processed(NocTrafficFlowId traffic_flow_id); + void set_traffic_flow_status(NocTrafficFlowId traffic_flow_id, bool status); //utility functions void finshed_noc_traffic_flows_setup(void); From c6b7b248396f367b27935b2b5dc247d930860fd7 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 29 Apr 2022 13:58:04 -0400 Subject: [PATCH 071/128] adding unit tests for the NocTrafficFlows class --- vpr/test/test_noc_traffic_flows.cpp | 171 ++++++++++++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 vpr/test/test_noc_traffic_flows.cpp diff --git a/vpr/test/test_noc_traffic_flows.cpp b/vpr/test/test_noc_traffic_flows.cpp new file mode 100644 index 00000000000..a8c8cc7ac16 --- /dev/null +++ b/vpr/test/test_noc_traffic_flows.cpp @@ -0,0 +1,171 @@ +#include "catch2/catch_test_macros.hpp" + +#include "noc_traffic_flows.h" + +#include + +#define NUM_OF_ROUTERS 10 + +namespace { + + TEST_CASE("test_adding_traffic_flows", "[vpr_noc_traffic_flows]") { + + // the traffic flows datastructure and reset it + NocTrafficFlows traffic_flow_storage; + traffic_flow_storage.clear_traffic_flows(); + + // parameters for each traffic flow + std::string source_router_name = "test_1"; + std::string sink_router_nanme = "test_2"; + double traffic_flow_bandwidth = 200; + double traffic_flow_latency = 10; + ClusterBlockId source_router_id; + ClusterBlockId sink_router_id; + NocTrafficFlowId curr_flow_id; + // setup the test data + + // create all the routers + std::vector golden_router_blocks_list; + for (int router = 0; router < NUM_OF_ROUTERS; router++){ + golden_router_blocks_list.push_back((ClusterBlockId)router); + } + + // total traffic flows will be NUM_OF_ROUTERS * (NUM_OF_ROUTERS - 1) + // create the traffic flows + std::vector golden_traffic_flow_list; + vtr::vector> golden_list_of_associated_links_source_router; + golden_list_of_associated_links_source_router.resize(NUM_OF_ROUTERS); + + vtr::vector> golden_list_of_associated_links_sink_router; + golden_list_of_associated_links_sink_router.resize(NUM_OF_ROUTERS); + + for (int router = 0; router < NUM_OF_ROUTERS; router++){ + + for (int second_router = 0; second_router < NUM_OF_ROUTERS; second_router++){ + + // dont want the case where the source and destination routers are the same + if (router == second_router){ + continue; + } + + source_router_id = (ClusterBlockId)router; + sink_router_id = (ClusterBlockId)second_router; + + // need to match how the test function does it + golden_traffic_flow_list.emplace_back(source_router_name, sink_router_nanme, source_router_id, sink_router_id, traffic_flow_bandwidth, traffic_flow_latency); + + curr_flow_id = (NocTrafficFlowId)(golden_traffic_flow_list.size() - 1); + + // add the traffic flows to the source and sink routers + golden_list_of_associated_links_source_router[source_router_id].emplace_back(curr_flow_id); + golden_list_of_associated_links_sink_router[sink_router_id].emplace_back(curr_flow_id); + + } + } + + // finished settting up all the golden information, so now perform the tests + SECTION("Verifying that all created traffic flows and their related information are stored correctly."){ + + // add all the traffic flows to the datastructure + for (int router = 0; router < NUM_OF_ROUTERS; router++){ + + for (int second_router = 0; second_router < NUM_OF_ROUTERS; second_router++){ + + // dont want the case where the source and destination routers are the same + if (router == second_router){ + continue; + } + + source_router_id = (ClusterBlockId)router; + sink_router_id = (ClusterBlockId)second_router; + + // create and add the traffic flow + traffic_flow_storage.create_noc_traffic_flow(source_router_name, sink_router_nanme, source_router_id, sink_router_id, traffic_flow_bandwidth, traffic_flow_latency); + + } + } + + int size_of_router_block_list = golden_router_blocks_list.size(); + + // check the set of routers first to see that they were all added properly + for (int router = 0; router < size_of_router_block_list; router++){ + // every router in the golden list needs to exist in the traffic flow datastructure (this also tests cases where a router was added multiple times, this shouldnt affect it) + REQUIRE(traffic_flow_storage.check_if_cluster_block_is_a_noc_router(golden_router_blocks_list[router]) == true); + + } + + int size_of_traffic_flow_list = golden_traffic_flow_list.size(); + + // check the traffic flows (make sure they are correct) + for (int traffic_flow = 0; traffic_flow < size_of_traffic_flow_list; traffic_flow++){ + + curr_flow_id = (NocTrafficFlowId)traffic_flow; + t_noc_traffic_flow curr_traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(curr_flow_id); + + // make sure that the source and destination routers match the golden set + REQUIRE(curr_traffic_flow.source_router_cluster_id == golden_traffic_flow_list[traffic_flow].source_router_cluster_id); + REQUIRE(curr_traffic_flow.sink_router_cluster_id == golden_traffic_flow_list[traffic_flow].sink_router_cluster_id); + + } + + int size_of_associated_flows_for_source_routers = golden_list_of_associated_links_source_router.size(); + // make sure that the correct traffic flows are added to each router when it is a source + for (int source_router = 0; source_router < size_of_associated_flows_for_source_routers;source_router++){ + + source_router_id = (ClusterBlockId)source_router; + + int size_of_current_source_router_associated_traffic_flows = golden_list_of_associated_links_source_router[source_router_id].size(); + + + const std::vector* associated_traffic_flows_to_source_router = traffic_flow_storage.get_traffic_flows_associated_to_source_router(source_router_id); + + for (int source_router_traffic_flow = 0; source_router_traffic_flow < size_of_current_source_router_associated_traffic_flows; source_router_traffic_flow++){ + + REQUIRE((size_t)golden_list_of_associated_links_source_router[source_router_id][source_router_traffic_flow] == (size_t)(*associated_traffic_flows_to_source_router)[source_router_traffic_flow]); + } + } + + int size_of_associated_flows_for_sink_routers = golden_list_of_associated_links_sink_router.size(); + // make sure that the correct traffic flows are added to each router when it is a sink + for (int sink_router = 0; sink_router < size_of_associated_flows_for_sink_routers;sink_router++){ + + sink_router_id = (ClusterBlockId)sink_router; + + int size_of_current_sink_router_associated_traffic_flows = golden_list_of_associated_links_sink_router[sink_router_id].size(); + + const std::vector* associated_traffic_flows_to_sink_router = traffic_flow_storage.get_traffic_flows_associated_to_sink_router(sink_router_id); + + for (int sink_router_traffic_flow = 0; sink_router_traffic_flow < size_of_current_sink_router_associated_traffic_flows; sink_router_traffic_flow++){ + + REQUIRE((size_t)golden_list_of_associated_links_sink_router[sink_router_id][sink_router_traffic_flow] == (size_t)(*associated_traffic_flows_to_sink_router)[sink_router_traffic_flow]); + } + } + } + SECTION("Checking to see if invalid blocks that are not routers exist in NocTrafficFlows."){ + + // create a invalid block id + ClusterBlockId invalid_block = (ClusterBlockId)(NUM_OF_ROUTERS + 1); + + // check that this block doesnt exist in the traffic flow datastructure + REQUIRE(traffic_flow_storage.check_if_cluster_block_is_a_noc_router(invalid_block) == false); + + } + SECTION("Checking that when there are no traffics flows where a given router is a source there exists no traffic flows associated with said source router."){ + + // create a invalid block id (mimics the effect where a router has no traffic flows associated with it) + ClusterBlockId invalid_block = (ClusterBlockId)(NUM_OF_ROUTERS + 1); + + // check that this router has no traffic flows associated with it + REQUIRE(traffic_flow_storage.get_traffic_flows_associated_to_source_router(invalid_block) == nullptr); + } + SECTION("Checking that when there are no traffics flows where a given router is a sink there exists no traffic flows associated with said sink router."){ + + // create a invalid block id (mimics the effect where a router has no traffic flows associated with it) + ClusterBlockId invalid_block = (ClusterBlockId)(NUM_OF_ROUTERS + 1); + + // check that this router has no traffic flows associated with it + REQUIRE(traffic_flow_storage.get_traffic_flows_associated_to_sink_router(invalid_block) == nullptr); + } + + } +} \ No newline at end of file From 5a77e6b057e1394a659fa44c800ec5af37abec9b Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 29 Apr 2022 14:00:05 -0400 Subject: [PATCH 072/128] added the parser for the noc traffic flows description file --- .../noc/read_xml_noc_traffic_flows_file.cpp | 354 ++++++++++++++++++ vpr/src/noc/read_xml_noc_traffic_flows_file.h | 40 ++ 2 files changed, 394 insertions(+) create mode 100644 vpr/src/noc/read_xml_noc_traffic_flows_file.cpp create mode 100644 vpr/src/noc/read_xml_noc_traffic_flows_file.h diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp new file mode 100644 index 00000000000..86fc4f57732 --- /dev/null +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -0,0 +1,354 @@ +/** + * The purpose of this file is to read and parse an xml file that has then + * a '.flows' extension. THis file contains the description of a number of + * traffic flows within the NoC. A traffic flow describes the communication + * between two routers in the NoC. + * + * All the processed traffic flows are stored inside the NocTrafficFlows class + * for future use. + * + * 'read_xml_noc_traffic_flows_file' is the main function that performs all the + * tasks listed above and should be used externally to process the traffic + * flows file. This file also contains a number of internal helper + * functions that assist in parsing the traffic flows file. + * + */ + +#include "pugixml.hpp" +#include "pugixml_util.hpp" +#include "read_xml_util.h" +#include "globals.h" + +#include "vtr_assert.h" +#include "vtr_util.h" +#include "ShowSetup.h" +#include "vpr_error.h" + +#include "noc_data_types.h" +#include "read_xml_noc_traffic_flows_file.h" + + +static void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type); + +static void verify_traffic_flow_router_modules(std::string source_router_name, std::string destination_router_name, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data); + +static void verify_traffic_flow_properties(double traffic_flow_bandwidth, double max_traffic_flow_latency, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data); + +static ClusterBlockId get_router_module_cluster_id(std::string router_module_name, const ClusteringContext& cluster_ctx, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data); + +static void check_traffic_flow_router_module_type(std::string router_module_name, ClusterBlockId router_module_id, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, t_physical_tile_type_ptr noc_router_tile_type); + +static t_physical_tile_type_ptr get_physical_type_of_noc_router_tile(const DeviceContext& device_ctx, NocContext& noc_ctx); + +static void check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type, std::string noc_flows_file); + +/** + * @brief Main driver function that parsed the xml '.flows' file which + * contains all the traffic flows in the NoC. This function + * takes the parsed information and stores it inside the + * NocTrafficFlows class. + * + * @param noc_flows_file Name of the '.flows' file + */ +void read_xml_noc_traffic_flows_file(char* noc_flows_file){ + + // start by checking that the provided file is a ".flows" file + if (vtr::check_file_name_extension(noc_flows_file, ".flows") == false){ + VPR_FATAL_ERROR(VPR_ERROR_OTHER, "NoC traffic flows file '%s' has an unknown extension. Expecting .flows for NoC traffic flow files.", noc_flows_file); + } + + // cluster information + const ClusteringContext& cluster_ctx = g_vpr_ctx.clustering(); + + // noc information + NocContext& noc_ctx = g_vpr_ctx.mutable_noc(); + + // device information + const DeviceContext& device_ctx = g_vpr_ctx.device(); + + // get the physical type of a noc router + t_physical_tile_type_ptr noc_router_tile_type = get_physical_type_of_noc_router_tile(device_ctx, noc_ctx); + + /* variabled used when parsing the file */ + pugi::xml_document doc; + pugiutil::loc_data loc_data; + + // go through the file + try { + + // load the file + loc_data = pugiutil::load_xml(doc, noc_flows_file); + + // Root tag should be traffic_flows + auto traffic_flows_tag = pugiutil::get_single_child(doc, "traffic_flows", loc_data); + + // process the individual traffic flows below + for (pugi::xml_node single_flow : traffic_flows_tag.children()){ + // we can only have "single_flow" tags within "traffic_flows" so check that + if (single_flow.name() != std::string("single_flow")) { + bad_tag(single_flow, loc_data, traffic_flows_tag, {"single_flow"}); + } + else { + // current tag is a valid "flow" so process it + process_single_flow(single_flow, loc_data, cluster_ctx, noc_ctx, noc_router_tile_type); + } + } + + } + catch(pugiutil::XmlError& e) { // used for identifying any of the xml parsing library errors + VPR_FATAL_ERROR(VPR_ERROR_OTHER, noc_flows_file, e.line(), "%s", e.what()); + } + + // make sure that all the router modules in the design have an associated traffic flow + check_that_all_router_blocks_have_an_associated_traffic_flow(noc_ctx, noc_router_tile_type, noc_flows_file); + + noc_ctx.noc_traffic_flows_storage.finshed_noc_traffic_flows_setup(); + + return; + +} + +/** + * @brief Takes a tag from the '.flows' file and extracts the + * flow information from it. This includes the two routers modules + * in the flow, the size of the data transferred and any latency + * constraints on the data transmission. The parsed information + * is verified and if it is legal then this traffic flow is added + * to the NocTrafficFlows class. + * + * @param single_flow_tag A xml tag that contains the traffic flow information + * @param loc_data Contains location data about the current line in the xml file + * @param cluster_ctx Global variable that contains clustering information. Used + * to get information about the router blocks int he design. + * @param noc_ctx Global variable that contains NoC information. Used to access + * the NocTrafficFlows class and store current flow. + * @param noc_router_tile_type The physical type of a Noc router tile in the + * FPGA. + */ +static void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type){ + + // contans all traffic flows + NocTrafficFlows* noc_traffic_flow_storage = &noc_ctx.noc_traffic_flows_storage; + + // an accepted list of attributes for the single flow tag + std::vector expected_single_flow_attributes = {"src", "dst", "bandwidth", "latency_cons"}; + + // check that only the accepted single flow attributes are found in the tag + pugiutil::expect_only_attributes(single_flow_tag, expected_single_flow_attributes, loc_data); + + // store the names of the routers part of this traffic flow + std::string source_router_module_name = pugiutil::get_attribute(single_flow_tag, "src", loc_data, pugiutil::REQUIRED).as_string(); + + std::string destination_router_module_name = pugiutil::get_attribute(single_flow_tag, "dst", loc_data, pugiutil::REQUIRED).as_string(); + + //verify whether the router module names are legal + verify_traffic_flow_router_modules(source_router_module_name, destination_router_module_name, single_flow_tag, loc_data); + + // assign the unique block ids of the two router modules after clustering + ClusterBlockId source_router_id = get_router_module_cluster_id(source_router_module_name, cluster_ctx, single_flow_tag, loc_data); + ClusterBlockId destination_router_id = get_router_module_cluster_id(destination_router_module_name, cluster_ctx, single_flow_tag, loc_data); + + // verify that the source and destination modules are actually noc routers + check_traffic_flow_router_module_type(source_router_module_name, source_router_id, single_flow_tag, loc_data, cluster_ctx, noc_router_tile_type); + check_traffic_flow_router_module_type(destination_router_module_name, destination_router_id, single_flow_tag, loc_data, cluster_ctx, noc_router_tile_type); + + // store the properties of the traffic flow + double traffic_flow_bandwidth = pugiutil::get_attribute(single_flow_tag, "bandwidth", loc_data, pugiutil::REQUIRED).as_double(NUMERICAL_ATTRIBUTE_CONVERSION_FAILURE); + + double max_traffic_flow_latency = pugiutil::get_attribute(single_flow_tag, "latency_cons", loc_data, pugiutil::REQUIRED).as_double(NUMERICAL_ATTRIBUTE_CONVERSION_FAILURE); + + verify_traffic_flow_properties(traffic_flow_bandwidth, max_traffic_flow_latency, single_flow_tag, loc_data); + + // The current flow information is legal, so store it + noc_traffic_flow_storage->create_noc_traffic_flow(source_router_module_name, destination_router_module_name, source_router_id, destination_router_id, traffic_flow_bandwidth, max_traffic_flow_latency); + + return; + +} + +/** + * @brief Checks to see that the two router module names provided in the + * traffic flow description are not empty and they dont have the + * same names. THe two routers cant be the exact same since a router + * cannot communicate with itself. + * + * @param source_router_name A string value of the source router module name + * @param destination_router_name A string value of the destination router + * module name + * @param single_flow_tag A xml tag that contains the traffic flow information + * @param loc_data Contains location data about the current line in the xml file + */ +static void verify_traffic_flow_router_modules(std::string source_router_name, std::string destination_router_name, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data){ + + // check that the router module names were legal + if ((source_router_name.compare("") == 0) || (destination_router_name.compare("") == 0)){ + + VPR_FATAL_ERROR(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "%s", "Invalid names for the source and dstination NoC router modules."); + }// check if the source and destination routers have the same name + else if (source_router_name.compare(destination_router_name) == 0) + { + // Cannot have the source and destination routers have the same name (they need to be different). A flow cant go to a single router. + VPR_FATAL_ERROR(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "%s", "Source and destination NoC routers cannot be the same modules."); + } + + return; + +} + +/** + * @brief Ensures that the a given traffic flows data transmission size and + * latency constraints are not negative values. + * + * @param traffic_flow_bandwidth The transmission size betwee the two routers + * in the traffic flow. + * @param max_traffic_flow_latency The allowable latency for the data + * transmission between the two routers in the + * traffic flow. + * @param single_flow_tag A xml tag that contains the traffic flow information + * @param loc_data Contains location data about the current line in the xml file + */ +static void verify_traffic_flow_properties(double traffic_flow_bandwidth, double max_traffic_flow_latency, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data){ + + // check that the bandwidth and max latency are positive values + if ((traffic_flow_bandwidth < 0) || (max_traffic_flow_latency < 0)){ + + VPR_FATAL_ERROR(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "%s", "THe traffic flow bandwidth and latency constraints need to be positive values."); + } + + return; +} + +/** + * @brief Given a router module name in the design, retrieve the + * equivalent clustered router block identifier, which is + * a ClusterBlockId. + * + * @param router_module_name The name of the router module in the design for + * which the corresponding block id needs to be found. + * @param cluster_ctx Global variable that contains clustering information. + * Contains a datastructure to convert a module name to + * a cluster block id. + * @param single_flow_tag A xml tag that contains the traffic flow information + * @param loc_data Contains location data about the current line in the xml file + * @return ClusterBlockId The corresponding router block id of the provided + * router module name. + */ +static ClusterBlockId get_router_module_cluster_id(std::string router_module_name, const ClusteringContext& cluster_ctx, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data){ + + ClusterBlockId router_module_id = cluster_ctx.clb_nlist.find_block(router_module_name); + + // check if a valid block id was found + if ((size_t)router_module_id == (size_t)ClusterBlockId::INVALID){ + // if here then the module did not exist in the design, so throw an error + VPR_FATAL_ERROR(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "%s", "The router module '%s' does not exist in the design.", router_module_id); + } + + return router_module_id; + +} + +/** + * @brief Checks to see whether a given router block is compatible with a NoC + * router tile, this helps determine whether the router block is a router + * or not (the user provided a name for another type of block in the + * design). + * + * @param router_module_name Name of the router module that we are trying to + * check whether it is of type router. + * @param router_module_id The ClusterBlockId of the router block we are trying + * to check if its of type router. + * @param single_flow_tag A xml tag that contains the traffic flow information + * @param loc_data Contains location data about the current line in the xml file + * @param cluster_ctx Global variable that contains clustering information. + * Contains a datastructure to get the logical type of a + * router cluster block. + * @param noc_router_tile_type The physical type of a Noc router tile in the + * FPGA. Used to check if the router block is + * compatible with a router tile. + */ +static void check_traffic_flow_router_module_type(std::string router_module_name, ClusterBlockId router_module_id, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, t_physical_tile_type_ptr noc_router_tile_type){ + + // get the logical type of the provided router module + t_logical_block_type_ptr router_module_logical_type = cluster_ctx.clb_nlist.block_type(router_module_id); + + /* + Check of the current router nodules logical type is compatible with the physical type if a noc router (can the module be placed on a noc router tile on the FPGA device). If not then this module is not a router so throw an error. + */ + if (!is_tile_compatible(noc_router_tile_type, router_module_logical_type)){ + + VPR_FATAL_ERROR(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "%s", "The supplied module name '%s' is not a NoC router.", router_module_name); + } + + return; + +} + +/** + * @brief Retreives the physical type of a noc router tile. + * + * @param device_ctx Contains the device information. Has a datastructure that + * can determine a tile type based on grid position on the + * FPGA. + * @param noc_ctx Contains the NoC information. Used to get the grid position + * of a NoC router tile. + * @return t_physical_tile_type_ptr The physical type of a NoC router tile + */ +static t_physical_tile_type_ptr get_physical_type_of_noc_router_tile(const DeviceContext& device_ctx, NocContext& noc_ctx){ + + // get a reference to a single physical noc router + auto physical_noc_router = noc_ctx.noc_model.get_noc_routers().begin(); + + + //Using the routers grid position go to the device and identify the physical type of the tile located there. + return device_ctx.grid[physical_noc_router->get_router_grid_position_x()][physical_noc_router->get_router_grid_position_y()].type; + +} + +/** + * @brief Verify that every router module in the design has an associated + * traffic flow to it. If a router module was instantiated in a design + * then it should be part of a traffic flow as either a source or + * destination router. If the module is not then we need to throw an + * error. + * + * @param noc_ctx Contains the NoC information. Used to get the total number + * unique routers found in all traffic flows. + * @param noc_router_tile_type The physical type of a Noc router tile in the + * FPGA. Used to get the logical types of all + * clustered router blocks in the that can be placed + * on a NoC router tile. + * @param noc_flows_file The name of the '.flows' file. Used when displaying + * the error. + */ +static void check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type, std::string noc_flows_file){ + + // contains the number of all the noc router blocks in the design + const auto clustered_netlist_stats = ClusteredNetlistStats(); + + int number_of_router_blocks_in_design = 0; + + const std::vector* noc_router_subtiles = &(noc_router_tile_type->sub_tiles); + + /* + Go through the router subtiles and get the router logical block types the subtiles support. Then determine how many of each router logical block types there are in the clustered netlist. The accumulated sum of all these clusters is the total number of router blocks in the design. */ + for (auto subtile = noc_router_subtiles->begin(); subtile != noc_router_subtiles->end(); subtile++){ + + for (auto router_logical_block = subtile->equivalent_sites.begin(); router_logical_block != subtile->equivalent_sites.end();router_logical_block++){ + + // get the number of logical blocks in the design of the current logical block type + number_of_router_blocks_in_design += clustered_netlist_stats.num_blocks_type[(*router_logical_block)->index]; + + } + } + + /* + Every router block in the design needs to be part of a traffic flow. There can never be a router that isnt part of a traffic flow, other wise the router is doing nothing. So check that the number of unique routers in all traffic flows equals the number of router blocks in the design, otherwise throw an error. + */ + if (noc_ctx.noc_traffic_flows_storage.get_number_of_routers_used_in_traffic_flows() != number_of_router_blocks_in_design){ + + VPR_FATAL_ERROR(VPR_ERROR_OTHER, "NoC traffic flows file '%s' does not contain all router modules in the design. Every router module in the design must be part of a traffic flow (communicationg to another router).", noc_flows_file); + } + + return; + +} \ No newline at end of file diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.h b/vpr/src/noc/read_xml_noc_traffic_flows_file.h new file mode 100644 index 00000000000..7f21e112de5 --- /dev/null +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.h @@ -0,0 +1,40 @@ +#ifndef READ_XML_NOC_TRAFFIC_FLOWS_FILE_H +#define READ_XML_NOC_TRAFFIC_FLOWS_FILE_H + +#include"noc_traffic_flows.h" + +#include +#include +#include + +// identifier when an integer conversion failed while reading an attribute value in an xml file +constexpr int NUMERICAL_ATTRIBUTE_CONVERSION_FAILURE = -1; + +/** + * @brief Parse an xml '.flows' file that contains a number of traffic + * in the NoC. A traffic flow is a communication between one router + * in the NoC to another. The XML file contains a number of these traffic + * flows and provides additional information about them, such as the + * size of data being tranferred and constraints on the latency of the + * data transmission. Once the traffic flows are parsed, they are stored + * inside the NocTrafficFlows class. + * + * @param noc_flows_file Name of the noc '.flows' file + */ +void read_xml_noc_traffic_flows_file(char* noc_flows_file); + + + + + + + + + + + + + + + +#endif \ No newline at end of file From b487e33c8b5e39bb833496376aac3078dfe18cb9 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Thu, 12 May 2022 16:27:53 -0400 Subject: [PATCH 073/128] changed the error logging to use vpr_throw instead of VPR_FATAL_ERROR() as this allows us to specify the error file and line number. And this could be used to log error about the noc .flows file format --- .../noc/read_xml_noc_traffic_flows_file.cpp | 19 ++++++++++--------- vpr/src/noc/read_xml_noc_traffic_flows_file.h | 2 +- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index 86fc4f57732..aba0d8f647e 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -50,7 +50,7 @@ static void check_that_all_router_blocks_have_an_associated_traffic_flow(NocCont * * @param noc_flows_file Name of the '.flows' file */ -void read_xml_noc_traffic_flows_file(char* noc_flows_file){ +void read_xml_noc_traffic_flows_file(const char* noc_flows_file){ // start by checking that the provided file is a ".flows" file if (vtr::check_file_name_extension(noc_flows_file, ".flows") == false){ @@ -96,7 +96,7 @@ void read_xml_noc_traffic_flows_file(char* noc_flows_file){ } catch(pugiutil::XmlError& e) { // used for identifying any of the xml parsing library errors - VPR_FATAL_ERROR(VPR_ERROR_OTHER, noc_flows_file, e.line(), "%s", e.what()); + vpr_throw(VPR_ERROR_OTHER, noc_flows_file, e.line(), e.what()); } // make sure that all the router modules in the design have an associated traffic flow @@ -183,12 +183,12 @@ static void verify_traffic_flow_router_modules(std::string source_router_name, s // check that the router module names were legal if ((source_router_name.compare("") == 0) || (destination_router_name.compare("") == 0)){ - VPR_FATAL_ERROR(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "%s", "Invalid names for the source and dstination NoC router modules."); + vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "Invalid names for the source and destination NoC router modules."); }// check if the source and destination routers have the same name else if (source_router_name.compare(destination_router_name) == 0) { // Cannot have the source and destination routers have the same name (they need to be different). A flow cant go to a single router. - VPR_FATAL_ERROR(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "%s", "Source and destination NoC routers cannot be the same modules."); + vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "Source and destination NoC routers cannot be the same modules."); } return; @@ -212,7 +212,7 @@ static void verify_traffic_flow_properties(double traffic_flow_bandwidth, double // check that the bandwidth and max latency are positive values if ((traffic_flow_bandwidth < 0) || (max_traffic_flow_latency < 0)){ - VPR_FATAL_ERROR(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "%s", "THe traffic flow bandwidth and latency constraints need to be positive values."); + vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "The traffic flow bandwidth and latency constraints need to be positive values."); } return; @@ -240,7 +240,7 @@ static ClusterBlockId get_router_module_cluster_id(std::string router_module_nam // check if a valid block id was found if ((size_t)router_module_id == (size_t)ClusterBlockId::INVALID){ // if here then the module did not exist in the design, so throw an error - VPR_FATAL_ERROR(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "%s", "The router module '%s' does not exist in the design.", router_module_id); + vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "The router module '%s' does not exist in the design.", router_module_id); } return router_module_id; @@ -276,7 +276,7 @@ static void check_traffic_flow_router_module_type(std::string router_module_name */ if (!is_tile_compatible(noc_router_tile_type, router_module_logical_type)){ - VPR_FATAL_ERROR(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "%s", "The supplied module name '%s' is not a NoC router.", router_module_name); + VPR_FATAL_ERROR(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "%s", "The supplied module name '%s' is not a NoC router. Found in file: %s, line: %d.", router_module_name, loc_data.filename_c_str(), loc_data.line(single_flow_tag)); } return; @@ -342,11 +342,12 @@ static void check_that_all_router_blocks_have_an_associated_traffic_flow(NocCont } /* - Every router block in the design needs to be part of a traffic flow. There can never be a router that isnt part of a traffic flow, other wise the router is doing nothing. So check that the number of unique routers in all traffic flows equals the number of router blocks in the design, otherwise throw an error. + Every router block in the design needs to be part of a traffic flow. There can never be a router that isnt part of a traffic flow, other wise the router is doing nothing. So check that the number of unique routers in all traffic flows equals the number of router blocks in the design, otherwise throw an warning to let the user know. If there aren't + any traffic flows for any routers then the NoC is not being used. */ if (noc_ctx.noc_traffic_flows_storage.get_number_of_routers_used_in_traffic_flows() != number_of_router_blocks_in_design){ - VPR_FATAL_ERROR(VPR_ERROR_OTHER, "NoC traffic flows file '%s' does not contain all router modules in the design. Every router module in the design must be part of a traffic flow (communicationg to another router).", noc_flows_file); + VTR_LOG_WARN("NoC traffic flows file '%s' does not contain all router modules in the design. Every router module in the design must be part of a traffic flow (communicationg to another router).", noc_flows_file); } return; diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.h b/vpr/src/noc/read_xml_noc_traffic_flows_file.h index 7f21e112de5..affc594b368 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.h +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.h @@ -21,7 +21,7 @@ constexpr int NUMERICAL_ATTRIBUTE_CONVERSION_FAILURE = -1; * * @param noc_flows_file Name of the noc '.flows' file */ -void read_xml_noc_traffic_flows_file(char* noc_flows_file); +void read_xml_noc_traffic_flows_file(const char* noc_flows_file); From d14f6bb5229afd5fbce77b9581a474c0c6aca1a8 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 13 May 2022 00:42:55 -0400 Subject: [PATCH 074/128] in the command line added the option to provide a noc traffic flows file --- vpr/src/base/SetupVPR.cpp | 1 + vpr/src/base/ShowSetup.cpp | 10 ++++++++++ vpr/src/base/read_options.cpp | 14 +++++++++++++- vpr/src/base/read_options.h | 1 + vpr/src/base/vpr_types.h | 1 + 5 files changed, 26 insertions(+), 1 deletion(-) diff --git a/vpr/src/base/SetupVPR.cpp b/vpr/src/base/SetupVPR.cpp index 52e7670c7ed..062fdaca11b 100644 --- a/vpr/src/base/SetupVPR.cpp +++ b/vpr/src/base/SetupVPR.cpp @@ -665,6 +665,7 @@ static void SetupPowerOpts(const t_options& Options, t_power_opts* power_opts, t static void SetupNocOpts(const t_options& Options, t_noc_opts* NocOpts) { // assign the noc specific options from the command line NocOpts->noc = Options.noc; + NocOpts->noc_flows_file = Options.noc_flows_file; return; } diff --git a/vpr/src/base/ShowSetup.cpp b/vpr/src/base/ShowSetup.cpp index 782038c4a31..4c47940d9b3 100644 --- a/vpr/src/base/ShowSetup.cpp +++ b/vpr/src/base/ShowSetup.cpp @@ -20,6 +20,7 @@ static void ShowPlacerOpts(const t_placer_opts& PlacerOpts, const t_annealing_sched& AnnealSched); static void ShowRouterOpts(const t_router_opts& RouterOpts); static void ShowAnalysisOpts(const t_analysis_opts& AnalysisOpts); +static void ShowNocOpts(const t_noc_opts& NocOpts); static void ShowAnnealSched(const t_annealing_sched& AnnealSched); @@ -61,6 +62,9 @@ void ShowSetup(const t_vpr_setup& vpr_setup) { if (vpr_setup.AnalysisOpts.doAnalysis) { ShowAnalysisOpts(vpr_setup.AnalysisOpts); } + if (vpr_setup.NocOpts.noc) { + ShowNocOpts(vpr_setup.NocOpts); + } } void ClusteredNetlistStats::writeHuman(std::ostream& output) const { @@ -764,3 +768,9 @@ static void ShowPackerOpts(const t_packer_opts& PackerOpts) { VTR_LOG("\n"); VTR_LOG("\n"); } + +static void ShowNocOpts(const t_noc_opts& NocOpts){ + VTR_LOG("NocOpts.noc_flows_file: %s\n", NocOpts.noc_flows_file); + + // add future options here (routing algorithm etc...) +} \ No newline at end of file diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index 2552ce0b3e4..78629c80b1c 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -2620,6 +2620,13 @@ argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& arg "This should be on only when the FPGA device contains a NoC and the provided netlist connects to the NoC.") .default_value("off") .show_in(argparse::ShowIn::HELP_ONLY); + + noc_grp.add_argument(args.noc_flows_file, "--noc_flows_file") + .help( + "XML file containing the list of traffic flows within the NoC (communication between routers)." + "This is required is required if --noc option is turned on.") + .default_value("") + .show_in(argparse::ShowIn::HELP_ONLY); return parser; } @@ -2802,7 +2809,7 @@ void set_conditional_defaults(t_options& args) { bool verify_args(const t_options& args) { /* - * Check for conflicting paramaters + * Check for conflicting paramaters or dependencies where one parameter set requires another parameter to be included */ if (args.read_rr_graph_file.provenance() == Provenance::SPECIFIED && args.RouteChanWidth.provenance() != Provenance::SPECIFIED) { @@ -2825,5 +2832,10 @@ bool verify_args(const t_options& args) { args.router_lookahead_type.argument_name().c_str()); } + if (args.noc.provenance() == Provenance::SPECIFIED && args.noc_flows_file.provenance() != Provenance::SPECIFIED) { + VPR_FATAL_ERROR(VPR_ERROR_OTHER, + "--noc_flows_file option must be specified if --noc is turned on.\n"); + } + return true; } diff --git a/vpr/src/base/read_options.h b/vpr/src/base/read_options.h index b995c044b0d..c11241989a4 100644 --- a/vpr/src/base/read_options.h +++ b/vpr/src/base/read_options.h @@ -140,6 +140,7 @@ struct t_options { /*NoC Options*/ argparse::ArgValue noc; + argparse::ArgValue noc_flows_file; /* Timing-driven placement options only */ argparse::ArgValue PlaceTimingTradeoff; diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index 2f63d450c9e..2f2cdff93a0 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -1272,6 +1272,7 @@ struct t_analysis_opts { // used to store NoC specific options, when supplied as an input by the user struct t_noc_opts { bool noc; /// Date: Fri, 13 May 2022 00:49:08 -0400 Subject: [PATCH 075/128] added the noc .flows file parser within the vpr flow --- vpr/src/base/vpr_api.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index 44565f36aed..592b1ecfaeb 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -39,6 +39,7 @@ #include "SetupGrid.h" #include "setup_clocks.h" #include "setup_noc.h" +#include "read_xml_noc_traffic_flows_file.h" #include "stats.h" #include "read_options.h" #include "echo_files.h" @@ -507,6 +508,8 @@ void vpr_setup_noc(const t_vpr_setup& vpr_setup, const t_arch& arch) { if (vpr_setup.NocOpts.noc == true) { // create the NoC model based on the user description from the arch file setup_noc(arch); + // read and store the noc traffic flow information + read_xml_noc_traffic_flows_file(vpr_setup.NocOpts.noc_flows_file.c_str()); #ifndef NO_GRAPHICS // setup the graphics From b30a1f6c980645b6c5b5b06d0490a572639b713a Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 16 May 2022 14:02:42 -0400 Subject: [PATCH 076/128] converted strings to characters before logging errors --- vpr/src/base/ShowSetup.cpp | 3 ++- .../noc/read_xml_noc_traffic_flows_file.cpp | 24 +++++++++---------- 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/vpr/src/base/ShowSetup.cpp b/vpr/src/base/ShowSetup.cpp index 4c47940d9b3..86e32cd726c 100644 --- a/vpr/src/base/ShowSetup.cpp +++ b/vpr/src/base/ShowSetup.cpp @@ -770,7 +770,8 @@ static void ShowPackerOpts(const t_packer_opts& PackerOpts) { } static void ShowNocOpts(const t_noc_opts& NocOpts){ - VTR_LOG("NocOpts.noc_flows_file: %s\n", NocOpts.noc_flows_file); + VTR_LOG("NocOpts.noc_flows_file: %s\n", NocOpts.noc_flows_file.c_str()); + VTR_LOG("\n"); // add future options here (routing algorithm etc...) } \ No newline at end of file diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index aba0d8f647e..125571f6ffa 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -82,20 +82,18 @@ void read_xml_noc_traffic_flows_file(const char* noc_flows_file){ // Root tag should be traffic_flows auto traffic_flows_tag = pugiutil::get_single_child(doc, "traffic_flows", loc_data); + // quick check to make sure that we only have single_flow tags within the traffic_flows tag + pugiutil::expect_only_children(traffic_flows_tag, {"single_flow"}, loc_data); + // process the individual traffic flows below for (pugi::xml_node single_flow : traffic_flows_tag.children()){ - // we can only have "single_flow" tags within "traffic_flows" so check that - if (single_flow.name() != std::string("single_flow")) { - bad_tag(single_flow, loc_data, traffic_flows_tag, {"single_flow"}); - } - else { - // current tag is a valid "flow" so process it - process_single_flow(single_flow, loc_data, cluster_ctx, noc_ctx, noc_router_tile_type); - } + // current tag is a valid "flow" so process it + process_single_flow(single_flow, loc_data, cluster_ctx, noc_ctx, noc_router_tile_type); } } catch(pugiutil::XmlError& e) { // used for identifying any of the xml parsing library errors + vpr_throw(VPR_ERROR_OTHER, noc_flows_file, e.line(), e.what()); } @@ -137,9 +135,9 @@ static void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil:: pugiutil::expect_only_attributes(single_flow_tag, expected_single_flow_attributes, loc_data); // store the names of the routers part of this traffic flow - std::string source_router_module_name = pugiutil::get_attribute(single_flow_tag, "src", loc_data, pugiutil::REQUIRED).as_string(); + std::string source_router_module_name = pugiutil::get_attribute(single_flow_tag, "src", loc_data, pugiutil::REQUIRED).value(); - std::string destination_router_module_name = pugiutil::get_attribute(single_flow_tag, "dst", loc_data, pugiutil::REQUIRED).as_string(); + std::string destination_router_module_name = pugiutil::get_attribute(single_flow_tag, "dst", loc_data, pugiutil::REQUIRED).value(); //verify whether the router module names are legal verify_traffic_flow_router_modules(source_router_module_name, destination_router_module_name, single_flow_tag, loc_data); @@ -238,9 +236,9 @@ static ClusterBlockId get_router_module_cluster_id(std::string router_module_nam ClusterBlockId router_module_id = cluster_ctx.clb_nlist.find_block(router_module_name); // check if a valid block id was found - if ((size_t)router_module_id == (size_t)ClusterBlockId::INVALID){ + if ((size_t)router_module_id == (size_t)ClusterBlockId::INVALID()){ // if here then the module did not exist in the design, so throw an error - vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "The router module '%s' does not exist in the design.", router_module_id); + vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "The router module '%s' does not exist in the design.", router_module_name.c_str()); } return router_module_id; @@ -347,7 +345,7 @@ static void check_that_all_router_blocks_have_an_associated_traffic_flow(NocCont */ if (noc_ctx.noc_traffic_flows_storage.get_number_of_routers_used_in_traffic_flows() != number_of_router_blocks_in_design){ - VTR_LOG_WARN("NoC traffic flows file '%s' does not contain all router modules in the design. Every router module in the design must be part of a traffic flow (communicationg to another router).", noc_flows_file); + VTR_LOG_WARN("NoC traffic flows file '%s' does not contain all router modules in the design. Every router module in the design must be part of a traffic flow (communicating to another router). Otherwise the router is being unused.\n", noc_flows_file.c_str()); } return; From 4175d5113e8d9d9871636479da9f8cf9db36fdfb Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 16 May 2022 14:03:54 -0400 Subject: [PATCH 077/128] modified help message for noc traffic flows file argument --- vpr/src/base/read_options.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index 78629c80b1c..f4026204ff6 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -2624,7 +2624,7 @@ argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& arg noc_grp.add_argument(args.noc_flows_file, "--noc_flows_file") .help( "XML file containing the list of traffic flows within the NoC (communication between routers)." - "This is required is required if --noc option is turned on.") + "This is required if the --noc option is turned on.") .default_value("") .show_in(argparse::ShowIn::HELP_ONLY); From 91daab2f2380943717618942ecbf49d9e3285866 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Sun, 22 May 2022 23:59:49 -0400 Subject: [PATCH 078/128] added functions to the clustered netlist and netlist classes that are capable of finding blocks by matching a string pattern in the block name instead of the exact string name --- vpr/src/base/clustered_netlist.cpp | 77 ++++++++++++++++++++++++++++++ vpr/src/base/clustered_netlist.h | 17 ++++++- vpr/src/base/netlist.h | 7 +++ vpr/src/base/netlist.tpp | 35 ++++++++++++++ 4 files changed, 134 insertions(+), 2 deletions(-) diff --git a/vpr/src/base/clustered_netlist.cpp b/vpr/src/base/clustered_netlist.cpp index 146e104d340..efa435a6b30 100644 --- a/vpr/src/base/clustered_netlist.cpp +++ b/vpr/src/base/clustered_netlist.cpp @@ -121,6 +121,8 @@ ClusterBlockId ClusteredNetlist::create_block(const char* name, t_pb* pb, t_logi //Allocate and initialize every potential pin of the block block_logical_pins_.insert(blk_id, std::vector(get_max_num_pins(type), ClusterPinId::INVALID())); + + add_block_to_logical_type(blk_id, type); } //Check post-conditions: size @@ -274,6 +276,30 @@ void ClusteredNetlist::shrink_to_fit_impl() { net_is_global_.shrink_to_fit(); } +/** + * @brief Given a newly created block, find its logical type and store the + * block in a list where all the other blocks in the list are of the + * blocks logical type. + */ +void ClusteredNetlist::add_block_to_logical_type(ClusterBlockId blk_id, t_logical_block_type_ptr type){ + + std::string logical_block_type_name = type->name; + + // check if a group of blocks exist for the current logical block type + // basically checking if this is the first time we are seeing this logical block type + auto logical_type_blocks = block_type_to_id.find(logical_block_type_name); + + if (logical_type_blocks == block_type_to_id.end()){ + // if the current logical block doesnt exist then create a new group of blocks for it and add it + block_type_to_id.emplace(logical_block_type_name, std::vector({blk_id})); + } + else{ + // current logical block exists, so add the current block to the group other blocks of this type + logical_type_blocks->second.push_back(blk_id); + } + return; +} + /* * * Sanity Checks @@ -306,3 +332,54 @@ bool ClusteredNetlist::validate_net_sizes_impl(size_t num_nets) const { } return true; } + +/** + * @brief Finds a block where the blocks name contains within it the + * provided input name. The intented use is to find the block id of a + * hard block when provided with the its module name in the HDL design. + * + * For example, suppose a RAM block was instantiated in the design and it + * was named "test_ram". The generated netlist would not have the block + * named as "test_ram", instead it would be something different but the + * name should contain "test_ram" inside it since it represents that + * block. If "test_ram" is provided to find_block() above, then an + * invalid block ID would be returned. The find_block_with_matching_name + * () can instead be used and it should find the ram block that has + * "test_ram" within its name. + * + * There is a similiar function in the Netlist Class. This function + * additionally requires the logical type of the block as well. Since + * the inteded use is to find hard blocks, it is quite inefficient to + * to go through all the blocks to find a matching one. Instead, an + * additional datastructure is created that groups clusters by their + * logical type. This function filters the clusters and only searches + * for the matching block within a list of blocks that are the same + * logical type. The idea here is that the filtered list should be + * considereably smaller that a list of every block in the netlist + * and this should help improve run time. + * + */ +ClusterBlockId ClusteredNetlist::find_block_with_matching_name(const std::string& name, t_logical_block_type_ptr blk_type){ + + ClusterBlockId blk_id = ClusterBlockId::INVALID(); + auto blks_of_logical_type = block_type_to_id.find(blk_type->name); + std::regex name_to_match(name); + + if (blks_of_logical_type != block_type_to_id.end()){ + // get the list of blocks that are of the specified logical type + std::vector* blk_list = &blks_of_logical_type->second; + + // go through the list of blocks to find if any block name matches the provided name (contains the input string in its name) + for (auto blk = blk_list->begin(); blk != blk_list->end(); blk++){ + + // another thing you can do is go through blocks and instead string.find(), you can use a regular expression version (so match a regular expression) + + // check for the string match + if (std::regex_match(Netlist::block_name(*blk), name_to_match)){ + blk_id = *blk; + break; + } + } + } + return blk_id; +} diff --git a/vpr/src/base/clustered_netlist.h b/vpr/src/base/clustered_netlist.h index 144c30dc095..57d1bfa084f 100644 --- a/vpr/src/base/clustered_netlist.h +++ b/vpr/src/base/clustered_netlist.h @@ -242,6 +242,9 @@ class ClusteredNetlist : public Netlist block_pbs_; /// block_types_; ///> block_logical_pins_; ///> block_type_to_id;///::find_block(const std::string& na } } +/** + * @brief Finds a block where the blocks name contains within it the + * provided input name. The intented use is to find the block id of a + * hard block when provided with the its module name in the HDL design. + * + * For example, suppose a RAM block was instantiated in the design and it + * was named "test_ram". The generated netlist would not have the block + * named as "test_ram", instead it would be something different but the + * name should contain "test_ram" inside it since it represents that + * block. If "test_ram" is provided to find_block() above, then an + * invalid block ID would be returned. The find_block_with_matching_name + * () can instead be used and it should find the ram block that has + * "test_ram" within its name. + * + */ +template +BlockId Netlist::find_block_with_matching_name(const std::string& name) const { + + BlockId matching_blk_id = BlockId::INVALID(); + const std::string blk_name; + + // go through all the blocks in the netlist + for (auto blk_id = block_ids_.begin(); blk_id != block_ids_.end(); blk_id++){ + // get the corresponding block name + blk_name = &strings_[block_names_[*blk_id]]; + // check whether the current block name contains the input string within it + if (blk_name.find(name) != std::string::npos){ + matching_blk_id = blk_id; + break; + } + } + return matching_blk_id; +} + + template PortId Netlist::find_port(const BlockId blk_id, const std::string& name) const { VTR_ASSERT_SAFE(valid_block_id(blk_id)); From 9873d39b7258039987dc9b7346234cae7113883b Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 23 May 2022 00:06:56 -0400 Subject: [PATCH 079/128] created a unit test to verify the functionality of the function that can find a block in a netlist by matching a string pattern in the blocks name --- vpr/test/test_clustered_netlist.cpp | 33 +++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 vpr/test/test_clustered_netlist.cpp diff --git a/vpr/test/test_clustered_netlist.cpp b/vpr/test/test_clustered_netlist.cpp new file mode 100644 index 00000000000..fafc0ca817f --- /dev/null +++ b/vpr/test/test_clustered_netlist.cpp @@ -0,0 +1,33 @@ +#include "catch2/catch_test_macros.hpp" +#include "catch2/matchers/catch_matchers_all.hpp" + + +#include "clustered_netlist.h" + +namespace { + +TEST_CASE("test_find_block_with_matching_name", "[vpr_clustered_netlist]") { + + // create some sample logical types that we will use when creating new cluster blocks + t_logical_block_type router_block; + char router[] = "router"; + router_block.name = router; + t_logical_block_type_ptr router_ref = &router_block; + + t_logical_block_type i_o_block; + char i_o[] = "IO"; + i_o_block.name = i_o; + t_logical_block_type_ptr i_o_ref = &i_o_block; + + // need to create the cluster netlist object that will hold the blocks + ClusteredNetlist test_netlist("test_netlist", "77"); + + // need to create the sample names for clusters in the design + + + + + +} + +} \ No newline at end of file From 76016e121270056d76a4c86711543662d79f9e55 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 24 May 2022 13:38:40 -0400 Subject: [PATCH 080/128] made the find_block_with_matching_name function public instead of private in the ClusteredNetlist class --- vpr/src/base/clustered_netlist.h | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/vpr/src/base/clustered_netlist.h b/vpr/src/base/clustered_netlist.h index 57d1bfa084f..d220c1e6615 100644 --- a/vpr/src/base/clustered_netlist.h +++ b/vpr/src/base/clustered_netlist.h @@ -228,6 +228,14 @@ class ClusteredNetlist : public Netlist block_pbs_; /// Date: Tue, 24 May 2022 13:39:28 -0400 Subject: [PATCH 081/128] added some additiontal tests to verify the find_block_with_matching_name function --- vpr/test/test_clustered_netlist.cpp | 112 +++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/vpr/test/test_clustered_netlist.cpp b/vpr/test/test_clustered_netlist.cpp index fafc0ca817f..c89517ce129 100644 --- a/vpr/test/test_clustered_netlist.cpp +++ b/vpr/test/test_clustered_netlist.cpp @@ -4,6 +4,10 @@ #include "clustered_netlist.h" +#include +#include +#include + namespace { TEST_CASE("test_find_block_with_matching_name", "[vpr_clustered_netlist]") { @@ -19,11 +23,117 @@ TEST_CASE("test_find_block_with_matching_name", "[vpr_clustered_netlist]") { i_o_block.name = i_o; t_logical_block_type_ptr i_o_ref = &i_o_block; + t_pb router_pb; + t_pb i_o_pb; + + // datastructure to keep track of blocks name to its id + std::map block_id_from_name; + // need to create the cluster netlist object that will hold the blocks ClusteredNetlist test_netlist("test_netlist", "77"); - // need to create the sample names for clusters in the design + // creating some names for i_o_blocks + // These will act as fillers to make sure that the matching function correctly handles a netlist with different types of blocks + + char io_port_one[] = "io_port_one"; + char io_port_two[] = "io_port_two"; + char io_port_three[] = "io_port_three"; + char io_port_four[] = "io_port_four"; + + // add the io blocks to the netlist + block_id_from_name.emplace(io_port_one, test_netlist.create_block(io_port_one, &i_o_pb, i_o_ref)); + block_id_from_name.emplace(io_port_two, test_netlist.create_block(io_port_two, &i_o_pb, i_o_ref)); + block_id_from_name.emplace(io_port_three, test_netlist.create_block(io_port_three, &i_o_pb, i_o_ref)); + block_id_from_name.emplace(io_port_four, test_netlist.create_block(io_port_four, &i_o_pb, i_o_ref)); + SECTION("Test find_block_with_matching_name when the input string is the instance name of the block"){ + + // create names for some router blocks + char router_one[] = "router:noc_router_one"; + char router_two[] = "router:noc_router_two"; + char router_three[] = "router:noc_router_three"; + char router_four[] = "router:noc_router_four"; + + // add the routers + block_id_from_name.emplace(router_one, test_netlist.create_block(router_one, &router_pb, router_ref)); + block_id_from_name.emplace(router_two, test_netlist.create_block(router_two, &router_pb, router_ref)); + block_id_from_name.emplace(router_three, test_netlist.create_block(router_three, &router_pb, router_ref)); + block_id_from_name.emplace(router_four, test_netlist.create_block(router_four, &router_pb, router_ref)); + + // now find a block just knowing its instance name + // the test names will have an arbritary number of characters in front and then the name of the instance and then maybe some characters after + std::string test_router_module_name = "*noc_router_one*"; + + //get the block id + ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, router_ref); + + // now check the block id with what we expect to be + REQUIRE((size_t)(block_id_from_name.find("router:noc_router_one")->second) == (size_t)test_router_id); + + } + SECTION("Test find_block_with_matching_name when the input string is a unique port name connecting to the block"){ + + // create the name of the router blocks + // the idea here is to create test cases where all the names of the blocks have the same block name but have a unique component identifying them + // this is a name identifying the net + char router_one[] = "router:new_router|q_a[1]"; + char router_two[] = "router:new_router|q_a[2]"; + char router_three[] = "router:new_router|q_a[3]"; + char router_four[] = "router:new_router|q_a[4]"; + + // add the routers + block_id_from_name.emplace(router_one, test_netlist.create_block(router_one, &router_pb, router_ref)); + block_id_from_name.emplace(router_two, test_netlist.create_block(router_two, &router_pb, router_ref)); + block_id_from_name.emplace(router_three, test_netlist.create_block(router_three, &router_pb, router_ref)); + block_id_from_name.emplace(router_four, test_netlist.create_block(router_four, &router_pb, router_ref)); + + // now find a block just knowing its unique identifier + // the test names will have an arbritary number of characters in front of them and the unique identifier at the end + std::string test_router_module_name = "*q_a_[2]"; + + //get the block id + ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, router_ref); + + // now check the block id with what we expect to be + REQUIRE((size_t)(block_id_from_name.find("router:new_router|q_a[2]")->second) == (size_t)test_router_id); + + } + SECTION("Test find_block_with_matching_name when multiple blocks match the input string "){ + + // create the name of the router blocks + char router_one[] = "router:noc_router_one|flit_out_two[0]~reg0"; + char router_two[] = "router:noc_router_two|flit_out_two[0]~reg0"; + char router_three[] = "router:noc_router_three|flit_out_two[0]~reg0"; + char router_four[] = "router:noc_router_four|flit_out_two[0]~reg0"; + + // need to create another block of a different type that has the same name as one of the router blocks + char i_o_block_with_same_name[] = "io|router:noc_router_four|flit_out_two[0]~reg0"; + + + // add the routers and the IO block + + // add the IO block with a similiar name + block_id_from_name.emplace(i_o_block_with_same_name, test_netlist.create_block(i_o_block_with_same_name, &i_o_pb, i_o_ref)); + + // add routers + block_id_from_name.emplace(router_one, test_netlist.create_block(router_one, &router_pb, router_ref)); + block_id_from_name.emplace(router_two, test_netlist.create_block(router_two, &router_pb, router_ref)); + block_id_from_name.emplace(router_three, test_netlist.create_block(router_three, &router_pb, router_ref)); + block_id_from_name.emplace(router_four, test_netlist.create_block(router_four, &router_pb, router_ref)); + + // now find a block just knowing its unique identifier + // THe identifier we use will match with multiple blocks in this test case + std::string test_router_module_name = "*noc_router_four|flit_out_two[0]~reg0"; + + //get the block id + ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, router_ref); + + // since we passed in the router logical type, we expect the router block to be the returned id + + // now check the block id with what we expect to be + REQUIRE((size_t)(block_id_from_name.find("router:noc_router_four|flit_out_two[0]~reg0")->second) == (size_t)test_router_id); + + } From 279f89da61a8f2d33c3f1a8118d34e8e307580a2 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 24 May 2022 17:22:02 -0400 Subject: [PATCH 082/128] fixed unit tests for the find_block_with_matching_name function and verified it worked correctly --- vpr/test/test_clustered_netlist.cpp | 213 ++++++++++++++-------------- 1 file changed, 104 insertions(+), 109 deletions(-) diff --git a/vpr/test/test_clustered_netlist.cpp b/vpr/test/test_clustered_netlist.cpp index c89517ce129..80608f443fe 100644 --- a/vpr/test/test_clustered_netlist.cpp +++ b/vpr/test/test_clustered_netlist.cpp @@ -10,134 +10,129 @@ namespace { -TEST_CASE("test_find_block_with_matching_name", "[vpr_clustered_netlist]") { - - // create some sample logical types that we will use when creating new cluster blocks - t_logical_block_type router_block; - char router[] = "router"; - router_block.name = router; - t_logical_block_type_ptr router_ref = &router_block; - - t_logical_block_type i_o_block; - char i_o[] = "IO"; - i_o_block.name = i_o; - t_logical_block_type_ptr i_o_ref = &i_o_block; - - t_pb router_pb; - t_pb i_o_pb; - - // datastructure to keep track of blocks name to its id - std::map block_id_from_name; - - // need to create the cluster netlist object that will hold the blocks - ClusteredNetlist test_netlist("test_netlist", "77"); - - // creating some names for i_o_blocks - // These will act as fillers to make sure that the matching function correctly handles a netlist with different types of blocks - - char io_port_one[] = "io_port_one"; - char io_port_two[] = "io_port_two"; - char io_port_three[] = "io_port_three"; - char io_port_four[] = "io_port_four"; - - // add the io blocks to the netlist - block_id_from_name.emplace(io_port_one, test_netlist.create_block(io_port_one, &i_o_pb, i_o_ref)); - block_id_from_name.emplace(io_port_two, test_netlist.create_block(io_port_two, &i_o_pb, i_o_ref)); - block_id_from_name.emplace(io_port_three, test_netlist.create_block(io_port_three, &i_o_pb, i_o_ref)); - block_id_from_name.emplace(io_port_four, test_netlist.create_block(io_port_four, &i_o_pb, i_o_ref)); - - SECTION("Test find_block_with_matching_name when the input string is the instance name of the block"){ - - // create names for some router blocks - char router_one[] = "router:noc_router_one"; - char router_two[] = "router:noc_router_two"; - char router_three[] = "router:noc_router_three"; - char router_four[] = "router:noc_router_four"; - - // add the routers - block_id_from_name.emplace(router_one, test_netlist.create_block(router_one, &router_pb, router_ref)); - block_id_from_name.emplace(router_two, test_netlist.create_block(router_two, &router_pb, router_ref)); - block_id_from_name.emplace(router_three, test_netlist.create_block(router_three, &router_pb, router_ref)); - block_id_from_name.emplace(router_four, test_netlist.create_block(router_four, &router_pb, router_ref)); - - // now find a block just knowing its instance name - // the test names will have an arbritary number of characters in front and then the name of the instance and then maybe some characters after - std::string test_router_module_name = "*noc_router_one*"; - - //get the block id - ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, router_ref); - - // now check the block id with what we expect to be - REQUIRE((size_t)(block_id_from_name.find("router:noc_router_one")->second) == (size_t)test_router_id); + TEST_CASE("test_find_block_with_matching_name", "[vpr_clustered_netlist]") { - } - SECTION("Test find_block_with_matching_name when the input string is a unique port name connecting to the block"){ + // create some sample logical types that we will use when creating new cluster blocks + t_logical_block_type router_block; + char router[] = "router"; + router_block.name = router; + t_logical_block_type_ptr router_ref = &router_block; - // create the name of the router blocks - // the idea here is to create test cases where all the names of the blocks have the same block name but have a unique component identifying them - // this is a name identifying the net - char router_one[] = "router:new_router|q_a[1]"; - char router_two[] = "router:new_router|q_a[2]"; - char router_three[] = "router:new_router|q_a[3]"; - char router_four[] = "router:new_router|q_a[4]"; + t_logical_block_type i_o_block; + char i_o[] = "IO"; + i_o_block.name = i_o; + t_logical_block_type_ptr i_o_ref = &i_o_block; - // add the routers - block_id_from_name.emplace(router_one, test_netlist.create_block(router_one, &router_pb, router_ref)); - block_id_from_name.emplace(router_two, test_netlist.create_block(router_two, &router_pb, router_ref)); - block_id_from_name.emplace(router_three, test_netlist.create_block(router_three, &router_pb, router_ref)); - block_id_from_name.emplace(router_four, test_netlist.create_block(router_four, &router_pb, router_ref)); + t_pb router_pb; + t_pb i_o_pb; - // now find a block just knowing its unique identifier - // the test names will have an arbritary number of characters in front of them and the unique identifier at the end - std::string test_router_module_name = "*q_a_[2]"; + // datastructure to keep track of blocks name to its id + std::map block_id_from_name; - //get the block id - ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, router_ref); + // need to create the cluster netlist object that will hold the blocks + ClusteredNetlist test_netlist("test_netlist", "77"); - // now check the block id with what we expect to be - REQUIRE((size_t)(block_id_from_name.find("router:new_router|q_a[2]")->second) == (size_t)test_router_id); + // creating some names for i_o_blocks + // These will act as fillers to make sure that the matching function correctly handles a netlist with different types of blocks - } - SECTION("Test find_block_with_matching_name when multiple blocks match the input string "){ + char io_port_one[] = "io_port_one"; + char io_port_two[] = "io_port_two"; + char io_port_three[] = "io_port_three"; + char io_port_four[] = "io_port_four"; - // create the name of the router blocks - char router_one[] = "router:noc_router_one|flit_out_two[0]~reg0"; - char router_two[] = "router:noc_router_two|flit_out_two[0]~reg0"; - char router_three[] = "router:noc_router_three|flit_out_two[0]~reg0"; - char router_four[] = "router:noc_router_four|flit_out_two[0]~reg0"; + // add the io blocks to the netlist + block_id_from_name.emplace(io_port_one, test_netlist.create_block(io_port_one, &i_o_pb, i_o_ref)); + block_id_from_name.emplace(io_port_two, test_netlist.create_block(io_port_two, &i_o_pb, i_o_ref)); + block_id_from_name.emplace(io_port_three, test_netlist.create_block(io_port_three, &i_o_pb, i_o_ref)); + block_id_from_name.emplace(io_port_four, test_netlist.create_block(io_port_four, &i_o_pb, i_o_ref)); - // need to create another block of a different type that has the same name as one of the router blocks - char i_o_block_with_same_name[] = "io|router:noc_router_four|flit_out_two[0]~reg0"; + SECTION("Test find_block_with_matching_name when the input string is the instance name of the block"){ + // create names for some router blocks + char router_one[] = "router:noc_router_one"; + char router_two[] = "router:noc_router_two"; + char router_three[] = "router:noc_router_three"; + char router_four[] = "router:noc_router_four"; - // add the routers and the IO block + // add the routers + block_id_from_name.emplace(router_one, test_netlist.create_block(router_one, &router_pb, router_ref)); + block_id_from_name.emplace(router_two, test_netlist.create_block(router_two, &router_pb, router_ref)); + block_id_from_name.emplace(router_three, test_netlist.create_block(router_three, &router_pb, router_ref)); + block_id_from_name.emplace(router_four, test_netlist.create_block(router_four, &router_pb, router_ref)); - // add the IO block with a similiar name - block_id_from_name.emplace(i_o_block_with_same_name, test_netlist.create_block(i_o_block_with_same_name, &i_o_pb, i_o_ref)); + // now find a block just knowing its instance name + // the test names will have an arbritary number of characters in front and then the name of the instance and then maybe some characters after + std::string test_router_module_name = "(.*)(noc_router_one)(.*)"; - // add routers - block_id_from_name.emplace(router_one, test_netlist.create_block(router_one, &router_pb, router_ref)); - block_id_from_name.emplace(router_two, test_netlist.create_block(router_two, &router_pb, router_ref)); - block_id_from_name.emplace(router_three, test_netlist.create_block(router_three, &router_pb, router_ref)); - block_id_from_name.emplace(router_four, test_netlist.create_block(router_four, &router_pb, router_ref)); + //get the block id + ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, router_ref); - // now find a block just knowing its unique identifier - // THe identifier we use will match with multiple blocks in this test case - std::string test_router_module_name = "*noc_router_four|flit_out_two[0]~reg0"; + // now check the block id with what we expect to be + REQUIRE((size_t)(block_id_from_name.find("router:noc_router_one")->second) == (size_t)test_router_id); - //get the block id - ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, router_ref); + } + SECTION("Test find_block_with_matching_name when the input string is a unique port name connecting to the block"){ - // since we passed in the router logical type, we expect the router block to be the returned id - - // now check the block id with what we expect to be - REQUIRE((size_t)(block_id_from_name.find("router:noc_router_four|flit_out_two[0]~reg0")->second) == (size_t)test_router_id); + // create the name of the router blocks + // the idea here is to create test cases where all the names of the blocks have the same block name but have a unique component identifying them + // this is a name identifying the net + char router_one[] = "router:new_router|q_a[1]"; + char router_two[] = "router:new_router|q_a[2]"; + char router_three[] = "router:new_router|q_a[3]"; + char router_four[] = "router:new_router|q_a[4]"; - } + // add the routers + block_id_from_name.emplace(router_one, test_netlist.create_block(router_one, &router_pb, router_ref)); + block_id_from_name.emplace(router_two, test_netlist.create_block(router_two, &router_pb, router_ref)); + block_id_from_name.emplace(router_three, test_netlist.create_block(router_three, &router_pb, router_ref)); + block_id_from_name.emplace(router_four, test_netlist.create_block(router_four, &router_pb, router_ref)); + + // now find a block just knowing its unique identifier + // the test names will have an arbritary number of characters in front of them and the unique identifier at the end + std::string test_router_module_name = "(.*)(q_a\\[2\\])(.*)"; + + //get the block id + ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, router_ref); + + // now check the block id with what we expect to be + REQUIRE((size_t)(block_id_from_name.find("router:new_router|q_a[2]")->second) == (size_t)test_router_id); + + } + SECTION("Test find_block_with_matching_name when multiple blocks match the input string "){ + + // create the name of the router blocks + char router_one[] = "router:noc_router_one|flit_out_two[0]~reg0"; + char router_two[] = "router:noc_router_two|flit_out_two[0]~reg0"; + char router_three[] = "router:noc_router_three|flit_out_two[0]~reg0"; + char router_four[] = "router:noc_router_four|flit_out_two[0]~reg0"; + // need to create another block of a different type that has the same name as one of the router blocks + char i_o_block_with_same_name[] = "io|router:noc_router_four|flit_out_two[0]~reg0"; - -} + // add the routers and the IO block + // add the IO block with a similiar name + block_id_from_name.emplace(i_o_block_with_same_name, test_netlist.create_block(i_o_block_with_same_name, &i_o_pb, i_o_ref)); + + // add routers + block_id_from_name.emplace(router_one, test_netlist.create_block(router_one, &router_pb, router_ref)); + block_id_from_name.emplace(router_two, test_netlist.create_block(router_two, &router_pb, router_ref)); + block_id_from_name.emplace(router_three, test_netlist.create_block(router_three, &router_pb, router_ref)); + block_id_from_name.emplace(router_four, test_netlist.create_block(router_four, &router_pb, router_ref)); + + // now find a block just knowing its unique identifier + // THe identifier we use will match with multiple blocks in this test case + std::string test_router_module_name = "(.*)(noc_router_four\\|flit_out_two\\[0\\]~reg0)$"; + + //get the block id + ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, router_ref); + + // since we passed in the router logical type, we expect the router block to be the returned id + + // now check the block id with what we expect to be + REQUIRE((size_t)(block_id_from_name.find("router:noc_router_four|flit_out_two[0]~reg0")->second) == (size_t)test_router_id); + + } + } } \ No newline at end of file From 74221177fdcd0c6b87f170c9d7b70d6bc272b92d Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 27 May 2022 13:34:42 -0400 Subject: [PATCH 083/128] changed the find_block_with_matching_name to a constant --- vpr/src/base/clustered_netlist.cpp | 4 ++-- vpr/src/base/clustered_netlist.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vpr/src/base/clustered_netlist.cpp b/vpr/src/base/clustered_netlist.cpp index efa435a6b30..7d2b8e4d816 100644 --- a/vpr/src/base/clustered_netlist.cpp +++ b/vpr/src/base/clustered_netlist.cpp @@ -359,7 +359,7 @@ bool ClusteredNetlist::validate_net_sizes_impl(size_t num_nets) const { * and this should help improve run time. * */ -ClusterBlockId ClusteredNetlist::find_block_with_matching_name(const std::string& name, t_logical_block_type_ptr blk_type){ +ClusterBlockId ClusteredNetlist::find_block_with_matching_name(const std::string& name, t_logical_block_type_ptr blk_type) const { ClusterBlockId blk_id = ClusterBlockId::INVALID(); auto blks_of_logical_type = block_type_to_id.find(blk_type->name); @@ -367,7 +367,7 @@ ClusterBlockId ClusteredNetlist::find_block_with_matching_name(const std::string if (blks_of_logical_type != block_type_to_id.end()){ // get the list of blocks that are of the specified logical type - std::vector* blk_list = &blks_of_logical_type->second; + const std::vector* blk_list = &blks_of_logical_type->second; // go through the list of blocks to find if any block name matches the provided name (contains the input string in its name) for (auto blk = blk_list->begin(); blk != blk_list->end(); blk++){ diff --git a/vpr/src/base/clustered_netlist.h b/vpr/src/base/clustered_netlist.h index d220c1e6615..a3c87abdf3b 100644 --- a/vpr/src/base/clustered_netlist.h +++ b/vpr/src/base/clustered_netlist.h @@ -234,7 +234,7 @@ class ClusteredNetlist : public Netlist Date: Fri, 27 May 2022 13:41:44 -0400 Subject: [PATCH 084/128] changed functions to static and modified the get_router_module_cluster_id function to use the find_block_with_matching_name function in the ClusteredNetlist class --- .../noc/read_xml_noc_traffic_flows_file.cpp | 192 ++++-------------- vpr/src/noc/read_xml_noc_traffic_flows_file.h | 133 +++++++++++- 2 files changed, 175 insertions(+), 150 deletions(-) diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index 125571f6ffa..16ca0ab82e6 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -13,43 +13,9 @@ * functions that assist in parsing the traffic flows file. * */ - -#include "pugixml.hpp" -#include "pugixml_util.hpp" -#include "read_xml_util.h" -#include "globals.h" - -#include "vtr_assert.h" -#include "vtr_util.h" -#include "ShowSetup.h" -#include "vpr_error.h" - -#include "noc_data_types.h" #include "read_xml_noc_traffic_flows_file.h" -static void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type); - -static void verify_traffic_flow_router_modules(std::string source_router_name, std::string destination_router_name, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data); - -static void verify_traffic_flow_properties(double traffic_flow_bandwidth, double max_traffic_flow_latency, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data); - -static ClusterBlockId get_router_module_cluster_id(std::string router_module_name, const ClusteringContext& cluster_ctx, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data); - -static void check_traffic_flow_router_module_type(std::string router_module_name, ClusterBlockId router_module_id, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, t_physical_tile_type_ptr noc_router_tile_type); - -static t_physical_tile_type_ptr get_physical_type_of_noc_router_tile(const DeviceContext& device_ctx, NocContext& noc_ctx); - -static void check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type, std::string noc_flows_file); - -/** - * @brief Main driver function that parsed the xml '.flows' file which - * contains all the traffic flows in the NoC. This function - * takes the parsed information and stores it inside the - * NocTrafficFlows class. - * - * @param noc_flows_file Name of the '.flows' file - */ void read_xml_noc_traffic_flows_file(const char* noc_flows_file){ // start by checking that the provided file is a ".flows" file @@ -106,24 +72,7 @@ void read_xml_noc_traffic_flows_file(const char* noc_flows_file){ } -/** - * @brief Takes a tag from the '.flows' file and extracts the - * flow information from it. This includes the two routers modules - * in the flow, the size of the data transferred and any latency - * constraints on the data transmission. The parsed information - * is verified and if it is legal then this traffic flow is added - * to the NocTrafficFlows class. - * - * @param single_flow_tag A xml tag that contains the traffic flow information - * @param loc_data Contains location data about the current line in the xml file - * @param cluster_ctx Global variable that contains clustering information. Used - * to get information about the router blocks int he design. - * @param noc_ctx Global variable that contains NoC information. Used to access - * the NocTrafficFlows class and store current flow. - * @param noc_router_tile_type The physical type of a Noc router tile in the - * FPGA. - */ -static void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type){ +void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type){ // contans all traffic flows NocTrafficFlows* noc_traffic_flow_storage = &noc_ctx.noc_traffic_flows_storage; @@ -143,8 +92,8 @@ static void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil:: verify_traffic_flow_router_modules(source_router_module_name, destination_router_module_name, single_flow_tag, loc_data); // assign the unique block ids of the two router modules after clustering - ClusterBlockId source_router_id = get_router_module_cluster_id(source_router_module_name, cluster_ctx, single_flow_tag, loc_data); - ClusterBlockId destination_router_id = get_router_module_cluster_id(destination_router_module_name, cluster_ctx, single_flow_tag, loc_data); + ClusterBlockId source_router_id = get_router_module_cluster_id(source_router_module_name, cluster_ctx, single_flow_tag, loc_data, noc_router_tile_type); + ClusterBlockId destination_router_id = get_router_module_cluster_id(destination_router_module_name, cluster_ctx, single_flow_tag, loc_data, noc_router_tile_type); // verify that the source and destination modules are actually noc routers check_traffic_flow_router_module_type(source_router_module_name, source_router_id, single_flow_tag, loc_data, cluster_ctx, noc_router_tile_type); @@ -164,19 +113,7 @@ static void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil:: } -/** - * @brief Checks to see that the two router module names provided in the - * traffic flow description are not empty and they dont have the - * same names. THe two routers cant be the exact same since a router - * cannot communicate with itself. - * - * @param source_router_name A string value of the source router module name - * @param destination_router_name A string value of the destination router - * module name - * @param single_flow_tag A xml tag that contains the traffic flow information - * @param loc_data Contains location data about the current line in the xml file - */ -static void verify_traffic_flow_router_modules(std::string source_router_name, std::string destination_router_name, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data){ +void verify_traffic_flow_router_modules(std::string source_router_name, std::string destination_router_name, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data){ // check that the router module names were legal if ((source_router_name.compare("") == 0) || (destination_router_name.compare("") == 0)){ @@ -193,19 +130,7 @@ static void verify_traffic_flow_router_modules(std::string source_router_name, s } -/** - * @brief Ensures that the a given traffic flows data transmission size and - * latency constraints are not negative values. - * - * @param traffic_flow_bandwidth The transmission size betwee the two routers - * in the traffic flow. - * @param max_traffic_flow_latency The allowable latency for the data - * transmission between the two routers in the - * traffic flow. - * @param single_flow_tag A xml tag that contains the traffic flow information - * @param loc_data Contains location data about the current line in the xml file - */ -static void verify_traffic_flow_properties(double traffic_flow_bandwidth, double max_traffic_flow_latency, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data){ +void verify_traffic_flow_properties(double traffic_flow_bandwidth, double max_traffic_flow_latency, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data){ // check that the bandwidth and max latency are positive values if ((traffic_flow_bandwidth < 0) || (max_traffic_flow_latency < 0)){ @@ -216,24 +141,42 @@ static void verify_traffic_flow_properties(double traffic_flow_bandwidth, double return; } -/** - * @brief Given a router module name in the design, retrieve the - * equivalent clustered router block identifier, which is - * a ClusterBlockId. - * - * @param router_module_name The name of the router module in the design for - * which the corresponding block id needs to be found. - * @param cluster_ctx Global variable that contains clustering information. - * Contains a datastructure to convert a module name to - * a cluster block id. - * @param single_flow_tag A xml tag that contains the traffic flow information - * @param loc_data Contains location data about the current line in the xml file - * @return ClusterBlockId The corresponding router block id of the provided - * router module name. - */ -static ClusterBlockId get_router_module_cluster_id(std::string router_module_name, const ClusteringContext& cluster_ctx, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data){ +ClusterBlockId get_router_module_cluster_id(std::string router_module_name, const ClusteringContext& cluster_ctx, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, t_physical_tile_type_ptr noc_router_tile_type){ + + ClusterBlockId router_module_id = ClusterBlockId::INVALID(); + + // get the subtiles of the noc router physical type + const std::vector* noc_router_subtiles = &noc_router_tile_type->sub_tiles; + + /* + iterate through all the logical block types that can be placed on the + NoC router tile. Check if the there is a cluster block that matches + the input router module name and is one of the supported logical + block types. + */ + for (auto sub_tile = noc_router_subtiles->begin(); sub_tile != noc_router_subtiles->end(); sub_tile++){ - ClusterBlockId router_module_id = cluster_ctx.clb_nlist.find_block(router_module_name); + //get the logical types the current tile supports + const std::vector* supported_noc_logical_types = &sub_tile->equivalent_sites; + + // go through each logical type and check if there is a cluster block + // of that type that also matches the input module name + for (auto logical_type = supported_noc_logical_types->begin(); logical_type != supported_noc_logical_types->end(); logical_type++){ + + router_module_id = cluster_ctx.clb_nlist.find_block_with_matching_name(router_module_name, *logical_type); + + // found a block for the current logical type, so exit + if ((size_t)router_module_id != (size_t)ClusterBlockId::INVALID()){ + break; + } + + } + // found a block for the current sub tile, so exit + if ((size_t)router_module_id != (size_t)ClusterBlockId::INVALID()){ + break; + } + + } // check if a valid block id was found if ((size_t)router_module_id == (size_t)ClusterBlockId::INVALID()){ @@ -245,32 +188,13 @@ static ClusterBlockId get_router_module_cluster_id(std::string router_module_nam } -/** - * @brief Checks to see whether a given router block is compatible with a NoC - * router tile, this helps determine whether the router block is a router - * or not (the user provided a name for another type of block in the - * design). - * - * @param router_module_name Name of the router module that we are trying to - * check whether it is of type router. - * @param router_module_id The ClusterBlockId of the router block we are trying - * to check if its of type router. - * @param single_flow_tag A xml tag that contains the traffic flow information - * @param loc_data Contains location data about the current line in the xml file - * @param cluster_ctx Global variable that contains clustering information. - * Contains a datastructure to get the logical type of a - * router cluster block. - * @param noc_router_tile_type The physical type of a Noc router tile in the - * FPGA. Used to check if the router block is - * compatible with a router tile. - */ -static void check_traffic_flow_router_module_type(std::string router_module_name, ClusterBlockId router_module_id, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, t_physical_tile_type_ptr noc_router_tile_type){ +void check_traffic_flow_router_module_type(std::string router_module_name, ClusterBlockId router_module_id, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, t_physical_tile_type_ptr noc_router_tile_type){ // get the logical type of the provided router module t_logical_block_type_ptr router_module_logical_type = cluster_ctx.clb_nlist.block_type(router_module_id); /* - Check of the current router nodules logical type is compatible with the physical type if a noc router (can the module be placed on a noc router tile on the FPGA device). If not then this module is not a router so throw an error. + Check the current router modules logical type is compatible with the physical type if a noc router (can the module be placed on a noc router tile on the FPGA device). If not then this module is not a router so throw an error. */ if (!is_tile_compatible(noc_router_tile_type, router_module_logical_type)){ @@ -281,17 +205,7 @@ static void check_traffic_flow_router_module_type(std::string router_module_name } -/** - * @brief Retreives the physical type of a noc router tile. - * - * @param device_ctx Contains the device information. Has a datastructure that - * can determine a tile type based on grid position on the - * FPGA. - * @param noc_ctx Contains the NoC information. Used to get the grid position - * of a NoC router tile. - * @return t_physical_tile_type_ptr The physical type of a NoC router tile - */ -static t_physical_tile_type_ptr get_physical_type_of_noc_router_tile(const DeviceContext& device_ctx, NocContext& noc_ctx){ +t_physical_tile_type_ptr get_physical_type_of_noc_router_tile(const DeviceContext& device_ctx, NocContext& noc_ctx){ // get a reference to a single physical noc router auto physical_noc_router = noc_ctx.noc_model.get_noc_routers().begin(); @@ -302,23 +216,7 @@ static t_physical_tile_type_ptr get_physical_type_of_noc_router_tile(const Devic } -/** - * @brief Verify that every router module in the design has an associated - * traffic flow to it. If a router module was instantiated in a design - * then it should be part of a traffic flow as either a source or - * destination router. If the module is not then we need to throw an - * error. - * - * @param noc_ctx Contains the NoC information. Used to get the total number - * unique routers found in all traffic flows. - * @param noc_router_tile_type The physical type of a Noc router tile in the - * FPGA. Used to get the logical types of all - * clustered router blocks in the that can be placed - * on a NoC router tile. - * @param noc_flows_file The name of the '.flows' file. Used when displaying - * the error. - */ -static void check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type, std::string noc_flows_file){ +void check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type, std::string noc_flows_file){ // contains the number of all the noc router blocks in the design const auto clustered_netlist_stats = ClusteredNetlistStats(); @@ -345,7 +243,7 @@ static void check_that_all_router_blocks_have_an_associated_traffic_flow(NocCont */ if (noc_ctx.noc_traffic_flows_storage.get_number_of_routers_used_in_traffic_flows() != number_of_router_blocks_in_design){ - VTR_LOG_WARN("NoC traffic flows file '%s' does not contain all router modules in the design. Every router module in the design must be part of a traffic flow (communicating to another router). Otherwise the router is being unused.\n", noc_flows_file.c_str()); + VTR_LOG_WARN("NoC traffic flows file '%s' does not contain all router modules in the design. Every router module in the design must be part of a traffic flow (communicating to another router). Otherwise the router is unused.\n", noc_flows_file.c_str()); } return; diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.h b/vpr/src/noc/read_xml_noc_traffic_flows_file.h index affc594b368..79c7fcb32eb 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.h +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.h @@ -1,11 +1,22 @@ #ifndef READ_XML_NOC_TRAFFIC_FLOWS_FILE_H #define READ_XML_NOC_TRAFFIC_FLOWS_FILE_H -#include"noc_traffic_flows.h" +#include "pugixml.hpp" +#include "pugixml_util.hpp" +#include "read_xml_util.h" +#include "globals.h" + +#include "vtr_assert.h" +#include "vtr_util.h" +#include "ShowSetup.h" +#include "vpr_error.h" + +#include "noc_data_types.h" +#include "noc_traffic_flows.h" #include -#include -#include +#include +#include // identifier when an integer conversion failed while reading an attribute value in an xml file constexpr int NUMERICAL_ATTRIBUTE_CONVERSION_FAILURE = -1; @@ -23,6 +34,122 @@ constexpr int NUMERICAL_ATTRIBUTE_CONVERSION_FAILURE = -1; */ void read_xml_noc_traffic_flows_file(const char* noc_flows_file); +/** + * @brief Takes a tag from the '.flows' file and extracts the + * flow information from it. This includes the two routers modules + * in the flow, the size of the data transferred and any latency + * constraints on the data transmission. The parsed information + * is verified and if it is legal then this traffic flow is added + * to the NocTrafficFlows class. + * + * @param single_flow_tag A xml tag that contains the traffic flow information + * @param loc_data Contains location data about the current line in the xml file + * @param cluster_ctx Global variable that contains clustering information. Used + * to get information about the router blocks int he design. + * @param noc_ctx Global variable that contains NoC information. Used to access + * the NocTrafficFlows class and store current flow. + * @param noc_router_tile_type The physical type of a Noc router tile in the + * FPGA. + */ +void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type); + +/** + * @brief Checks to see that the two router module names provided in the + * traffic flow description are not empty and they dont have the + * same names. THe two routers cant be the exact same since a router + * cannot communicate with itself. + * + * @param source_router_name A string value of the source router module name + * @param destination_router_name A string value of the destination router + * module name + * @param single_flow_tag A xml tag that contains the traffic flow information + * @param loc_data Contains location data about the current line in the xml file + */ +void verify_traffic_flow_router_modules(std::string source_router_name, std::string destination_router_name, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data); + +/** + * @brief Ensures that the a given traffic flows data transmission size and + * latency constraints are not negative values. + * + * @param traffic_flow_bandwidth The transmission size betwee the two routers + * in the traffic flow. + * @param max_traffic_flow_latency The allowable latency for the data + * transmission between the two routers in the + * traffic flow. + * @param single_flow_tag A xml tag that contains the traffic flow information + * @param loc_data Contains location data about the current line in the xml file + */ +void +verify_traffic_flow_properties(double traffic_flow_bandwidth, double max_traffic_flow_latency, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data); + +/** + * @brief Given a router module name in the design, retrieve the + * equivalent clustered router block identifier, which is + * a ClusterBlockId. + * + * @param router_module_name The name of the router module in the design for + * which the corresponding block id needs to be found. + * @param cluster_ctx Global variable that contains clustering information. + * Contains a datastructure to convert a module name to + * a cluster block id. + * @param single_flow_tag A xml tag that contains the traffic flow information + * @param loc_data Contains location data about the current line in the xml file + * @return ClusterBlockId The corresponding router block id of the provided + * router module name. + */ +ClusterBlockId get_router_module_cluster_id(std::string router_module_name, const ClusteringContext& cluster_ctx, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, t_physical_tile_type_ptr noc_router_tile_type); + +/** + * @brief Checks to see whether a given router block is compatible with a NoC + * router tile, this helps determine whether the router block is a router + * or not (the user provided a name for another type of block in the + * design). + * + * @param router_module_name Name of the router module that we are trying to + * check whether it is of type router. + * @param router_module_id The ClusterBlockId of the router block we are trying + * to check if its of type router. + * @param single_flow_tag A xml tag that contains the traffic flow information + * @param loc_data Contains location data about the current line in the xml file + * @param cluster_ctx Global variable that contains clustering information. + * Contains a datastructure to get the logical type of a + * router cluster block. + * @param noc_router_tile_type The physical type of a Noc router tile in the + * FPGA. Used to check if the router block is + * compatible with a router tile. + */ +void check_traffic_flow_router_module_type(std::string router_module_name, ClusterBlockId router_module_id, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, t_physical_tile_type_ptr noc_router_tile_type); + +/** + * @brief Retreives the physical type of a noc router tile. + * + * @param device_ctx Contains the device information. Has a datastructure that + * can determine a tile type based on grid position on the + * FPGA. + * @param noc_ctx Contains the NoC information. Used to get the grid position + * of a NoC router tile. + * @return t_physical_tile_type_ptr The physical type of a NoC router tile + */ +t_physical_tile_type_ptr get_physical_type_of_noc_router_tile(const DeviceContext& device_ctx, NocContext& noc_ctx); + +/** + * @brief Verify that every router module in the design has an associated + * traffic flow to it. If a router module was instantiated in a design + * then it should be part of a traffic flow as either a source or + * destination router. If the module is not then we need to throw an + * error. + * + * @param noc_ctx Contains the NoC information. Used to get the total number + * unique routers found in all traffic flows. + * @param noc_router_tile_type The physical type of a Noc router tile in the + * FPGA. Used to get the logical types of all + * clustered router blocks in the that can be placed + * on a NoC router tile. + * @param noc_flows_file The name of the '.flows' file. Used when displaying + * the error. + */ +void check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type, std::string noc_flows_file); + From 8d8af65ff6fabcc4618557e3c24c006be1da2460 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 27 May 2022 13:42:52 -0400 Subject: [PATCH 085/128] added a unit test to verify the verify_traffic_flow_router_modules --- .../test_read_xml_noc_traffic_flows_file.cpp | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 vpr/test/test_read_xml_noc_traffic_flows_file.cpp diff --git a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp new file mode 100644 index 00000000000..1d94e069cc7 --- /dev/null +++ b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp @@ -0,0 +1,55 @@ +#include "catch2/catch_test_macros.hpp" +#include "catch2/matchers/catch_matchers_all.hpp" + +#include "read_xml_noc_traffic_flows_file.h" + +namespace{ + + TEST_CASE("test_verify_traffic_flow_router_modules", "[vpr_noc_traffic_flows_parser]"){ + + // filler data for the xml information + // data for the xml parsing + pugi::xml_node test; + pugiutil::loc_data test_location; + + + SECTION("Test case where atleast one of the input strings for the source and destination router module name is empty"){ + + std::string src_router_name = ""; + std::string dst_router_name = "test"; + + REQUIRE_THROWS_WITH(verify_traffic_flow_router_modules(src_router_name, dst_router_name, test, test_location), "Invalid names for the source and destination NoC router modules."); + + } + SECTION("Test case where the router module names for both the source and destination routers are the same"){ + + std::string src_router_name = "same_router"; + std::string dst_router_name = "same_router"; + + REQUIRE_THROWS_WITH(verify_traffic_flow_router_modules(src_router_name, dst_router_name, test, test_location), "Source and destination NoC routers cannot be the same modules."); + } + SECTION("Test case where the source and destination router module names are legeal"){ + + std::string src_router_name = "source_router"; + std::string dst_router_name = "destination_router"; + + REQUIRE_NOTHROW(verify_traffic_flow_router_modules(src_router_name, dst_router_name, test, test_location)); + + } + + } + + + + + + + + + + + + + + +} \ No newline at end of file From 32125ffd0c92024f7467a799c0ce0c5184c72076 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 8 Jun 2022 00:46:27 -0400 Subject: [PATCH 086/128] changed a call of VPR_ERROR() to vpr_throw() --- vpr/src/noc/read_xml_noc_traffic_flows_file.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index 16ca0ab82e6..4bb9481495f 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -198,7 +198,7 @@ void check_traffic_flow_router_module_type(std::string router_module_name, Clust */ if (!is_tile_compatible(noc_router_tile_type, router_module_logical_type)){ - VPR_FATAL_ERROR(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "%s", "The supplied module name '%s' is not a NoC router. Found in file: %s, line: %d.", router_module_name, loc_data.filename_c_str(), loc_data.line(single_flow_tag)); + vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "The supplied module name '%s' is not a NoC router.", router_module_name.c_str()); } return; From 4837211e223a8c86ebed2990860bfd4ae7d4a638 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 8 Jun 2022 00:52:25 -0400 Subject: [PATCH 087/128] added unit tests to verify functions: verify_traffic_flow_properties,get_router_module_cluster_id, check_traffic_flow_router_module_type --- .../test_read_xml_noc_traffic_flows_file.cpp | 213 +++++++++++++++++- 1 file changed, 212 insertions(+), 1 deletion(-) diff --git a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp index 1d94e069cc7..a75f88b105d 100644 --- a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp +++ b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp @@ -36,20 +36,231 @@ namespace{ REQUIRE_NOTHROW(verify_traffic_flow_router_modules(src_router_name, dst_router_name, test, test_location)); } + } + TEST_CASE("test_verify_traffic_flow_properties", "[vpr_noc_traffic_flows_parser]"){ + + // filler data for the xml information + // data for the xml parsing + pugi::xml_node test; + pugiutil::loc_data test_location; + + SECTION("Test case where the noc traffic flow properties are illegal"){ + double test_traffic_flow_bandwidth = 1.5; + // illegal value + double test_max_traffic_flow_latency = -1.5; + + REQUIRE_THROWS_WITH(verify_traffic_flow_properties(test_traffic_flow_bandwidth, test_max_traffic_flow_latency, test, test_location), "The traffic flow bandwidth and latency constraints need to be positive values."); + } + SECTION("Test case where the noc traffic flows properties are legal"){ + + double test_traffic_flow_bandwidth = 1.5; + double test_max_traffic_flow_latency = 1.5; + + REQUIRE_NOTHROW(verify_traffic_flow_properties(test_traffic_flow_bandwidth, test_max_traffic_flow_latency, test, test_location)); + } } - + TEST_CASE("test_get_router_module_cluster_id", "[vpr_noc_traffic_flows_parser]"){ + + // filler data for the xml information + // data for the xml parsing + pugi::xml_node test; + pugiutil::loc_data test_location; + + // datastructure to keep track of blocks name to its id + std::map block_id_from_name; + + // get the global netlist + ClusteringContext& cluster_ctx = g_vpr_ctx.mutable_clustering(); + ClusteredNetlist* test_netlist = &cluster_ctx.clb_nlist; + + // create a new clustered netlist + *test_netlist = ClusteredNetlist("test_netlist", "77"); + + /* need to create the noc router physical type */ + + t_physical_tile_type noc_router; + + // create a single subtile + t_sub_tile router_tile; + + // there are two logical router types that are compatible with this subtile + t_logical_block_type router_block; + char router[] = "router"; + router_block.name = router; + t_logical_block_type_ptr router_ref = &router_block; + t_pb router_pb; + // second logical router block + t_logical_block_type router_block_2; + char router_2[] = "router_2"; + router_block_2.name = router_2; + t_logical_block_type_ptr router_ref_2 = &router_block_2; + t_pb router_2_pb; + + // add these two logical tyes as the equivalent sites of the subtile + router_tile.equivalent_sites.push_back(router_ref); + router_tile.equivalent_sites.push_back(router_ref_2); + // add the subtile to the physical noc router type + noc_router.sub_tiles.push_back(router_tile); + // create a reference to the physical type + t_physical_tile_type_ptr noc_router_ref = &noc_router; + /* finished creating noc router physical type */ + // creating an IO logical type + t_logical_block_type i_o_block; + char i_o[] = "IO"; + i_o_block.name = i_o; + t_logical_block_type_ptr i_o_ref = &i_o_block; + t_pb io_pb; + // create some sample IO blocks in the clustered netlist + // These will act as fillers to make sure that the find block function correctly handles a netlist with different types of blocks + + // the block names + char io_port_one[] = "io_port_one"; + char io_port_two[] = "io_port_two"; + char io_port_three[] = "io_port_three"; + char io_port_four[] = "io_port_four"; + // add the io blocks to the netlist + block_id_from_name.emplace(io_port_one, test_netlist->create_block(io_port_one, &io_pb, i_o_ref)); + block_id_from_name.emplace(io_port_two, test_netlist->create_block(io_port_two, &io_pb, i_o_ref)); + block_id_from_name.emplace(io_port_three, test_netlist->create_block(io_port_three, &io_pb, i_o_ref)); + block_id_from_name.emplace(io_port_four, test_netlist->create_block(io_port_four, &io_pb, i_o_ref)); + SECTION("Test case where the block is found in the clustered netlist"){ + // create names for some router blocks + char router_one[] = "router:noc_router_one|flit_out_two[0]~reg0"; + char router_two[] = "router:noc_router_two|flit_out_two[0]~reg0"; + char router_three[] = "router:noc_router_three|flit_out_two[0]~reg0"; + char router_four[] = "router:noc_router_four|flit_out_two[0]~reg0"; + // add the router blocks + block_id_from_name.emplace(router_one, test_netlist->create_block(router_one, &router_pb, router_ref)); + block_id_from_name.emplace(router_two, test_netlist->create_block(router_two, &router_pb, router_ref)); + block_id_from_name.emplace(router_three, test_netlist->create_block(router_three, &router_pb, router_ref)); + block_id_from_name.emplace(router_four, test_netlist->create_block(router_four, &router_pb, router_ref)); + + // create additional router blocks + char router_five[] = "router:noc_router_five|flit_out_two[0]~reg0"; + char router_six[] = "router:noc_router_six|flit_out_two[0]~reg0"; + + block_id_from_name.emplace(router_five, test_netlist->create_block(router_five, &router_2_pb, router_ref_2)); + block_id_from_name.emplace(router_six, test_netlist->create_block(router_six, &router_2_pb, router_ref_2)); + + // now find a block just knowing its instance name + std::string test_router_module_name = ".*noc_router_five.*"; + + // now get the cluster id of the block with the test router name using the function we are testing + ClusterBlockId test_router_block_id; + REQUIRE_NOTHROW(test_router_block_id = get_router_module_cluster_id(test_router_module_name, cluster_ctx, test, test_location, noc_router_ref)); + + REQUIRE((size_t)(block_id_from_name.find("router:noc_router_five|flit_out_two[0]~reg0")->second) == (size_t)test_router_block_id); + } + SECTION("Test case where the block is not found in the clustered netlist"){ + // create names for some router blocks + char router_one[] = "router:noc_router_one|flit_out_two[0]~reg0"; + char router_two[] = "router:noc_router_two|flit_out_two[0]~reg0"; + char router_three[] = "router:noc_router_three|flit_out_two[0]~reg0"; + char router_four[] = "router:noc_router_four|flit_out_two[0]~reg0"; + // add the router blocks + block_id_from_name.emplace(router_one, test_netlist->create_block(router_one, &router_pb, router_ref)); + block_id_from_name.emplace(router_two, test_netlist->create_block(router_two, &router_pb, router_ref)); + block_id_from_name.emplace(router_three, test_netlist->create_block(router_three, &router_pb, router_ref)); + block_id_from_name.emplace(router_four, test_netlist->create_block(router_four, &router_pb, router_ref)); + // create additional router blocks + char router_five[] = "router:noc_router_five|flit_out_two[0]~reg0"; + char router_six[] = "router:noc_router_six|flit_out_two[0]~reg0"; + + block_id_from_name.emplace(router_five, test_netlist->create_block(router_five, &router_2_pb, router_ref_2)); + block_id_from_name.emplace(router_six, test_netlist->create_block(router_six, &router_2_pb, router_ref_2)); + + // now find a block just knowing its name. Choosing a block name that doesn't exist + std::string test_router_module_name = "^router:noc_router_seven|flit_out_two[0]~reg0$"; + + // now get the cluster id of the block with the test router name using the function we are testing + // This should fail, so check that it does + REQUIRE_THROWS_WITH(get_router_module_cluster_id(test_router_module_name, cluster_ctx, test, test_location, noc_router_ref), "The router module '^router:noc_router_seven|flit_out_two[0]~reg0$' does not exist in the design."); + } + } + TEST_CASE("test_check_traffic_flow_router_module_type", "[vpr_noc_traffic_flows_parser]"){ + + // filler data for the xml information + // data for the xml parsing + pugi::xml_node test; + pugiutil::loc_data test_location; + + // get the global netlist + ClusteringContext& cluster_ctx = g_vpr_ctx.mutable_clustering(); + ClusteredNetlist* test_netlist = &cluster_ctx.clb_nlist; + + // create a new clustered netlist + *test_netlist = ClusteredNetlist("test_netlist", "77"); + + /* need to create the noc router physical type */ + + t_physical_tile_type noc_router; + + // create a single subtile + t_sub_tile router_tile; + + // there is a single logical type that is compatible with this subtile and it is a router + t_logical_block_type router_block; + char router[] = "router"; + router_block.name = router; + t_logical_block_type_ptr router_ref = &router_block; + t_pb router_pb; + + // add the logical tyes as the equivalent sites of the subtile + router_tile.equivalent_sites.push_back(router_ref); + + // add the subtile to the physical noc router type + noc_router.sub_tiles.push_back(router_tile); + + // create a reference to the physical type + t_physical_tile_type_ptr noc_router_ref = &noc_router; + + /* finished creating noc router physical type */ + + // need to add the physical type to the logical block types equivalent tiles + router_block.equivalent_tiles.push_back(noc_router_ref); + + // creating an IO logical type + t_logical_block_type i_o_block; + char i_o[] = "IO"; + i_o_block.name = i_o; + t_logical_block_type_ptr i_o_ref = &i_o_block; + t_pb io_pb; + + SECTION("Test case where the traffic flow module is of type router"){ + // create a name for a router block + char router_one[] = "router:noc_router_one|flit_out_two[0]~reg0"; + + // create a cluster block that represents a router module + ClusterBlockId router_module_id = test_netlist->create_block(router_one, &router_pb, router_ref); + + // now run the test function to verify that the current router module has a logical type of a router + // the function should not fail since the module is a router + REQUIRE_NOTHROW(check_traffic_flow_router_module_type(router_one, router_module_id, test, test_location, cluster_ctx, noc_router_ref)); + } + SECTION("Test case where the traffic flow module is not of type router"){ + // create a name for a IO block + char io_block_one[] = "io_block_one"; + + // create a cluster blcok that represents a IO block + ClusterBlockId io_module_id = test_netlist->create_block(io_block_one, &io_pb, i_o_ref); + + // now run the test function to verify that the current IO module doesnt have a logical type of a router + // the function should faile since the module is of type IO + REQUIRE_THROWS_WITH(check_traffic_flow_router_module_type(io_block_one, io_module_id, test, test_location, cluster_ctx, noc_router_ref), "The supplied module name 'io_block_one' is not a NoC router."); + } + } } \ No newline at end of file From f4e3ee4447e347c80013d73e3b36156f803c5f6d Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Sun, 12 Jun 2022 22:00:05 -0400 Subject: [PATCH 088/128] changed the check_that_all_router_blocks_have_an_associated_traffic_flow function so that a boolean is returned to indicate the result of the function (in additional to a log message) --- vpr/src/noc/read_xml_noc_traffic_flows_file.cpp | 8 ++++++-- vpr/src/noc/read_xml_noc_traffic_flows_file.h | 5 ++++- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index 4bb9481495f..94c1b539143 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -216,7 +216,9 @@ t_physical_tile_type_ptr get_physical_type_of_noc_router_tile(const DeviceContex } -void check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type, std::string noc_flows_file){ +bool check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type, std::string noc_flows_file){ + + bool result = true; // contains the number of all the noc router blocks in the design const auto clustered_netlist_stats = ClusteredNetlistStats(); @@ -244,8 +246,10 @@ void check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& no if (noc_ctx.noc_traffic_flows_storage.get_number_of_routers_used_in_traffic_flows() != number_of_router_blocks_in_design){ VTR_LOG_WARN("NoC traffic flows file '%s' does not contain all router modules in the design. Every router module in the design must be part of a traffic flow (communicating to another router). Otherwise the router is unused.\n", noc_flows_file.c_str()); + + result = false; } - return; + return result; } \ No newline at end of file diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.h b/vpr/src/noc/read_xml_noc_traffic_flows_file.h index 79c7fcb32eb..5011388adca 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.h +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.h @@ -147,8 +147,11 @@ t_physical_tile_type_ptr get_physical_type_of_noc_router_tile(const DeviceContex * on a NoC router tile. * @param noc_flows_file The name of the '.flows' file. Used when displaying * the error. + * @return bool True implies that all router blocks in the design have an + * associated traffic flow. False means there are some router + * blocks that do not have a an associated traffic flow. */ -void check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type, std::string noc_flows_file); +bool check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type, std::string noc_flows_file); From 76f9f49b5dea096febf4c3218339b4ce0168e1ff Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Sun, 12 Jun 2022 22:01:20 -0400 Subject: [PATCH 089/128] added a unit test to verify the check_that_all_router_blocks_have_an_associated_traffic_flow function --- .../test_read_xml_noc_traffic_flows_file.cpp | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp index a75f88b105d..9c79a7b78b5 100644 --- a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp +++ b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp @@ -3,6 +3,8 @@ #include "read_xml_noc_traffic_flows_file.h" +#include + namespace{ TEST_CASE("test_verify_traffic_flow_router_modules", "[vpr_noc_traffic_flows_parser]"){ @@ -263,4 +265,98 @@ namespace{ REQUIRE_THROWS_WITH(check_traffic_flow_router_module_type(io_block_one, io_module_id, test, test_location, cluster_ctx, noc_router_ref), "The supplied module name 'io_block_one' is not a NoC router."); } } + TEST_CASE("test_check_that_all_router_blocks_have_an_associated_traffic_flow", "[vpr_noc_traffic_flows_parser]"){ + + // get the global netlist + ClusteringContext& cluster_ctx = g_vpr_ctx.mutable_clustering(); + ClusteredNetlist* test_netlist = &cluster_ctx.clb_nlist; + + // create a new clustered netlist + *test_netlist = ClusteredNetlist("test_netlist", "77"); + + // get the global device information + DeviceContext& device_ctx = g_vpr_ctx.mutable_device(); + + // get the global noc information + NocContext& noc_ctx = g_vpr_ctx.mutable_noc(); + // delete any previously created traffic flow info + noc_ctx.noc_traffic_flows_storage.clear_traffic_flows(); + + // create the logical type of a noc router + // there is a single logical type that is compatible with this subtile and it is a router + t_logical_block_type router_block; + char router[] = "router"; + router_block.name = router; + t_logical_block_type_ptr router_ref = &router_block; + t_pb router_pb; + + //set the index of the logical type as 0 (its the only block type in this test device) + router_block.index = 0; + // now add this logical type to the device + device_ctx.logical_block_types.push_back(router_block); + + //need to create the noc router physical type + t_physical_tile_type noc_router; + + // indicate that the noc_router physical tile is not an input/output + noc_router.is_input_type = false; + noc_router.is_output_type = false; + + // create a single subtile + t_sub_tile router_tile; + + // add the logical tyes as the equivalent sites of the subtile + router_tile.equivalent_sites.push_back(router_ref); + + // add the subtile to the physical noc router type + noc_router.sub_tiles.push_back(router_tile); + + // create a reference to the physical type + t_physical_tile_type_ptr noc_router_ref = &noc_router; + // need to add the physical type of the router to the list of physical tiles that match to the router logical block + router_block.equivalent_tiles.push_back(noc_router_ref); + + // define arbritary values for traffic flow bandwidths and latency + double traffic_flow_bandwidth = 0.0; + double traffic_flow_latency = 0.0; + + // start by creating a set of router blocks in the design and add them to the clustered netlist + + // define the test router block names + char router_one[] = "router_block_one"; + char router_two[] = "router_block_two"; + char router_three[] = "router_block_three"; + + ClusterBlockId router_block_one_id = test_netlist->create_block(router_one, &router_pb, router_ref); + ClusterBlockId router_block_two_id = test_netlist->create_block(router_two, &router_pb, router_ref); + ClusterBlockId router_block_three_id = test_netlist->create_block(router_three, &router_pb, router_ref); + + // define the name of the test noc traffic flows file + std::string test_noc_traffic_flows_file_name = "noc_traffic_flows_file.flows"; + + SECTION("Test case when all router blocks in the design have an associated traffic flow"){ + + // create a number of traffic flows that include all router blocks in the design + noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_one, router_two, router_block_one_id, router_block_two_id, traffic_flow_bandwidth, traffic_flow_latency); + + noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_two, router_three, router_block_two_id, router_block_three_id, traffic_flow_bandwidth, traffic_flow_latency); + + noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_three, router_one, router_block_three_id, router_block_one_id, traffic_flow_bandwidth, traffic_flow_latency); + + // now check to see whether all router blocks in the design have an associated traffic flow (this is the function tested here) + // we expect this to pass + CHECK(check_that_all_router_blocks_have_an_associated_traffic_flow(noc_ctx, noc_router_ref, test_noc_traffic_flows_file_name) == true); + } + SECTION("Test case where some router blocks in the design do not have an associated traffic flow"){ + + // create a number of traffic flows that includes router_one and router_twp but does not include router_three + noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_one, router_two, router_block_one_id, router_block_two_id, traffic_flow_bandwidth, traffic_flow_latency); + + noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_two, router_one, router_block_two_id, router_block_one_id, traffic_flow_bandwidth, traffic_flow_latency); + + // now check to see whether all router blocks in the design have an associated traffic flow (this is the function tested here) + // we expect this fail + CHECK(check_that_all_router_blocks_have_an_associated_traffic_flow(noc_ctx, noc_router_ref, test_noc_traffic_flows_file_name) == false); + } + } } \ No newline at end of file From 72926e5dba83ce1a051558f5bb52d84b3c15eef4 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 13 Jun 2022 23:15:20 -0400 Subject: [PATCH 090/128] added a new function to catch duplicate traffic flows (source and sink routers being the same) when parsing the noc traffic flows file. Also added a corresponding unit test to verify the function. --- .../noc/read_xml_noc_traffic_flows_file.cpp | 30 ++++++++++- vpr/src/noc/read_xml_noc_traffic_flows_file.h | 18 +++++++ .../test_read_xml_noc_traffic_flows_file.cpp | 52 +++++++++++++++++++ 3 files changed, 99 insertions(+), 1 deletion(-) diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index 94c1b539143..40f88162cf5 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -74,7 +74,7 @@ void read_xml_noc_traffic_flows_file(const char* noc_flows_file){ void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type){ - // contans all traffic flows + // contains all traffic flows NocTrafficFlows* noc_traffic_flow_storage = &noc_ctx.noc_traffic_flows_storage; // an accepted list of attributes for the single flow tag @@ -106,6 +106,9 @@ void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_dat verify_traffic_flow_properties(traffic_flow_bandwidth, max_traffic_flow_latency, single_flow_tag, loc_data); + // make sure that the current traffic flow was not added previously + check_for_duplicate_traffic_flow(source_router_id, destination_router_id,single_flow_tag, loc_data, *noc_traffic_flow_storage); + // The current flow information is legal, so store it noc_traffic_flow_storage->create_noc_traffic_flow(source_router_module_name, destination_router_module_name, source_router_id, destination_router_id, traffic_flow_bandwidth, max_traffic_flow_latency); @@ -252,4 +255,29 @@ bool check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& no return result; +} + +void check_for_duplicate_traffic_flow(ClusterBlockId source_router_id, ClusterBlockId sink_router_id, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const NocTrafficFlows& noc_traffic_flow_storage){ + + const std::vector* list_of_associated_traffic_flows_to_source_router = noc_traffic_flow_storage.get_traffic_flows_associated_to_source_router(source_router_id); + + /* + Go through all the traffic flows that exist with the current source router and check to see if any of those traffic flows have a sink router + that matches current sink router. When this happens then the two traffic flows are duplicates and an error should be thrown. + */ + for (auto traffic_flow_id = list_of_associated_traffic_flows_to_source_router->begin(); traffic_flow_id != list_of_associated_traffic_flows_to_source_router->end(); traffic_flow_id++){ + + ClusterBlockId curr_sink_router_id = noc_traffic_flow_storage.get_single_noc_traffic_flow(*traffic_flow_id).sink_router_cluster_id; + + // compare the current traffic flows sink router with the new traffic flows sink router + if ((size_t)curr_sink_router_id == (size_t)sink_router_id){ + + // the routers are the same, so this is a duplicate traffic flow. thrown an error + vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "The supplied traffic flow is a duplicate of another traffic flow (contain the same source and sink routers). Duplicate traffic flows are not allowed."); + + } + + } + + return; } \ No newline at end of file diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.h b/vpr/src/noc/read_xml_noc_traffic_flows_file.h index 5011388adca..bb1fe4069fb 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.h +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.h @@ -153,6 +153,24 @@ t_physical_tile_type_ptr get_physical_type_of_noc_router_tile(const DeviceContex */ bool check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type, std::string noc_flows_file); +/** + * @brief Given a traffic flow source and sink router, check to see if there + * already exists another traffic flow with the same source and sink + * routers. If there already exsists a traffic flow with the same routers + * then this is a duplicate and an error is thrown, otherwise no + * duplicate traffic flow exists. + * + * @param source_router_id The cluster block id of the source router in + * the traffic flow to be added. + * @param sink_router_id The cluster block id of the sink router in the + * the traffic flow to be added. + * @param single_flow_tag A xml tag that contains the traffic flow information + * @param loc_data Contains location data about the current line in the xml file + * @param noc_traffic_flow_storage Used to get the previously added traffic + * traffic flow information. + */ +void check_for_duplicate_traffic_flow(ClusterBlockId source_router_id, ClusterBlockId sink_router_id, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const NocTrafficFlows& noc_traffic_flow_storage); + diff --git a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp index 9c79a7b78b5..f9f451b6c16 100644 --- a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp +++ b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp @@ -359,4 +359,56 @@ namespace{ CHECK(check_that_all_router_blocks_have_an_associated_traffic_flow(noc_ctx, noc_router_ref, test_noc_traffic_flows_file_name) == false); } } + TEST_CASE("test_check_for_duplicate_traffic_flow", "[vpr_noc_traffic_flows_parser]"){ + + // filler data for the xml information + // data for the xml parsing + pugi::xml_node test; + pugiutil::loc_data test_location; + + // get the global noc information + NocContext& noc_ctx = g_vpr_ctx.mutable_noc(); + // delete any previously created traffic flow info + noc_ctx.noc_traffic_flows_storage.clear_traffic_flows(); + + // define arbritary values for traffic flow bandwidths and latency + double traffic_flow_bandwidth = 0.0; + double traffic_flow_latency = 0.0; + + SECTION("Test case where there are duplicate traffic flows"){ + + // create some sample clusterblock ids that can be used to generate traffic flows + ClusterBlockId router_block_zero_id(0); + ClusterBlockId router_block_one_id(1); + + // create sample router block names that can be used to create a traffic flow + std::string router_block_zero = "router_block_zero"; + std::string router_block_one = "router_block_one"; + + // now create a traffic flow + noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_block_zero, router_block_one, router_block_zero_id, router_block_one_id, traffic_flow_bandwidth, traffic_flow_latency); + + // now run the test function with the situation where another traffic flow is being added with the exact same source and sink routers as above + // we expect the function to fail and erro to be thrown + REQUIRE_THROWS_WITH(check_for_duplicate_traffic_flow(router_block_zero_id, router_block_one_id, test, test_location, noc_ctx.noc_traffic_flows_storage), "The supplied traffic flow is a duplicate of another traffic flow (contain the same source and sink routers). Duplicate traffic flows are not allowed."); + } + SECTION("Test case where there are no duplicate traffic flows"){ + + // create some sample clusterblock ids that can be used to generate traffic flows + ClusterBlockId router_block_zero_id(0); + ClusterBlockId router_block_one_id(1); + ClusterBlockId router_block_two_id(2); + + // create sample router block names that can be used to create a traffic flow + std::string router_block_zero = "router_block_zero"; + std::string router_block_one = "router_block_one"; + + // now create a traffic flow + noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_block_zero, router_block_one, router_block_zero_id, router_block_one_id, traffic_flow_bandwidth, traffic_flow_latency); + + // now run the test function with the situation where another traffic flow is being added with sink router than what was used above + // we expect the function to pass and no error to be thrown + REQUIRE_NOTHROW(check_for_duplicate_traffic_flow(router_block_zero_id, router_block_two_id, test, test_location, noc_ctx.noc_traffic_flows_storage)); + } + } } \ No newline at end of file From a153da5bac33a8b63bbbd7c7de655bb156f6e2ef Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 17 Jun 2022 00:29:42 -0400 Subject: [PATCH 091/128] Modified comments to doxygen style and improved them --- vpr/src/noc/noc_traffic_flows.cpp | 48 +--- vpr/src/noc/noc_traffic_flows.h | 245 +++++++++++++++--- .../noc/read_xml_noc_traffic_flows_file.cpp | 48 ++-- vpr/src/noc/read_xml_noc_traffic_flows_file.h | 35 +-- 4 files changed, 250 insertions(+), 126 deletions(-) diff --git a/vpr/src/noc/noc_traffic_flows.cpp b/vpr/src/noc/noc_traffic_flows.cpp index 2a68baa4245..986bafc6c7d 100644 --- a/vpr/src/noc/noc_traffic_flows.cpp +++ b/vpr/src/noc/noc_traffic_flows.cpp @@ -1,22 +1,3 @@ -/* - * The NocTrafficFlows contains all the communication - * happening within the NoC. This includes the source - * and destination routers in the communication link, the - * size of the data being tranferred and any constraints - * put on the communication link (ex. maximum latency). All - * this information is stored inside a traffic flow. - * - * The NocTrafficFlows stores a list of all the traffic flows in - * a given design as provided by the user. Additionally it includes - * a number of additional datastructures to quickly retrieve a traffic flow. - * Additionally it provides information about all the routers in the design. - * These include datastructures include: - * - A set of all the routers in the design - * - A list of all traffic flows for every router where the router - * is the source or destination of the traffic flow - * - The processed status of each and every traffic flow - * - */ #include "noc_traffic_flows.h" #include "vpr_error.h" @@ -33,9 +14,6 @@ const t_noc_traffic_flow& NocTrafficFlows::get_single_noc_traffic_flow(NocTraffi return list_of_noc_traffic_flows[traffic_flow_id]; } -/* - Given a router ClusterBlockId, return a list of traffic flows where the provided router is the source router of the traffic flow -*/ const std::vector* NocTrafficFlows::get_traffic_flows_associated_to_source_router(ClusterBlockId source_router_id) const { const std::vector* traffic_flow_list = nullptr; @@ -53,9 +31,6 @@ const std::vector* NocTrafficFlows::get_traffic_flows_associat return traffic_flow_list; } -/* - Given a router ClusterBlockId, return a list of traffic flows where the provided router is the sink router of the traffic flow -*/ const std::vector* NocTrafficFlows::get_traffic_flows_associated_to_sink_router(ClusterBlockId source_router_id) const { const std::vector* traffic_flow_list = nullptr; @@ -78,9 +53,6 @@ bool NocTrafficFlows::get_traffic_flow_processed_status(NocTrafficFlowId traffic return processed_traffic_flows[traffic_flow_id]; } -/* - Determines the number of unique router blocks that were used as a source or sink router in all traffic flows. -*/ int NocTrafficFlows::get_number_of_routers_used_in_traffic_flows(void){ return noc_router_blocks.size(); @@ -88,11 +60,6 @@ int NocTrafficFlows::get_number_of_routers_used_in_traffic_flows(void){ // setters for the traffic flows -/* - Given all the information for a given traffic flow, create it - and add it to all the internal datastructures. Then add the two routers - in the newly created flow to the set of all routers in the design. -*/ void NocTrafficFlows::create_noc_traffic_flow(std::string source_router_module_name, std::string sink_router_module_name, ClusterBlockId source_router_cluster_id, ClusterBlockId sink_router_cluster_id, double traffic_flow_bandwidth, double traffic_flow_latency){ // create and add the new traffic flow to the list @@ -125,7 +92,6 @@ void NocTrafficFlows::set_traffic_flow_status(NocTrafficFlowId traffic_flow_id, // utility functions for the noc traffic flows -//Create the list that stores the status of all traffic flows void NocTrafficFlows::finshed_noc_traffic_flows_setup(void){ // get the total number of traffic flows and create a vectorof the same size to hold the "processed status" of each traffic flow @@ -136,7 +102,6 @@ void NocTrafficFlows::finshed_noc_traffic_flows_setup(void){ return; } -// set the status of all the traffic flows as not processed void NocTrafficFlows::reset_traffic_flows_processed_status(void){ for (auto traffic_flow = processed_traffic_flows.begin(); traffic_flow != processed_traffic_flows.end(); traffic_flow++){ @@ -146,7 +111,7 @@ void NocTrafficFlows::reset_traffic_flows_processed_status(void){ return; } -// clear all the internal datastructures + void NocTrafficFlows::clear_traffic_flows(void){ // delete any information from internal datastructures @@ -159,7 +124,6 @@ void NocTrafficFlows::clear_traffic_flows(void){ return; } -// given a ClusterBlockId, determine whether it is a router block or not bool NocTrafficFlows::check_if_cluster_block_is_a_noc_router(ClusterBlockId block_id){ auto router_block = noc_router_blocks.find(block_id); @@ -174,18 +138,15 @@ bool NocTrafficFlows::check_if_cluster_block_is_a_noc_router(ClusterBlockId bloc // private functions used internally -/* - Given a router, add the current traffic flow to the list of traffic flows for the current router where it is a source or destination of the given flow -*/ -void NocTrafficFlows::add_traffic_flow_to_associated_routers(NocTrafficFlowId traffic_flow_id, ClusterBlockId router_id, std::unordered_map>& router_associated_traffic_flows){ +void NocTrafficFlows::add_traffic_flow_to_associated_routers(NocTrafficFlowId traffic_flow_id, ClusterBlockId associated_router_id, std::unordered_map>& router_associated_traffic_flows){ // get a reference to the list of traffic flows associated with the current router - auto router_traffic_flows = router_associated_traffic_flows.find(router_id); + auto router_traffic_flows = router_associated_traffic_flows.find(associated_router_id); // check if a list exists if (router_traffic_flows == router_associated_traffic_flows.end()){ // there exists no list of traffic flows for this router, so we add it with the newly created traffic flow id - router_associated_traffic_flows.insert(std::pair>(router_id, {traffic_flow_id})); + router_associated_traffic_flows.insert(std::pair>(associated_router_id, {traffic_flow_id})); } else{ // there already is a list of traffic flows for the current router, so add it to the list @@ -197,7 +158,6 @@ void NocTrafficFlows::add_traffic_flow_to_associated_routers(NocTrafficFlowId tr } -// adds a router to the list of all router blocks in the design void NocTrafficFlows::add_router_to_block_set(ClusterBlockId router_block_id){ noc_router_blocks.insert(router_block_id); diff --git a/vpr/src/noc/noc_traffic_flows.h b/vpr/src/noc/noc_traffic_flows.h index e6b39ded2b9..62fb78e8c16 100644 --- a/vpr/src/noc/noc_traffic_flows.h +++ b/vpr/src/noc/noc_traffic_flows.h @@ -1,17 +1,32 @@ #ifndef NOC_TRAFFIC_FLOWS_H #define NOC_TRAFFIC_FLOWS_H -/* - * The NocTrafficFlows class description header file. - * - * The NocTrafficFlows class contains all the communication within the NoC. So - * this includes the source and destination routers involved in the - * communication link and its properties (size and constraints on the link). - * We call this infor mation a traffic flow. +/** + * @file + * @brief This file defines the NocTrafficFlows class, which contains all + * communication betwee routers in the NoC. + * + * Overview + * ======== + * The NocTrafficFlows class contains a list of t_noc_traffic_flow in a given + * design. Each traffic flow is indexed by a unique id that can be used to + * retrieve information about them. + * + * The class also associates traffic flows to their source routers (start point) + * and sink routers (end point). This is useful if one wants to find traffic + * flows based on just the source or sink router. + * + * The routes for the traffic flows are expected to change throughout placement + * as routers will be moved throughout the chip. Therefore this class provides + * a datastructure to keep track of which flows have been updated (re-routed). + * + * Finally, this class also stores a list of all router blocks in the design. + * + * This class will be primarily used during + * placement to identify which routers inside the NoC(NocStorage) need to + * routed to each other.This is important since the router modules can be moved + * around to different tiles on the FPGA device. * - * In addition, the NoCTrafficFlows class includes additional variables and - * functions to quickly access the traffic flows. - * */ #include "clustered_netlist_fwd.h" @@ -31,32 +46,29 @@ constexpr bool PROCESSED = true; constexpr bool NOT_PROCESSED = false; -/* - Describes a traffic flow within the NoC, which is the communication between two routers. This description includes the following: - - The module names of the source and destination routers that are communicating with each other. The module name is the name used when instantiating a router module in the HDL design. - - The atom IDs of the router modules. By storing this, we can quickly lookup the router modules instead of identifying them by using their names. - - The bandwidth(size) of data being transferred between the two routers. - - The maximum allowable latency of the data transfer. - - This datastructure will be primarily used during placement to identify which routers inside the NoC(NocStorage) need to be routed to each other.This is important since the router modules can be moved around to different tiles on the FPGA device. Additionaly, once a the routing has been completed, the bandwidht and latency parameters can be used to calculate the cost of the placement of routers. -*/ +/** + * @brief Describes a traffic flow within the NoC, which is the communication + * between two routers. THe NocTrafficFlows contains a number of this structure + * to describe all the communication happening within the NoC. + * + */ struct t_noc_traffic_flow { - // router module names + /** stores the names of the router blocks communicating within this traffic flow*/ std::string source_router_module_name; std::string sink_router_module_name; - // router module atom ids + /** stores the block id of the two routers blocks communicating within this traffic flow. This can be used to retrieve the block information from the clustered netlist*/ ClusterBlockId source_router_cluster_id; ClusterBlockId sink_router_cluster_id; - // in bytes/s + /** The bandwidth of the information transferred between the two routers. Units in bps. This parameters will be used to update the link usage in the noc model after routing the traffic flow.*/ double traffic_flow_bandwidth; - // in seconds + /** The maximum allowable time to transmit data between thw two routers. This parameter will be used to evaluate a router traffic flow.*/ double max_traffic_flow_latency; - // constructor + /** Constructor initializes all variables*/ t_noc_traffic_flow(std::string source_router_name, std::string sink_router_name, ClusterBlockId source_router_id, ClusterBlockId sink_router_id, double flow_bandwidth, double max_flow_latency) : source_router_module_name(source_router_name), sink_router_module_name(sink_router_name), source_router_cluster_id(source_router_id), sink_router_cluster_id(sink_router_id), traffic_flow_bandwidth(flow_bandwidth), max_traffic_flow_latency(max_flow_latency) {} @@ -66,31 +78,66 @@ class NocTrafficFlows { private: - // contains all the traffic flows provided by the user and their information + /** contains all the traffic flows provided by the user and their information*/ vtr::vector list_of_noc_traffic_flows; - /* + /** A traffic flow has a source and destination router associated to it. So when either the source or destination router for a given flow is moved, we need to find a new route between them. Therefore, during placement if two router blocks are swapped, then the only traffic flows we need to re-route are the flows where the two routers are either the source or destination routers of those flows. - The datastructures below store a list of traffic flows for each router then its a source router for the traffic flow. Similarily, there is a another datastructure for where a list of traffic flows are stored for each router where its a source router for the traffic flow. The routers are indexed by their ClusterBlockId. + The datastructures below store a list of traffic flows for each router when the router is a source for the traffic flow. Similarily, there is a another datastructure where a list of traffic flows are stored for each router where the router is a sink for the traffic flow. The routers are indexed by their ClusterBlockId. - This is done so that the traffic that need to be re-routed during placement are quickly found. + This is done so that the traffic that need to be re-routed during placement can be quickly found. */ std::unordered_map> source_router_associated_traffic_flows; std::unordered_map> sink_router_associated_traffic_flows; - // keeps track of which traffic flows have already been processed + /** keeps track of which traffic flows have already been processed. + * By processed, it tracks whether a traffic flow has been routed or + * not. During placement, two routers can be swapped, if the + * two routers share a traffic flow, then the shared traffic flow + * will be routed twice, where it will routed when processing the + * flows associated to the source router and then again when + * processing the flows associated to the sink router. By using the + * datastructure below, if whether a traffic flow is processed or not + * is tracked, then we can ensure that no traffic flows are routed + * more than once by referring to this datastructure. + */ vtr::vector processed_traffic_flows; - // contains the cluster ID of all unique router modules in the design - // can quikly determine whether a given cluster is a router module or not + /** contains the cluster ID of all unique router modules in the design. + * and can quickly determine whether a given cluster in the netlist + * is a router block or not. whenever placement swaps two clusters, we + * need to check if the clusters a router blocks or not, this is needed + * so that we can deterimine if we need to re-route traffic flows. The + * datastructure below can be used to quickly identify whether a given + * cluster that was swapped furing palcement is a router block or not.*/ std::unordered_set noc_router_blocks; - // shouldnt have access to these functions - void add_traffic_flow_to_associated_routers(NocTrafficFlowId traffic_flow_id, ClusterBlockId source_router_id, std::unordered_map>& router_associated_traffic_flows); - + // private functions + + /** + * @brief Given a router that is either a source or sink of + * a traffic flow, the corresponding traffic flow is added + * to a list of traffic flows associated to the router. + * + * @param traffic_flow_id A unique id that represents a traffic flow. + * @param associated_router_id A ClusterblockId that represents a + * router block. + * @param router_associated_traffic_flows A datastructure that stores + * a list of traffic flows for a given router block where the traffic + * flows have the router as a source or sink within the flow. + * + */ + void add_traffic_flow_to_associated_routers(NocTrafficFlowId traffic_flow_id, ClusterBlockId associated_router_id, std::unordered_map>& router_associated_traffic_flows); + + /** + * @brief Given a router block in the clustered netlist, store it + * internally. + * + * @param router_block_id A unique identifier that rerpesents a router block in the clustered netlist. This id will be stored. + */ void add_router_to_block_set(ClusterBlockId router_block_id); @@ -98,26 +145,152 @@ class NocTrafficFlows NocTrafficFlows(); //getters + + /** + * @brief Given a unique id of a traffic flow (t_noc_traffic_flow) + * retrieve it from the list of all traffic flows in the design. The + * retrieved traffic flow cannot be modified but can be used to + * retireve information such as the routers involved. + * + * @param traffic_flow_id The unique identifier (NocTrafficFlowId) + * of the traffic flow to retrieve. + * @return const t_noc_traffic_flow& The traffic flow represented by + * the provided identifier. + */ const t_noc_traffic_flow& get_single_noc_traffic_flow(NocTrafficFlowId traffic_flow_id) const; + /** + * @brief Get a list of all traffic flows that have a given router + * block in the clustered netlist as the source (starting point) in the + * flow. + * + * @param source_router_id A unique identifier that represents the + * a router block in the clustered netlist. This router block will + * be the source router in the retrieved traffic flow. + * @return const std::vector* A list of traffic flows + * that have the input router block parameter as the source in the + * flow. + */ const std::vector* get_traffic_flows_associated_to_source_router(ClusterBlockId source_router_id) const; - + + /** + * @brief Get a list of all traffic flows that have a given router + * block in the clustered netlist as the sink (end point) in the + * flow. + * + * @param sink_router_id A unique identifier that represents the + * a router block in the clustered netlist. This router block will + * be the sink router in the retrieved traffic flow. + * @return const std::vector* A list of traffic flows + * that have the input router block parameter as the sink in the flow. + */ const std::vector* get_traffic_flows_associated_to_sink_router(ClusterBlockId sink_router_id) const; + /** + * @brief Given a traffic flow, determine whether it has been processed + * or not. By processed, it checks to see whether the traffic flow has + * been routed. This function should be used before routing a traffic + * flow. + * + * @param traffic_flow_id A unique identifier that represents a traffic + * flow + * @return true Represents the case where the traffic flow has been + * processed + * @return false Represents the case where the traffic flow has not + * been processed + */ bool get_traffic_flow_processed_status(NocTrafficFlowId traffic_flow_id); + /** + * @brief Gets the number of unique router blocks in the + * clustered netlist that were used within the user provided + * traffic flows description. + * + * @return int The total number of unique routers used in + * the traffic flows provided by the user. + */ int get_number_of_routers_used_in_traffic_flows(void); // setters - void create_noc_traffic_flow(std::string source_router_module_name, std::string sink_router_module_name, ClusterBlockId source_router_cluster_id, ClusterBlockId sink_router_cluster_id, double traffic_flow_bandwidth, double traffic_flow_latency); + /** + * @brief Given a set of parameters that describe a traffic + * flow, create it an add it to the list of traffic flows in the + * design. Additionally, the two router blocks involved have their + * ids stored to to keep track of all router blocks that are used + * in traffic flows. Finally, the newly created traffic flow is + * added to a list of traffic flows associated to both the + * source and sink routers of the flow. + * + * @param source_router_module_name A string that represents the + * name of the source router block in the traffic flow. THis is + * provided by the user. + * @param sink_router_module_name A string that represents the name + * of the sink router block in the traffic flow. This is provided by + * the user. + * @param source_router_cluster_id The source router block id that + * uniquely identifies this block in the clustered netlist. + * @param sink_router_cluster_id The sink router block id that + * uniquely identifier this block in the clusterd netlist. + * @param traffic_flow_bandwidth The size of the data transmission + * in this traffic flow (units of bps). + * @param traffic_flow_latency The maximum allowable delay between + * transmitting data at the source router and having it received + * at the sink router. + */ + void create_noc_traffic_flow(std::string source_router_module_name, std::string sink_router_module_name, ClusterBlockId source_router_cluster_id, ClusterBlockId sink_router_cluster_id, double traffic_flow_bandwidth, double traffic_flow_latency); + + /** + * @brief Set the status of a given traffic flow. The status indicates + * whether the traffic flow has been routed or not. + * + * @param traffic_flow_id A unique identifier that represents a traffic + * flow. + * @param status THe updated status of the traffic flow. True indicating + * that the traffic flow has been router and False indicating that + * the traffic flow has not been routed. + */ void set_traffic_flow_status(NocTrafficFlowId traffic_flow_id, bool status); //utility functions + + /** + * @brief Determines the total number of traffic flows in + * the design and creates a list to keep track of the traffic + * flows processed status. This function should be called after + * all the traffic flows have been created. The traffic flows are + * all initialized to being not processed. + * + */ void finshed_noc_traffic_flows_setup(void); + + /** + * @brief Goes through the status of all traffic flows + * and sets them to being not processed. This should be + * used before each iteraition of placement. + * + */ void reset_traffic_flows_processed_status(void); + + /** + * @brief Resets the class by clearning internal + * satastructures. + * + */ void clear_traffic_flows(void); + + /** + * @brief Given a block from the clustered netlist, determine + * if the block is a router. This function should be used during + * each iteration of placement to check whether two swapped clusters + * are routers or not. + * + * @param block_id A unique identifier that represents a cluster + * block in the clustered netlist + * @return true The block is a router + * @return false THe block is not a router + */ bool check_if_cluster_block_is_a_noc_router(ClusterBlockId block_id); }; diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index 40f88162cf5..f6fd798b716 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -1,18 +1,4 @@ -/** - * The purpose of this file is to read and parse an xml file that has then - * a '.flows' extension. THis file contains the description of a number of - * traffic flows within the NoC. A traffic flow describes the communication - * between two routers in the NoC. - * - * All the processed traffic flows are stored inside the NocTrafficFlows class - * for future use. - * - * 'read_xml_noc_traffic_flows_file' is the main function that performs all the - * tasks listed above and should be used externally to process the traffic - * flows file. This file also contains a number of internal helper - * functions that assist in parsing the traffic flows file. - * - */ + #include "read_xml_noc_traffic_flows_file.h" @@ -86,18 +72,18 @@ void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_dat // store the names of the routers part of this traffic flow std::string source_router_module_name = pugiutil::get_attribute(single_flow_tag, "src", loc_data, pugiutil::REQUIRED).value(); - std::string destination_router_module_name = pugiutil::get_attribute(single_flow_tag, "dst", loc_data, pugiutil::REQUIRED).value(); + std::string sink_router_module_name = pugiutil::get_attribute(single_flow_tag, "dst", loc_data, pugiutil::REQUIRED).value(); //verify whether the router module names are legal - verify_traffic_flow_router_modules(source_router_module_name, destination_router_module_name, single_flow_tag, loc_data); + verify_traffic_flow_router_modules(source_router_module_name, sink_router_module_name, single_flow_tag, loc_data); // assign the unique block ids of the two router modules after clustering ClusterBlockId source_router_id = get_router_module_cluster_id(source_router_module_name, cluster_ctx, single_flow_tag, loc_data, noc_router_tile_type); - ClusterBlockId destination_router_id = get_router_module_cluster_id(destination_router_module_name, cluster_ctx, single_flow_tag, loc_data, noc_router_tile_type); + ClusterBlockId sink_router_id = get_router_module_cluster_id(sink_router_module_name, cluster_ctx, single_flow_tag, loc_data, noc_router_tile_type); - // verify that the source and destination modules are actually noc routers + // verify that the source and sink modules are actually noc routers check_traffic_flow_router_module_type(source_router_module_name, source_router_id, single_flow_tag, loc_data, cluster_ctx, noc_router_tile_type); - check_traffic_flow_router_module_type(destination_router_module_name, destination_router_id, single_flow_tag, loc_data, cluster_ctx, noc_router_tile_type); + check_traffic_flow_router_module_type(sink_router_module_name, sink_router_id, single_flow_tag, loc_data, cluster_ctx, noc_router_tile_type); // store the properties of the traffic flow double traffic_flow_bandwidth = pugiutil::get_attribute(single_flow_tag, "bandwidth", loc_data, pugiutil::REQUIRED).as_double(NUMERICAL_ATTRIBUTE_CONVERSION_FAILURE); @@ -107,26 +93,26 @@ void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_dat verify_traffic_flow_properties(traffic_flow_bandwidth, max_traffic_flow_latency, single_flow_tag, loc_data); // make sure that the current traffic flow was not added previously - check_for_duplicate_traffic_flow(source_router_id, destination_router_id,single_flow_tag, loc_data, *noc_traffic_flow_storage); + check_for_duplicate_traffic_flow(source_router_id, sink_router_id,single_flow_tag, loc_data, *noc_traffic_flow_storage); // The current flow information is legal, so store it - noc_traffic_flow_storage->create_noc_traffic_flow(source_router_module_name, destination_router_module_name, source_router_id, destination_router_id, traffic_flow_bandwidth, max_traffic_flow_latency); + noc_traffic_flow_storage->create_noc_traffic_flow(source_router_module_name, sink_router_module_name, source_router_id, sink_router_id, traffic_flow_bandwidth, max_traffic_flow_latency); return; } -void verify_traffic_flow_router_modules(std::string source_router_name, std::string destination_router_name, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data){ +void verify_traffic_flow_router_modules(std::string source_router_name, std::string sink_router_name, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data){ // check that the router module names were legal - if ((source_router_name.compare("") == 0) || (destination_router_name.compare("") == 0)){ + if ((source_router_name.compare("") == 0) || (sink_router_name.compare("") == 0)){ - vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "Invalid names for the source and destination NoC router modules."); - }// check if the source and destination routers have the same name - else if (source_router_name.compare(destination_router_name) == 0) + vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "Invalid names for the source and sink NoC router modules."); + }// check if the source and sink routers have the same name + else if (source_router_name.compare(sink_router_name) == 0) { - // Cannot have the source and destination routers have the same name (they need to be different). A flow cant go to a single router. - vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "Source and destination NoC routers cannot be the same modules."); + // Cannot have the source and sink routers have the same name (they need to be different). A flow cant go to a single router. + vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "Source and sink NoC routers cannot be the same modules."); } return; @@ -197,7 +183,9 @@ void check_traffic_flow_router_module_type(std::string router_module_name, Clust t_logical_block_type_ptr router_module_logical_type = cluster_ctx.clb_nlist.block_type(router_module_id); /* - Check the current router modules logical type is compatible with the physical type if a noc router (can the module be placed on a noc router tile on the FPGA device). If not then this module is not a router so throw an error. + Check whether the current router modules logical type is compatible + with the physical type of a noc router (can the module be placed on a + noc router tile on the FPGA device). If not then this module is not a router so throw an error. */ if (!is_tile_compatible(noc_router_tile_type, router_module_logical_type)){ diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.h b/vpr/src/noc/read_xml_noc_traffic_flows_file.h index bb1fe4069fb..9e4e6888d6f 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.h +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.h @@ -1,6 +1,22 @@ #ifndef READ_XML_NOC_TRAFFIC_FLOWS_FILE_H #define READ_XML_NOC_TRAFFIC_FLOWS_FILE_H +/** + * @brief The purpose of this file is to read and parse an xml file that has + * then a '.flows' extension. THis file contains the description of + * a number of traffic flows within the NoC. A traffic flow describes + * the communication between two routers in the NoC. + * + * All the processed traffic flows are stored inside the + * NocTrafficFlows class for future use. + * + * 'read_xml_noc_traffic_flows_file' is the main function that performs + * all the tasks listed above and should be used externally to process + * the traffic flows file. This file also contains a number of internal + * helper functions that assist in parsing the traffic flows file. + * + */ + #include "pugixml.hpp" #include "pugixml_util.hpp" #include "read_xml_util.h" @@ -60,12 +76,12 @@ void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_dat * cannot communicate with itself. * * @param source_router_name A string value of the source router module name - * @param destination_router_name A string value of the destination router + * @param sink_router_name A string value of the sink router * module name * @param single_flow_tag A xml tag that contains the traffic flow information * @param loc_data Contains location data about the current line in the xml file */ -void verify_traffic_flow_router_modules(std::string source_router_name, std::string destination_router_name, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data); +void verify_traffic_flow_router_modules(std::string source_router_name, std::string sink_router_name, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data); /** * @brief Ensures that the a given traffic flows data transmission size and @@ -136,7 +152,7 @@ t_physical_tile_type_ptr get_physical_type_of_noc_router_tile(const DeviceContex * @brief Verify that every router module in the design has an associated * traffic flow to it. If a router module was instantiated in a design * then it should be part of a traffic flow as either a source or - * destination router. If the module is not then we need to throw an + * sink router. If the module is not then we need to throw an * error. * * @param noc_ctx Contains the NoC information. Used to get the total number @@ -172,17 +188,4 @@ bool check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& no void check_for_duplicate_traffic_flow(ClusterBlockId source_router_id, ClusterBlockId sink_router_id, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const NocTrafficFlows& noc_traffic_flow_storage); - - - - - - - - - - - - - #endif \ No newline at end of file From 1f3a951773c1c533ccc34052f4dee3a4f4adf1fd Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 27 Jun 2022 22:15:39 -0400 Subject: [PATCH 092/128] fixed issues that arose during the merge. Redeclaration of functions in draw.h and draw.cpp that have been moved to other files and also re-adding the noc_traffic_flow_parser option in the command line which was not added during the merge. --- vpr/src/base/read_options.cpp | 3 --- vpr/src/draw/draw.cpp | 13 ------------- vpr/src/draw/draw.h | 31 ------------------------------- 3 files changed, 47 deletions(-) diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index c4f11ef46c7..2634bea2eb9 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -2621,8 +2621,6 @@ argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& arg "This should be on only when the FPGA device contains a NoC and the provided netlist connects to the NoC.") .default_value("off") .show_in(argparse::ShowIn::HELP_ONLY); -<<<<<<< HEAD -======= noc_grp.add_argument(args.noc_flows_file, "--noc_flows_file") .help( @@ -2630,7 +2628,6 @@ argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& arg "This is required if the --noc option is turned on.") .default_value("") .show_in(argparse::ShowIn::HELP_ONLY); ->>>>>>> noc_traffic_flows_parser return parser; } diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp index 19e030d318f..6c7f4b0036d 100644 --- a/vpr/src/draw/draw.cpp +++ b/vpr/src/draw/draw.cpp @@ -127,15 +127,6 @@ static void set_block_text(GtkWidget* widget, gint /*response_id*/, gpointer /*d static void clip_routing_util(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); static void run_graphics_commands(std::string commands); -// draw_noc helper functions -static ezgl::rectangle get_noc_connection_marker_bbox(const t_logical_block_type_ptr noc_router_logical_block_type); - -static void draw_noc_connection_marker(ezgl::renderer* g, const vtr::vector& router_list, ezgl::rectangle connection_marker_bbox); - -static void draw_noc_links(ezgl::renderer* g, const t_logical_block_type_ptr noc_router_logical_block_type, vtr::vector& noc_link_colors, ezgl::rectangle noc_connection_marker_bbox, const vtr::vector& list_of_noc_link_shift_directions); - -static void draw_noc_usage(vtr::vector& noc_link_colors); - /************************** File Scope Variables ****************************/ //The arrow head position for turning/straight-thru connections in a switch box @@ -143,10 +134,6 @@ constexpr float SB_EDGE_TURN_ARROW_POSITION = 0.2; constexpr float SB_EDGE_STRAIGHT_ARROW_POSITION = 0.95; constexpr float EMPTY_BLOCK_LIGHTEN_FACTOR = 0.20; -// defines the area of the marker that represents connection points between links -// area is equivalent to the %x of the area of the router -constexpr float SIZE_OF_NOC_MARKER = 0.30; - //Kelly's maximum contrast colors are selected to be easily distinguishable as described in: // Kenneth Kelly, "Twenty-Two Colors of Maximum Contrast", Color Eng. 3(6), 1943 //We use these to highlight a relatively small number of things (e.g. stages in a critical path, diff --git a/vpr/src/draw/draw.h b/vpr/src/draw/draw.h index a378db7eb2a..14bd255c7fd 100644 --- a/vpr/src/draw/draw.h +++ b/vpr/src/draw/draw.h @@ -62,7 +62,6 @@ ezgl::point2d tnode_draw_coord(tatum::NodeId node); /* Converts a vtr Color to a ezgl Color. */ ezgl::color to_ezgl_color(vtr::Color color); -<<<<<<< HEAD /* This helper function determines whether a net has been highlighted. The highlighting * could be caused by the user clicking on a routing resource, toggled, or * fan-in/fan-out of a highlighted node. */ @@ -78,36 +77,6 @@ std::vector trace_routed_connection_rr_nodes( bool trace_routed_connection_rr_nodes_recurr(const t_rt_node* rt_node, int sink_rr_node, std::vector& rr_nodes_on_path); -======= -void draw_screen(); - -// search bar related functions -ezgl::rectangle draw_get_rr_chan_bbox(int inode); -void draw_highlight_blocks_color(t_logical_block_type_ptr type, ClusterBlockId blk_id); -void highlight_nets(char* message, int hit_node); -void draw_highlight_fan_in_fan_out(const std::set& nodes); -std::set draw_expand_non_configurable_rr_nodes(int hit_node); -void deselect_all(); - -// toggle functions -void toggle_nets(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); -void toggle_rr(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); -void toggle_congestion(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); -void toggle_routing_congestion_cost(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); -void toggle_routing_bounding_box(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); -void toggle_routing_util(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); -void toggle_crit_path(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); -void toggle_block_pin_util(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); -void toggle_router_expansion_costs(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); -void toggle_placement_macros(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); -void toggle_noc_display(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); -void net_max_fanout(GtkWidget* /*widget*/, gint /*response_id*/, gpointer /*data*/); -void set_net_alpha_value(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); -void set_net_alpha_value_with_enter(GtkWidget* widget, gint /*response_id*/, gpointer /*data*/); -float get_net_alpha(); - -ezgl::color get_block_type_color(t_physical_tile_type_ptr type); ->>>>>>> noc_traffic_flows_parser /* This routine highlights the blocks affected in the latest move * * It highlights the old and new locations of the moved blocks * From 3ad61120e169cc10b8878adf7eab0e1c8c6352f6 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 27 Jun 2022 22:28:36 -0400 Subject: [PATCH 093/128] added comments to help explain the need for error checking for command line argument dependencies --- vpr/src/base/read_options.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index 2634bea2eb9..e8ae4a8ef74 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -2833,6 +2833,15 @@ bool verify_args(const t_options& args) { args.router_lookahead_type.argument_name().c_str()); } + /** + * @brief If the user provided the "--noc" command line option, then there + * must be a NoC in the FPGA and the netlist must include NoC routers. + * Therefore, the user must also provide a noc traffic flows file to + * describe the communication within the NoC. We ensure that a noc traffic + * flows file is provided when the "--noc" option is used. If it is not + * provided, we throw an error. + * + */ if (args.noc.provenance() == Provenance::SPECIFIED && args.noc_flows_file.provenance() != Provenance::SPECIFIED) { VPR_FATAL_ERROR(VPR_ERROR_OTHER, "--noc_flows_file option must be specified if --noc is turned on.\n"); From caee85f61f376eedd79559c98283685b5124b95e Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 29 Jun 2022 02:31:36 -0400 Subject: [PATCH 094/128] added an echo function to dump out all the internal datastructure information for the NocTrafficFlows class --- vpr/src/noc/noc_traffic_flows.cpp | 98 +++++++++++++++++++++++++++++++ vpr/src/noc/noc_traffic_flows.h | 18 ++++-- 2 files changed, 112 insertions(+), 4 deletions(-) diff --git a/vpr/src/noc/noc_traffic_flows.cpp b/vpr/src/noc/noc_traffic_flows.cpp index 986bafc6c7d..0fa6cfd4f75 100644 --- a/vpr/src/noc/noc_traffic_flows.cpp +++ b/vpr/src/noc/noc_traffic_flows.cpp @@ -163,4 +163,102 @@ void NocTrafficFlows::add_router_to_block_set(ClusterBlockId router_block_id){ noc_router_blocks.insert(router_block_id); return; +} + +void NocTrafficFlows::echo_noc_traffic_flows(char* file_name){ + FILE* fp; + fp = vtr::fopen(file_name, "w"); + + // file header + fprintf(fp, "--------------------------------------------------------------\n"); + fprintf(fp, "NoC Traffic Flows\n"); + fprintf(fp, "--------------------------------------------------------------\n"); + fprintf(fp, "\n"); + + // print all the routers and their properties + fprintf(fp, "List of NoC Traffic Flows:\n"); + fprintf(fp, "--------------------------------------------------------------\n"); + fprintf(fp, "\n"); + + int traffic_flow_id = 0; + + // go through each traffic flow and print its information + for(auto traffic_flow = list_of_noc_traffic_flows.begin(); traffic_flow != list_of_noc_traffic_flows.end(); traffic_flow++){ + + // print the current traffic flows data + fprintf(fp, "Traffic flow ID: %d\n", traffic_flow_id); + fprintf(fp, "Traffic flow source router block name: %s\n", traffic_flow->source_router_module_name.c_str()); + fprintf(fp, "Traffic flow source router block cluster ID: %lu\n", (size_t)traffic_flow->source_router_cluster_id); + fprintf(fp, "Traffic flow sink router block name: %s\n", traffic_flow->sink_router_module_name.c_str()); + fprintf(fp, "Traffic flow sink router block cluster ID: %lu\n", (size_t)traffic_flow->sink_router_cluster_id); + fprintf(fp, "Traffic flow bandwidth: %f bps\n", traffic_flow->traffic_flow_bandwidth); + fprintf(fp, "Traffic flow latency: %f seconds\n", traffic_flow->max_traffic_flow_latency); + + // seperate the next link information + fprintf(fp, "\n"); + } + + // now print the associated traffic flow information for router cluster blocks that act as source routers in traffic flows + fprintf(fp, "List of traffic flows where the router block cluster is a source router:\n"); + fprintf(fp, "--------------------------------------------------------------\n"); + fprintf(fp, "\n"); + + // go through each router block cluster and print its associated traffic flows where the cluster is a source router for those traffic flows + // we only print out the traffic flow ids + for (auto it = source_router_associated_traffic_flows.begin(); it != source_router_associated_traffic_flows.end(); it++){ + + // print the current router cluster id + fprintf(fp, "Cluster ID %lu: ", (size_t)it->first); + + // get the vector of associated traffic flows + auto assoc_traffic_flows = &(it->second); + + // now go through the traffic flows this router is a source router and add it + for (auto traffic_flow = assoc_traffic_flows->begin(); traffic_flow != assoc_traffic_flows->end(); traffic_flow++){ + + fprintf(fp, "%lu ", (size_t)*traffic_flow); + } + + // seperate the next cluster information + fprintf(fp, "\n\n"); + } + + // now print the associated traffic flow information for router cluster blocks that act as source routers in traffic flows + fprintf(fp, "List of traffic flows where the router block cluster is a sink router:\n"); + fprintf(fp, "--------------------------------------------------------------\n"); + fprintf(fp, "\n"); + + // go through each router block cluster and print its associated traffic flows where the cluster is a sink router for those traffic flows + // we only print out the traffic flow ids + for (auto it = sink_router_associated_traffic_flows.begin(); it != sink_router_associated_traffic_flows.end(); it++){ + + // print the current router cluster id + fprintf(fp, "Router block cluster ID %lu: ", (size_t)it->first); + + // get the vector of associated traffic flows + auto assoc_traffic_flows = &(it->second); + + // now go through the traffic flows this router is a sink router and add it + for (auto traffic_flow = assoc_traffic_flows->begin(); traffic_flow != assoc_traffic_flows->end(); traffic_flow++){ + + fprintf(fp, "%lu ", (size_t)*traffic_flow); + } + + // seperate the next cluster information + fprintf(fp, "\n\n"); + } + + // now print all the unique router block cluster ids in the netlist + fprintf(fp, "List of all router block cluster IDs in the netlist:\n"); + fprintf(fp, "--------------------------------------------------------------\n"); + fprintf(fp, "\n"); + + // print all the unique router block cluster ids + for (auto single_router_block = noc_router_blocks.begin(); single_router_block != noc_router_blocks.end(); single_router_block++){ + + fprintf(fp, "Router cluster block ID: %lu\n", (size_t)*single_router_block); + } + + return; + } \ 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 62fb78e8c16..d1051467f24 100644 --- a/vpr/src/noc/noc_traffic_flows.h +++ b/vpr/src/noc/noc_traffic_flows.h @@ -28,14 +28,15 @@ * around to different tiles on the FPGA device. * */ - -#include "clustered_netlist_fwd.h" -#include "noc_data_types.h" -#include "vtr_vector.h" #include #include #include #include +#include "clustered_netlist_fwd.h" +#include "noc_data_types.h" +#include "vtr_vector.h" +#include "echo_files.h" +#include "vtr_util.h" /* @@ -293,6 +294,15 @@ class NocTrafficFlows */ bool check_if_cluster_block_is_a_noc_router(ClusterBlockId block_id); + /** + * @brief Writes out the NocTrafficFlows class information to a file. + * This includes printing out each internal datastructure information. + * + * @param file_name The name of the file that contains the NoC + * traffic flow information + */ + void echo_noc_traffic_flows(char* file_name); + }; From af61c8435d088d21ffe2897104e0c097a097e584 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 29 Jun 2022 02:39:23 -0400 Subject: [PATCH 095/128] Made it so now after parsing the traffic flows file the NocTrafficFlows class information is dumped out to a text file. This is done only if the user requested it. --- vpr/src/base/echo_files.cpp | 1 + vpr/src/base/echo_files.h | 1 + vpr/src/noc/read_xml_noc_traffic_flows_file.cpp | 5 +++++ vpr/src/noc/read_xml_noc_traffic_flows_file.h | 1 + 4 files changed, 8 insertions(+) diff --git a/vpr/src/base/echo_files.cpp b/vpr/src/base/echo_files.cpp index c03587d1260..10cf8c18443 100644 --- a/vpr/src/base/echo_files.cpp +++ b/vpr/src/base/echo_files.cpp @@ -132,6 +132,7 @@ void alloc_and_load_echo_file_info() { //NoC setEchoFileName(E_ECHO_NOC_MODEL, "noc_model.echo"); + setEchoFileName(E_ECHO_NOC_TRAFFIC_FLOWS, "noc_traffic_flows.echo"); } void free_echo_file_info() { diff --git a/vpr/src/base/echo_files.h b/vpr/src/base/echo_files.h index 4d70911ca3b..548d6a9fe49 100644 --- a/vpr/src/base/echo_files.h +++ b/vpr/src/base/echo_files.h @@ -65,6 +65,7 @@ enum e_echo_files { //NoC E_ECHO_NOC_MODEL, + E_ECHO_NOC_TRAFFIC_FLOWS, E_ECHO_END_TOKEN }; diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index f6fd798b716..d9488660590 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -54,6 +54,11 @@ void read_xml_noc_traffic_flows_file(const char* noc_flows_file){ noc_ctx.noc_traffic_flows_storage.finshed_noc_traffic_flows_setup(); + // dump out the NocTrafficFlows class information if the user requested it + if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_NOC_TRAFFIC_FLOWS)) { + noc_ctx.noc_traffic_flows_storage.echo_noc_traffic_flows(getEchoFileName(E_ECHO_NOC_TRAFFIC_FLOWS)); + } + return; } diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.h b/vpr/src/noc/read_xml_noc_traffic_flows_file.h index 9e4e6888d6f..4196f82c0e6 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.h +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.h @@ -26,6 +26,7 @@ #include "vtr_util.h" #include "ShowSetup.h" #include "vpr_error.h" +#include "echo_files.h" #include "noc_data_types.h" #include "noc_traffic_flows.h" From 70de39ae3c342021b9390839e459ad4c675c9a46 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 29 Jun 2022 23:10:16 -0400 Subject: [PATCH 096/128] fixed an issue within the check_for_diplicate_traffic_flows function, when there are no associated traffic flows for a given router a null datastructure is accessed causing a segmentation fault --- .../noc/read_xml_noc_traffic_flows_file.cpp | 41 +++++++++++-------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index d9488660590..9b19c07a21a 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -75,9 +75,9 @@ void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_dat pugiutil::expect_only_attributes(single_flow_tag, expected_single_flow_attributes, loc_data); // store the names of the routers part of this traffic flow - std::string source_router_module_name = pugiutil::get_attribute(single_flow_tag, "src", loc_data, pugiutil::REQUIRED).value(); + std::string source_router_module_name = pugiutil::get_attribute(single_flow_tag, "src", loc_data, pugiutil::REQUIRED).as_string(); - std::string sink_router_module_name = pugiutil::get_attribute(single_flow_tag, "dst", loc_data, pugiutil::REQUIRED).value(); + std::string sink_router_module_name = pugiutil::get_attribute(single_flow_tag, "dst", loc_data, pugiutil::REQUIRED).as_string(); //verify whether the router module names are legal verify_traffic_flow_router_modules(source_router_module_name, sink_router_module_name, single_flow_tag, loc_data); @@ -156,8 +156,13 @@ ClusterBlockId get_router_module_cluster_id(std::string router_module_name, cons // go through each logical type and check if there is a cluster block // of that type that also matches the input module name for (auto logical_type = supported_noc_logical_types->begin(); logical_type != supported_noc_logical_types->end(); logical_type++){ - - router_module_id = cluster_ctx.clb_nlist.find_block_with_matching_name(router_module_name, *logical_type); + + try{ + router_module_id = cluster_ctx.clb_nlist.find_block_with_matching_name(router_module_name, *logical_type); + }catch(const std::regex_error& error){ + // if there was an error with matching the regex string,report it to the user here + vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), error.what()); + } // found a block for the current logical type, so exit if ((size_t)router_module_id != (size_t)ClusterBlockId::INVALID()){ @@ -254,22 +259,26 @@ void check_for_duplicate_traffic_flow(ClusterBlockId source_router_id, ClusterBl const std::vector* list_of_associated_traffic_flows_to_source_router = noc_traffic_flow_storage.get_traffic_flows_associated_to_source_router(source_router_id); - /* - Go through all the traffic flows that exist with the current source router and check to see if any of those traffic flows have a sink router - that matches current sink router. When this happens then the two traffic flows are duplicates and an error should be thrown. - */ - for (auto traffic_flow_id = list_of_associated_traffic_flows_to_source_router->begin(); traffic_flow_id != list_of_associated_traffic_flows_to_source_router->end(); traffic_flow_id++){ - - ClusterBlockId curr_sink_router_id = noc_traffic_flow_storage.get_single_noc_traffic_flow(*traffic_flow_id).sink_router_cluster_id; + // make sure the router is associated to atleast one traffic flow + if (list_of_associated_traffic_flows_to_source_router != nullptr){ - // compare the current traffic flows sink router with the new traffic flows sink router - if ((size_t)curr_sink_router_id == (size_t)sink_router_id){ + /* + Go through all the traffic flows that exist with the current source router and check to see if any of those traffic flows have a sink router + that matches current sink router. When this happens then the two traffic flows are duplicates and an error should be thrown. + */ + for (auto traffic_flow_id = list_of_associated_traffic_flows_to_source_router->begin(); traffic_flow_id != list_of_associated_traffic_flows_to_source_router->end(); traffic_flow_id++){ - // the routers are the same, so this is a duplicate traffic flow. thrown an error - vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "The supplied traffic flow is a duplicate of another traffic flow (contain the same source and sink routers). Duplicate traffic flows are not allowed."); + ClusterBlockId curr_sink_router_id = noc_traffic_flow_storage.get_single_noc_traffic_flow(*traffic_flow_id).sink_router_cluster_id; - } + // compare the current traffic flows sink router with the new traffic flows sink router + if ((size_t)curr_sink_router_id == (size_t)sink_router_id){ + + // the routers are the same, so this is a duplicate traffic flow. thrown an error + vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "The supplied traffic flow is a duplicate of another traffic flow (contain the same source and sink routers). Duplicate traffic flows are not allowed."); + } + + } } return; From 496c9a421214e2146bb4217be5a2417475845103 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 29 Jun 2022 23:20:29 -0400 Subject: [PATCH 097/128] fixed in an issue in the echo function whereall the printed traffic flow ids were the same number. Now the correct traffic flow id is printed for each traffic flow --- vpr/src/noc/noc_traffic_flows.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vpr/src/noc/noc_traffic_flows.cpp b/vpr/src/noc/noc_traffic_flows.cpp index 0fa6cfd4f75..ec19d3c0545 100644 --- a/vpr/src/noc/noc_traffic_flows.cpp +++ b/vpr/src/noc/noc_traffic_flows.cpp @@ -196,6 +196,9 @@ void NocTrafficFlows::echo_noc_traffic_flows(char* file_name){ // seperate the next link information fprintf(fp, "\n"); + + // update the id for the next traffic flow + traffic_flow_id++; } // now print the associated traffic flow information for router cluster blocks that act as source routers in traffic flows @@ -258,6 +261,8 @@ void NocTrafficFlows::echo_noc_traffic_flows(char* file_name){ fprintf(fp, "Router cluster block ID: %lu\n", (size_t)*single_router_block); } + + vtr::fclose(fp); return; From 0c8d04dcf0c7abb34efec999778e8c71c541f034 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Thu, 30 Jun 2022 00:27:03 -0400 Subject: [PATCH 098/128] Moved from using the string comparison function to directly comparing strings. Also removed casting of strongIDs --- vpr/src/noc/read_xml_noc_traffic_flows_file.cpp | 12 ++++++------ vpr/src/noc/read_xml_noc_traffic_flows_file.h | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index 9b19c07a21a..a6e508e8877 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -110,11 +110,11 @@ void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_dat void verify_traffic_flow_router_modules(std::string source_router_name, std::string sink_router_name, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data){ // check that the router module names were legal - if ((source_router_name.compare("") == 0) || (sink_router_name.compare("") == 0)){ + if ((source_router_name == "") || (sink_router_name == "")){ vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "Invalid names for the source and sink NoC router modules."); }// check if the source and sink routers have the same name - else if (source_router_name.compare(sink_router_name) == 0) + else if (source_router_name == sink_router_name) { // Cannot have the source and sink routers have the same name (they need to be different). A flow cant go to a single router. vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "Source and sink NoC routers cannot be the same modules."); @@ -165,20 +165,20 @@ ClusterBlockId get_router_module_cluster_id(std::string router_module_name, cons } // found a block for the current logical type, so exit - if ((size_t)router_module_id != (size_t)ClusterBlockId::INVALID()){ + if (router_module_id != ClusterBlockId::INVALID()){ break; } } // found a block for the current sub tile, so exit - if ((size_t)router_module_id != (size_t)ClusterBlockId::INVALID()){ + if (router_module_id != ClusterBlockId::INVALID()){ break; } } // check if a valid block id was found - if ((size_t)router_module_id == (size_t)ClusterBlockId::INVALID()){ + if (router_module_id == ClusterBlockId::INVALID()){ // if here then the module did not exist in the design, so throw an error vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "The router module '%s' does not exist in the design.", router_module_name.c_str()); } @@ -271,7 +271,7 @@ void check_for_duplicate_traffic_flow(ClusterBlockId source_router_id, ClusterBl ClusterBlockId curr_sink_router_id = noc_traffic_flow_storage.get_single_noc_traffic_flow(*traffic_flow_id).sink_router_cluster_id; // compare the current traffic flows sink router with the new traffic flows sink router - if ((size_t)curr_sink_router_id == (size_t)sink_router_id){ + if (curr_sink_router_id == sink_router_id){ // the routers are the same, so this is a duplicate traffic flow. thrown an error vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "The supplied traffic flow is a duplicate of another traffic flow (contain the same source and sink routers). Duplicate traffic flows are not allowed."); diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.h b/vpr/src/noc/read_xml_noc_traffic_flows_file.h index 4196f82c0e6..8b6c3482649 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.h +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.h @@ -3,7 +3,7 @@ /** * @brief The purpose of this file is to read and parse an xml file that has - * then a '.flows' extension. THis file contains the description of + * then a '.flows' extension. This file contains the description of * a number of traffic flows within the NoC. A traffic flow describes * the communication between two routers in the NoC. * From 9b8cbf2b33b43c006d459942336db39e4d744fb0 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Thu, 30 Jun 2022 00:28:18 -0400 Subject: [PATCH 099/128] Updated tests to check for previously changed error messages in read_xml_noc_traffic_flows_file.cpp --- vpr/test/test_read_xml_noc_traffic_flows_file.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp index f9f451b6c16..c1b31ad29f7 100644 --- a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp +++ b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp @@ -20,7 +20,7 @@ namespace{ std::string src_router_name = ""; std::string dst_router_name = "test"; - REQUIRE_THROWS_WITH(verify_traffic_flow_router_modules(src_router_name, dst_router_name, test, test_location), "Invalid names for the source and destination NoC router modules."); + REQUIRE_THROWS_WITH(verify_traffic_flow_router_modules(src_router_name, dst_router_name, test, test_location), "Invalid names for the source and sink NoC router modules."); } SECTION("Test case where the router module names for both the source and destination routers are the same"){ @@ -28,7 +28,7 @@ namespace{ std::string src_router_name = "same_router"; std::string dst_router_name = "same_router"; - REQUIRE_THROWS_WITH(verify_traffic_flow_router_modules(src_router_name, dst_router_name, test, test_location), "Source and destination NoC routers cannot be the same modules."); + REQUIRE_THROWS_WITH(verify_traffic_flow_router_modules(src_router_name, dst_router_name, test, test_location), "Source and sink NoC routers cannot be the same modules."); } SECTION("Test case where the source and destination router module names are legeal"){ From 9491ffed39f83d35283b3d212d53d799dd6584b3 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Thu, 30 Jun 2022 13:57:04 -0400 Subject: [PATCH 100/128] Removed the use of the word 'list' when naming vectors or referencing them. --- vpr/src/noc/noc_traffic_flows.cpp | 34 +++++++++-------- vpr/src/noc/noc_traffic_flows.h | 38 ++++++++++--------- .../noc/read_xml_noc_traffic_flows_file.cpp | 8 ++-- 3 files changed, 42 insertions(+), 38 deletions(-) diff --git a/vpr/src/noc/noc_traffic_flows.cpp b/vpr/src/noc/noc_traffic_flows.cpp index ec19d3c0545..acf8150098f 100644 --- a/vpr/src/noc/noc_traffic_flows.cpp +++ b/vpr/src/noc/noc_traffic_flows.cpp @@ -11,7 +11,7 @@ NocTrafficFlows::NocTrafficFlows(void){ const t_noc_traffic_flow& NocTrafficFlows::get_single_noc_traffic_flow(NocTrafficFlowId traffic_flow_id) const { - return list_of_noc_traffic_flows[traffic_flow_id]; + return noc_traffic_flows[traffic_flow_id]; } const std::vector* NocTrafficFlows::get_traffic_flows_associated_to_source_router(ClusterBlockId source_router_id) const { @@ -33,19 +33,19 @@ const std::vector* NocTrafficFlows::get_traffic_flows_associat const std::vector* NocTrafficFlows::get_traffic_flows_associated_to_sink_router(ClusterBlockId source_router_id) const { - const std::vector* traffic_flow_list = nullptr; + const std::vector* associated_traffic_flows_ref = nullptr; - // get a reference to the list of traffic flows that have the current router as a source - auto sink_router_traffic_flows_list = sink_router_associated_traffic_flows.find(source_router_id); + // get a reference to the traffic flows that have the current router as a source + auto associated_traffic_flows = sink_router_associated_traffic_flows.find(source_router_id); // check if there are any traffic flows associated with the current router - if (sink_router_traffic_flows_list != sink_router_associated_traffic_flows.end()){ + if (associated_traffic_flows != sink_router_associated_traffic_flows.end()){ // if we are here then there exists atleast 1 traffic flow that includes the current router as a source - traffic_flow_list = &(sink_router_traffic_flows_list->second); + associated_traffic_flows_ref = &(associated_traffic_flows->second); } - return traffic_flow_list; + return associated_traffic_flows_ref; } bool NocTrafficFlows::get_traffic_flow_processed_status(NocTrafficFlowId traffic_flow_id){ @@ -62,11 +62,11 @@ int NocTrafficFlows::get_number_of_routers_used_in_traffic_flows(void){ void NocTrafficFlows::create_noc_traffic_flow(std::string source_router_module_name, std::string sink_router_module_name, ClusterBlockId source_router_cluster_id, ClusterBlockId sink_router_cluster_id, double traffic_flow_bandwidth, double traffic_flow_latency){ - // create and add the new traffic flow to the list - list_of_noc_traffic_flows.emplace_back(source_router_module_name, sink_router_module_name, source_router_cluster_id, sink_router_cluster_id, traffic_flow_bandwidth, traffic_flow_latency); + // create and add the new traffic flow to the vector + noc_traffic_flows.emplace_back(source_router_module_name, sink_router_module_name, source_router_cluster_id, sink_router_cluster_id, traffic_flow_bandwidth, traffic_flow_latency); - //since the new traffic flow was added to the back of the list, its id will be the index of the last element - NocTrafficFlowId curr_traffic_flow_id = (NocTrafficFlowId)(list_of_noc_traffic_flows.size() - 1); + //since the new traffic flow was added to the back of the vector, its id will be the index of the last element + NocTrafficFlowId curr_traffic_flow_id = (NocTrafficFlowId)(noc_traffic_flows.size() - 1); // add the source and sink routers to the set of unique router blocks in the design add_router_to_block_set(source_router_cluster_id); @@ -94,8 +94,8 @@ void NocTrafficFlows::set_traffic_flow_status(NocTrafficFlowId traffic_flow_id, void NocTrafficFlows::finshed_noc_traffic_flows_setup(void){ - // get the total number of traffic flows and create a vectorof the same size to hold the "processed status" of each traffic flow - int num_of_traffic_flows = list_of_noc_traffic_flows.size(); + // get the total number of traffic flows and create a vector of the same size to hold the "processed status" of each traffic flow + int num_of_traffic_flows = noc_traffic_flows.size(); // initialize the status to not processed yet processed_traffic_flows.resize(num_of_traffic_flows,NOT_PROCESSED); @@ -115,7 +115,7 @@ void NocTrafficFlows::reset_traffic_flows_processed_status(void){ void NocTrafficFlows::clear_traffic_flows(void){ // delete any information from internal datastructures - list_of_noc_traffic_flows.clear(); + noc_traffic_flows.clear(); source_router_associated_traffic_flows.clear(); sink_router_associated_traffic_flows.clear(); processed_traffic_flows.clear(); @@ -127,8 +127,10 @@ void NocTrafficFlows::clear_traffic_flows(void){ bool NocTrafficFlows::check_if_cluster_block_is_a_noc_router(ClusterBlockId block_id){ auto router_block = noc_router_blocks.find(block_id); + bool result = false; + // Check if the given cluster block was found inside the set of all router blocks in the design, then this was a router block so return true. Otherwise return false. if (router_block != noc_router_blocks.end()){ result = true; } @@ -140,7 +142,7 @@ bool NocTrafficFlows::check_if_cluster_block_is_a_noc_router(ClusterBlockId bloc void NocTrafficFlows::add_traffic_flow_to_associated_routers(NocTrafficFlowId traffic_flow_id, ClusterBlockId associated_router_id, std::unordered_map>& router_associated_traffic_flows){ - // get a reference to the list of traffic flows associated with the current router + // get a reference to the traffic flows associated with the current router auto router_traffic_flows = router_associated_traffic_flows.find(associated_router_id); // check if a list exists @@ -183,7 +185,7 @@ void NocTrafficFlows::echo_noc_traffic_flows(char* file_name){ int traffic_flow_id = 0; // go through each traffic flow and print its information - for(auto traffic_flow = list_of_noc_traffic_flows.begin(); traffic_flow != list_of_noc_traffic_flows.end(); traffic_flow++){ + for(auto traffic_flow = noc_traffic_flows.begin(); traffic_flow != noc_traffic_flows.end(); traffic_flow++){ // print the current traffic flows data fprintf(fp, "Traffic flow ID: %d\n", traffic_flow_id); diff --git a/vpr/src/noc/noc_traffic_flows.h b/vpr/src/noc/noc_traffic_flows.h index d1051467f24..b57d0e693ae 100644 --- a/vpr/src/noc/noc_traffic_flows.h +++ b/vpr/src/noc/noc_traffic_flows.h @@ -8,8 +8,9 @@ * * Overview * ======== - * The NocTrafficFlows class contains a list of t_noc_traffic_flow in a given - * design. Each traffic flow is indexed by a unique id that can be used to + * The NocTrafficFlows class contains all traffic flows in a given + * design. A traffic flow is defined by the t_noc_traffic_flow struct. + * Each traffic flow is indexed by a unique id that can be used to * retrieve information about them. * * The class also associates traffic flows to their source routers (start point) @@ -20,7 +21,7 @@ * as routers will be moved throughout the chip. Therefore this class provides * a datastructure to keep track of which flows have been updated (re-routed). * - * Finally, this class also stores a list of all router blocks in the design. + * Finally, this class also stores all router blocks in the design. * * This class will be primarily used during * placement to identify which routers inside the NoC(NocStorage) need to @@ -80,14 +81,14 @@ class NocTrafficFlows private: /** contains all the traffic flows provided by the user and their information*/ - vtr::vector list_of_noc_traffic_flows; + vtr::vector noc_traffic_flows; /** A traffic flow has a source and destination router associated to it. So when either the source or destination router for a given flow is moved, we need to find a new route between them. Therefore, during placement if two router blocks are swapped, then the only traffic flows we need to re-route are the flows where the two routers are either the source or destination routers of those flows. - The datastructures below store a list of traffic flows for each router when the router is a source for the traffic flow. Similarily, there is a another datastructure where a list of traffic flows are stored for each router where the router is a sink for the traffic flow. The routers are indexed by their ClusterBlockId. + The datastructures below store all traffic flows for each router where the router is a source for the traffic flow. Similarily, there is a another datastructure where all traffic flows are stored for each router where the router is a sink for the traffic flow. The routers are indexed by their ClusterBlockId. This is done so that the traffic that need to be re-routed during placement can be quickly found. */ @@ -121,13 +122,13 @@ class NocTrafficFlows /** * @brief Given a router that is either a source or sink of * a traffic flow, the corresponding traffic flow is added - * to a list of traffic flows associated to the router. + * to a vector of traffic flows associated to the router. * * @param traffic_flow_id A unique id that represents a traffic flow. * @param associated_router_id A ClusterblockId that represents a * router block. * @param router_associated_traffic_flows A datastructure that stores - * a list of traffic flows for a given router block where the traffic + * a vector of traffic flows for a given router block where the traffic * flows have the router as a source or sink within the flow. * */ @@ -149,7 +150,7 @@ class NocTrafficFlows /** * @brief Given a unique id of a traffic flow (t_noc_traffic_flow) - * retrieve it from the list of all traffic flows in the design. The + * retrieve it from the vector of all traffic flows in the design. The * retrieved traffic flow cannot be modified but can be used to * retireve information such as the routers involved. * @@ -161,29 +162,30 @@ class NocTrafficFlows const t_noc_traffic_flow& get_single_noc_traffic_flow(NocTrafficFlowId traffic_flow_id) const; /** - * @brief Get a list of all traffic flows that have a given router + * @brief Get a vector of all traffic flows that have a given router * block in the clustered netlist as the source (starting point) in the * flow. * * @param source_router_id A unique identifier that represents the * a router block in the clustered netlist. This router block will * be the source router in the retrieved traffic flow. - * @return const std::vector* A list of traffic flows - * that have the input router block parameter as the source in the + * @return const std::vector* A vector of traffic + * flows that have the input router block parameter as the source in the * flow. */ const std::vector* get_traffic_flows_associated_to_source_router(ClusterBlockId source_router_id) const; /** - * @brief Get a list of all traffic flows that have a given router + * @brief Get a vector of all traffic flows that have a given router * block in the clustered netlist as the sink (end point) in the * flow. * * @param sink_router_id A unique identifier that represents the * a router block in the clustered netlist. This router block will * be the sink router in the retrieved traffic flow. - * @return const std::vector* A list of traffic flows - * that have the input router block parameter as the sink in the flow. + * @return const std::vector* A vector of traffic + * flows that have the input router block parameter as the sink in the + * flow. */ const std::vector* get_traffic_flows_associated_to_sink_router(ClusterBlockId sink_router_id) const; @@ -217,12 +219,12 @@ class NocTrafficFlows /** * @brief Given a set of parameters that describe a traffic - * flow, create it an add it to the list of traffic flows in the + * flow, create it an add it to the vector of traffic flows in the * design. Additionally, the two router blocks involved have their * ids stored to to keep track of all router blocks that are used * in traffic flows. Finally, the newly created traffic flow is - * added to a list of traffic flows associated to both the - * source and sink routers of the flow. + * also added to a vector of traffic flows that are associated to both + * the source and sink routers of the flow. * * @param source_router_module_name A string that represents the * name of the source router block in the traffic flow. THis is @@ -258,7 +260,7 @@ class NocTrafficFlows /** * @brief Determines the total number of traffic flows in - * the design and creates a list to keep track of the traffic + * the design and creates a vector to keep track of the traffic * flows processed status. This function should be called after * all the traffic flows have been created. The traffic flows are * all initialized to being not processed. diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index a6e508e8877..83379dfc97b 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -68,7 +68,7 @@ void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_dat // contains all traffic flows NocTrafficFlows* noc_traffic_flow_storage = &noc_ctx.noc_traffic_flows_storage; - // an accepted list of attributes for the single flow tag + // an accepted set of attributes for the single flow tag std::vector expected_single_flow_attributes = {"src", "dst", "bandwidth", "latency_cons"}; // check that only the accepted single flow attributes are found in the tag @@ -257,16 +257,16 @@ bool check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& no void check_for_duplicate_traffic_flow(ClusterBlockId source_router_id, ClusterBlockId sink_router_id, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const NocTrafficFlows& noc_traffic_flow_storage){ - const std::vector* list_of_associated_traffic_flows_to_source_router = noc_traffic_flow_storage.get_traffic_flows_associated_to_source_router(source_router_id); + const std::vector* associated_traffic_flows_to_source_router = noc_traffic_flow_storage.get_traffic_flows_associated_to_source_router(source_router_id); // make sure the router is associated to atleast one traffic flow - if (list_of_associated_traffic_flows_to_source_router != nullptr){ + if (associated_traffic_flows_to_source_router != nullptr){ /* Go through all the traffic flows that exist with the current source router and check to see if any of those traffic flows have a sink router that matches current sink router. When this happens then the two traffic flows are duplicates and an error should be thrown. */ - for (auto traffic_flow_id = list_of_associated_traffic_flows_to_source_router->begin(); traffic_flow_id != list_of_associated_traffic_flows_to_source_router->end(); traffic_flow_id++){ + for (auto traffic_flow_id = associated_traffic_flows_to_source_router->begin(); traffic_flow_id != associated_traffic_flows_to_source_router->end(); traffic_flow_id++){ ClusterBlockId curr_sink_router_id = noc_traffic_flow_storage.get_single_noc_traffic_flow(*traffic_flow_id).sink_router_cluster_id; From 2addace4172ac7da9c623c128e973dac60aeb48b Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Thu, 30 Jun 2022 15:30:58 -0400 Subject: [PATCH 101/128] formatting changes. --- vpr/src/base/ShowSetup.cpp | 2 +- vpr/src/base/clustered_netlist.cpp | 20 +- vpr/src/base/clustered_netlist.h | 10 +- vpr/src/base/netlist.h | 2 +- vpr/src/base/netlist.tpp | 8 +- vpr/src/base/read_options.cpp | 4 +- vpr/src/base/vpr_types.h | 2 +- vpr/src/noc/noc_traffic_flows.cpp | 104 +-- vpr/src/noc/noc_traffic_flows.h | 474 ++++++------ .../noc/read_xml_noc_traffic_flows_file.cpp | 145 ++-- vpr/src/noc/read_xml_noc_traffic_flows_file.h | 4 +- vpr/test/test_clustered_netlist.cpp | 227 +++--- vpr/test/test_noc_traffic_flows.cpp | 235 +++--- .../test_read_xml_noc_traffic_flows_file.cpp | 708 +++++++++--------- 14 files changed, 909 insertions(+), 1036 deletions(-) diff --git a/vpr/src/base/ShowSetup.cpp b/vpr/src/base/ShowSetup.cpp index 86e32cd726c..b6e5e5163b7 100644 --- a/vpr/src/base/ShowSetup.cpp +++ b/vpr/src/base/ShowSetup.cpp @@ -769,7 +769,7 @@ static void ShowPackerOpts(const t_packer_opts& PackerOpts) { VTR_LOG("\n"); } -static void ShowNocOpts(const t_noc_opts& NocOpts){ +static void ShowNocOpts(const t_noc_opts& NocOpts) { VTR_LOG("NocOpts.noc_flows_file: %s\n", NocOpts.noc_flows_file.c_str()); VTR_LOG("\n"); diff --git a/vpr/src/base/clustered_netlist.cpp b/vpr/src/base/clustered_netlist.cpp index 7d2b8e4d816..e1c22b55b2b 100644 --- a/vpr/src/base/clustered_netlist.cpp +++ b/vpr/src/base/clustered_netlist.cpp @@ -281,19 +281,17 @@ void ClusteredNetlist::shrink_to_fit_impl() { * block in a list where all the other blocks in the list are of the * blocks logical type. */ -void ClusteredNetlist::add_block_to_logical_type(ClusterBlockId blk_id, t_logical_block_type_ptr type){ - +void ClusteredNetlist::add_block_to_logical_type(ClusterBlockId blk_id, t_logical_block_type_ptr type) { std::string logical_block_type_name = type->name; // check if a group of blocks exist for the current logical block type // basically checking if this is the first time we are seeing this logical block type auto logical_type_blocks = block_type_to_id.find(logical_block_type_name); - if (logical_type_blocks == block_type_to_id.end()){ + if (logical_type_blocks == block_type_to_id.end()) { // if the current logical block doesnt exist then create a new group of blocks for it and add it block_type_to_id.emplace(logical_block_type_name, std::vector({blk_id})); - } - else{ + } else { // current logical block exists, so add the current block to the group other blocks of this type logical_type_blocks->second.push_back(blk_id); } @@ -360,26 +358,24 @@ bool ClusteredNetlist::validate_net_sizes_impl(size_t num_nets) const { * */ ClusterBlockId ClusteredNetlist::find_block_with_matching_name(const std::string& name, t_logical_block_type_ptr blk_type) const { - ClusterBlockId blk_id = ClusterBlockId::INVALID(); auto blks_of_logical_type = block_type_to_id.find(blk_type->name); std::regex name_to_match(name); - if (blks_of_logical_type != block_type_to_id.end()){ + if (blks_of_logical_type != block_type_to_id.end()) { // get the list of blocks that are of the specified logical type const std::vector* blk_list = &blks_of_logical_type->second; - - // go through the list of blocks to find if any block name matches the provided name (contains the input string in its name) - for (auto blk = blk_list->begin(); blk != blk_list->end(); blk++){ + // go through the list of blocks to find if any block name matches the provided name (contains the input string in its name) + for (auto blk = blk_list->begin(); blk != blk_list->end(); blk++) { // another thing you can do is go through blocks and instead string.find(), you can use a regular expression version (so match a regular expression) // check for the string match - if (std::regex_match(Netlist::block_name(*blk), name_to_match)){ + if (std::regex_match(Netlist::block_name(*blk), name_to_match)) { blk_id = *blk; break; } - } + } } return blk_id; } diff --git a/vpr/src/base/clustered_netlist.h b/vpr/src/base/clustered_netlist.h index a3c87abdf3b..c2dfea65c46 100644 --- a/vpr/src/base/clustered_netlist.h +++ b/vpr/src/base/clustered_netlist.h @@ -251,7 +251,7 @@ class ClusteredNetlist : public Netlist block_pbs_; /// block_types_; ///> block_logical_pins_; ///> block_type_to_id;///> block_type_to_id; ///::find_block(const std::string& na */ template BlockId Netlist::find_block_with_matching_name(const std::string& name) const { - BlockId matching_blk_id = BlockId::INVALID(); const std::string blk_name; - + // go through all the blocks in the netlist - for (auto blk_id = block_ids_.begin(); blk_id != block_ids_.end(); blk_id++){ + for (auto blk_id = block_ids_.begin(); blk_id != block_ids_.end(); blk_id++) { // get the corresponding block name blk_name = &strings_[block_names_[*blk_id]]; // check whether the current block name contains the input string within it - if (blk_name.find(name) != std::string::npos){ + if (blk_name.find(name) != std::string::npos) { matching_blk_id = blk_id; break; } @@ -492,7 +491,6 @@ BlockId Netlist::find_block_with_matching_name(co return matching_blk_id; } - template PortId Netlist::find_port(const BlockId blk_id, const std::string& name) const { VTR_ASSERT_SAFE(valid_block_id(blk_id)); diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index e8ae4a8ef74..50917547e96 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -2621,10 +2621,10 @@ argparse::ArgumentParser create_arg_parser(std::string prog_name, t_options& arg "This should be on only when the FPGA device contains a NoC and the provided netlist connects to the NoC.") .default_value("off") .show_in(argparse::ShowIn::HELP_ONLY); - + noc_grp.add_argument(args.noc_flows_file, "--noc_flows_file") .help( - "XML file containing the list of traffic flows within the NoC (communication between routers)." + "XML file containing the list of traffic flows within the NoC (communication between routers)." "This is required if the --noc option is turned on.") .default_value("") .show_in(argparse::ShowIn::HELP_ONLY); diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index f1562aea37b..401a8dd3873 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -1271,7 +1271,7 @@ struct t_analysis_opts { // used to store NoC specific options, when supplied as an input by the user struct t_noc_opts { - bool noc; ///* NocTrafficFlows::get_traffic_flows_associated_to_source_router(ClusterBlockId source_router_id) const { + const std::vector* associated_traffic_flows_ref = nullptr; - const std::vector* traffic_flow_list = nullptr; - - // get a reference to the list of traffic flows that have the current router as a source - auto source_router_traffic_flows_list = source_router_associated_traffic_flows.find(source_router_id); + // get a reference to the traffic flows that have the current router as a source + auto associated_traffic_flows = source_router_associated_traffic_flows.find(source_router_id); // check if there are any traffic flows associated with the current router - if (source_router_traffic_flows_list != source_router_associated_traffic_flows.end()){ - + if (associated_traffic_flows != source_router_associated_traffic_flows.end()) { // if we are here then there exists atleast 1 traffic flow that includes the current router as a source - traffic_flow_list = &(source_router_traffic_flows_list->second); + associated_traffic_flows_ref = &(associated_traffic_flows->second); } - return traffic_flow_list; + return associated_traffic_flows_ref; } const std::vector* NocTrafficFlows::get_traffic_flows_associated_to_sink_router(ClusterBlockId source_router_id) const { - const std::vector* associated_traffic_flows_ref = nullptr; - // get a reference to the traffic flows that have the current router as a source + // get a reference to the traffic flows that have the current router as a source auto associated_traffic_flows = sink_router_associated_traffic_flows.find(source_router_id); // check if there are any traffic flows associated with the current router - if (associated_traffic_flows != sink_router_associated_traffic_flows.end()){ - + if (associated_traffic_flows != sink_router_associated_traffic_flows.end()) { // if we are here then there exists atleast 1 traffic flow that includes the current router as a source associated_traffic_flows_ref = &(associated_traffic_flows->second); } @@ -48,20 +43,17 @@ const std::vector* NocTrafficFlows::get_traffic_flows_associat return associated_traffic_flows_ref; } -bool NocTrafficFlows::get_traffic_flow_processed_status(NocTrafficFlowId traffic_flow_id){ - +bool NocTrafficFlows::get_traffic_flow_processed_status(NocTrafficFlowId traffic_flow_id) { return processed_traffic_flows[traffic_flow_id]; } -int NocTrafficFlows::get_number_of_routers_used_in_traffic_flows(void){ - +int NocTrafficFlows::get_number_of_routers_used_in_traffic_flows(void) { return noc_router_blocks.size(); } // setters for the traffic flows -void NocTrafficFlows::create_noc_traffic_flow(std::string source_router_module_name, std::string sink_router_module_name, ClusterBlockId source_router_cluster_id, ClusterBlockId sink_router_cluster_id, double traffic_flow_bandwidth, double traffic_flow_latency){ - +void NocTrafficFlows::create_noc_traffic_flow(std::string source_router_module_name, std::string sink_router_module_name, ClusterBlockId source_router_cluster_id, ClusterBlockId sink_router_cluster_id, double traffic_flow_bandwidth, double traffic_flow_latency) { // create and add the new traffic flow to the vector noc_traffic_flows.emplace_back(source_router_module_name, sink_router_module_name, source_router_cluster_id, sink_router_cluster_id, traffic_flow_bandwidth, traffic_flow_latency); @@ -77,13 +69,11 @@ void NocTrafficFlows::create_noc_traffic_flow(std::string source_router_module_n add_traffic_flow_to_associated_routers(curr_traffic_flow_id, sink_router_cluster_id, this->sink_router_associated_traffic_flows); return; - } // given a traffic flow and its status, update it -void NocTrafficFlows::set_traffic_flow_status(NocTrafficFlowId traffic_flow_id, bool status){ - - // status is initialized to false, change it to true to reflect that the specified flow has been processed +void NocTrafficFlows::set_traffic_flow_status(NocTrafficFlowId traffic_flow_id, bool status) { + // status is initialized to false, change it to true to reflect that the specified flow has been processed processed_traffic_flows[traffic_flow_id] = status; return; @@ -91,29 +81,24 @@ void NocTrafficFlows::set_traffic_flow_status(NocTrafficFlowId traffic_flow_id, // utility functions for the noc traffic flows - -void NocTrafficFlows::finshed_noc_traffic_flows_setup(void){ - +void NocTrafficFlows::finshed_noc_traffic_flows_setup(void) { // get the total number of traffic flows and create a vector of the same size to hold the "processed status" of each traffic flow int num_of_traffic_flows = noc_traffic_flows.size(); // initialize the status to not processed yet - processed_traffic_flows.resize(num_of_traffic_flows,NOT_PROCESSED); + processed_traffic_flows.resize(num_of_traffic_flows, NOT_PROCESSED); return; } -void NocTrafficFlows::reset_traffic_flows_processed_status(void){ - - for (auto traffic_flow = processed_traffic_flows.begin(); traffic_flow != processed_traffic_flows.end(); traffic_flow++){ - +void NocTrafficFlows::reset_traffic_flows_processed_status(void) { + for (auto traffic_flow = processed_traffic_flows.begin(); traffic_flow != processed_traffic_flows.end(); traffic_flow++) { *traffic_flow = NOT_PROCESSED; } return; } -void NocTrafficFlows::clear_traffic_flows(void){ - +void NocTrafficFlows::clear_traffic_flows(void) { // delete any information from internal datastructures noc_traffic_flows.clear(); source_router_associated_traffic_flows.clear(); @@ -124,14 +109,13 @@ void NocTrafficFlows::clear_traffic_flows(void){ return; } -bool NocTrafficFlows::check_if_cluster_block_is_a_noc_router(ClusterBlockId block_id){ - +bool NocTrafficFlows::check_if_cluster_block_is_a_noc_router(ClusterBlockId block_id) { auto router_block = noc_router_blocks.find(block_id); - + bool result = false; - + // Check if the given cluster block was found inside the set of all router blocks in the design, then this was a router block so return true. Otherwise return false. - if (router_block != noc_router_blocks.end()){ + if (router_block != noc_router_blocks.end()) { result = true; } @@ -140,34 +124,29 @@ bool NocTrafficFlows::check_if_cluster_block_is_a_noc_router(ClusterBlockId bloc // private functions used internally -void NocTrafficFlows::add_traffic_flow_to_associated_routers(NocTrafficFlowId traffic_flow_id, ClusterBlockId associated_router_id, std::unordered_map>& router_associated_traffic_flows){ - +void NocTrafficFlows::add_traffic_flow_to_associated_routers(NocTrafficFlowId traffic_flow_id, ClusterBlockId associated_router_id, std::unordered_map>& router_associated_traffic_flows) { // get a reference to the traffic flows associated with the current router auto router_traffic_flows = router_associated_traffic_flows.find(associated_router_id); - // check if a list exists - if (router_traffic_flows == router_associated_traffic_flows.end()){ - // there exists no list of traffic flows for this router, so we add it with the newly created traffic flow id + // check if a vector asssociated traffic flows exists + if (router_traffic_flows == router_associated_traffic_flows.end()) { + // there exists no associated traffic flows for this router, so we add it with the newly created traffic flow id router_associated_traffic_flows.insert(std::pair>(associated_router_id, {traffic_flow_id})); - } - else{ - // there already is a list of traffic flows for the current router, so add it to the list + } else { + // there already is a vector associated of traffic flows for the current router, so add it router_traffic_flows->second.emplace_back(traffic_flow_id); } - return; - } -void NocTrafficFlows::add_router_to_block_set(ClusterBlockId router_block_id){ - +void NocTrafficFlows::add_router_to_block_set(ClusterBlockId router_block_id) { noc_router_blocks.insert(router_block_id); return; } -void NocTrafficFlows::echo_noc_traffic_flows(char* file_name){ +void NocTrafficFlows::echo_noc_traffic_flows(char* file_name) { FILE* fp; fp = vtr::fopen(file_name, "w"); @@ -185,8 +164,7 @@ void NocTrafficFlows::echo_noc_traffic_flows(char* file_name){ int traffic_flow_id = 0; // go through each traffic flow and print its information - for(auto traffic_flow = noc_traffic_flows.begin(); traffic_flow != noc_traffic_flows.end(); traffic_flow++){ - + for (auto traffic_flow = noc_traffic_flows.begin(); traffic_flow != noc_traffic_flows.end(); traffic_flow++) { // print the current traffic flows data fprintf(fp, "Traffic flow ID: %d\n", traffic_flow_id); fprintf(fp, "Traffic flow source router block name: %s\n", traffic_flow->source_router_module_name.c_str()); @@ -210,8 +188,7 @@ void NocTrafficFlows::echo_noc_traffic_flows(char* file_name){ // go through each router block cluster and print its associated traffic flows where the cluster is a source router for those traffic flows // we only print out the traffic flow ids - for (auto it = source_router_associated_traffic_flows.begin(); it != source_router_associated_traffic_flows.end(); it++){ - + for (auto it = source_router_associated_traffic_flows.begin(); it != source_router_associated_traffic_flows.end(); it++) { // print the current router cluster id fprintf(fp, "Cluster ID %lu: ", (size_t)it->first); @@ -219,8 +196,7 @@ void NocTrafficFlows::echo_noc_traffic_flows(char* file_name){ auto assoc_traffic_flows = &(it->second); // now go through the traffic flows this router is a source router and add it - for (auto traffic_flow = assoc_traffic_flows->begin(); traffic_flow != assoc_traffic_flows->end(); traffic_flow++){ - + for (auto traffic_flow = assoc_traffic_flows->begin(); traffic_flow != assoc_traffic_flows->end(); traffic_flow++) { fprintf(fp, "%lu ", (size_t)*traffic_flow); } @@ -235,8 +211,7 @@ void NocTrafficFlows::echo_noc_traffic_flows(char* file_name){ // go through each router block cluster and print its associated traffic flows where the cluster is a sink router for those traffic flows // we only print out the traffic flow ids - for (auto it = sink_router_associated_traffic_flows.begin(); it != sink_router_associated_traffic_flows.end(); it++){ - + for (auto it = sink_router_associated_traffic_flows.begin(); it != sink_router_associated_traffic_flows.end(); it++) { // print the current router cluster id fprintf(fp, "Router block cluster ID %lu: ", (size_t)it->first); @@ -244,8 +219,7 @@ void NocTrafficFlows::echo_noc_traffic_flows(char* file_name){ auto assoc_traffic_flows = &(it->second); // now go through the traffic flows this router is a sink router and add it - for (auto traffic_flow = assoc_traffic_flows->begin(); traffic_flow != assoc_traffic_flows->end(); traffic_flow++){ - + for (auto traffic_flow = assoc_traffic_flows->begin(); traffic_flow != assoc_traffic_flows->end(); traffic_flow++) { fprintf(fp, "%lu ", (size_t)*traffic_flow); } @@ -259,13 +233,11 @@ void NocTrafficFlows::echo_noc_traffic_flows(char* file_name){ fprintf(fp, "\n"); // print all the unique router block cluster ids - for (auto single_router_block = noc_router_blocks.begin(); single_router_block != noc_router_blocks.end(); single_router_block++){ - + for (auto single_router_block = noc_router_blocks.begin(); single_router_block != noc_router_blocks.end(); single_router_block++) { fprintf(fp, "Router cluster block ID: %lu\n", (size_t)*single_router_block); } vtr::fclose(fp); - - return; + return; } \ 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 b57d0e693ae..20b84c6c0c0 100644 --- a/vpr/src/noc/noc_traffic_flows.h +++ b/vpr/src/noc/noc_traffic_flows.h @@ -39,12 +39,11 @@ #include "echo_files.h" #include "vtr_util.h" - /* - Whenever a traffic flow is processed (routed a connection between - 2 routers and updated the relevant information) we need to - some way to track it, so that we don't process it again. The flags below indicate whether a traffic flow was processed or not. -*/ + * Whenever a traffic flow is processed (routed a connection between + * 2 routers and updated the relevant information) we need to + * some way to track it, so that we don't process it again. The flags below indicate whether a traffic flow was processed or not. + */ constexpr bool PROCESSED = true; constexpr bool NOT_PROCESSED = false; @@ -55,7 +54,6 @@ constexpr bool NOT_PROCESSED = false; * */ struct t_noc_traffic_flow { - /** stores the names of the router blocks communicating within this traffic flow*/ std::string source_router_module_name; std::string sink_router_module_name; @@ -71,241 +69,239 @@ struct t_noc_traffic_flow { double max_traffic_flow_latency; /** Constructor initializes all variables*/ - t_noc_traffic_flow(std::string source_router_name, std::string sink_router_name, ClusterBlockId source_router_id, ClusterBlockId sink_router_id, double flow_bandwidth, double max_flow_latency) : source_router_module_name(source_router_name), sink_router_module_name(sink_router_name), source_router_cluster_id(source_router_id), sink_router_cluster_id(sink_router_id), traffic_flow_bandwidth(flow_bandwidth), max_traffic_flow_latency(max_flow_latency) - {} - + t_noc_traffic_flow(std::string source_router_name, std::string sink_router_name, ClusterBlockId source_router_id, ClusterBlockId sink_router_id, double flow_bandwidth, double max_flow_latency) + : source_router_module_name(source_router_name) + , sink_router_module_name(sink_router_name) + , source_router_cluster_id(source_router_id) + , sink_router_cluster_id(sink_router_id) + , traffic_flow_bandwidth(flow_bandwidth) + , max_traffic_flow_latency(max_flow_latency) {} }; -class NocTrafficFlows -{ - private: - - /** contains all the traffic flows provided by the user and their information*/ - vtr::vector noc_traffic_flows; - - /** - A traffic flow has a source and destination router associated to it. So when either the source or destination router for a given flow is moved, we need to find a new route between them. - - Therefore, during placement if two router blocks are swapped, then the only traffic flows we need to re-route are the flows where the two routers are either the source or destination routers of those flows. - - The datastructures below store all traffic flows for each router where the router is a source for the traffic flow. Similarily, there is a another datastructure where all traffic flows are stored for each router where the router is a sink for the traffic flow. The routers are indexed by their ClusterBlockId. - - This is done so that the traffic that need to be re-routed during placement can be quickly found. - */ - std::unordered_map> source_router_associated_traffic_flows; - std::unordered_map> sink_router_associated_traffic_flows; - - /** keeps track of which traffic flows have already been processed. - * By processed, it tracks whether a traffic flow has been routed or - * not. During placement, two routers can be swapped, if the - * two routers share a traffic flow, then the shared traffic flow - * will be routed twice, where it will routed when processing the - * flows associated to the source router and then again when - * processing the flows associated to the sink router. By using the - * datastructure below, if whether a traffic flow is processed or not - * is tracked, then we can ensure that no traffic flows are routed - * more than once by referring to this datastructure. - */ - vtr::vector processed_traffic_flows; - - /** contains the cluster ID of all unique router modules in the design. - * and can quickly determine whether a given cluster in the netlist - * is a router block or not. whenever placement swaps two clusters, we - * need to check if the clusters a router blocks or not, this is needed - * so that we can deterimine if we need to re-route traffic flows. The - * datastructure below can be used to quickly identify whether a given - * cluster that was swapped furing palcement is a router block or not.*/ - std::unordered_set noc_router_blocks; - - // private functions - - /** - * @brief Given a router that is either a source or sink of - * a traffic flow, the corresponding traffic flow is added - * to a vector of traffic flows associated to the router. - * - * @param traffic_flow_id A unique id that represents a traffic flow. - * @param associated_router_id A ClusterblockId that represents a - * router block. - * @param router_associated_traffic_flows A datastructure that stores - * a vector of traffic flows for a given router block where the traffic - * flows have the router as a source or sink within the flow. - * - */ - void add_traffic_flow_to_associated_routers(NocTrafficFlowId traffic_flow_id, ClusterBlockId associated_router_id, std::unordered_map>& router_associated_traffic_flows); - - /** - * @brief Given a router block in the clustered netlist, store it - * internally. - * - * @param router_block_id A unique identifier that rerpesents a router block in the clustered netlist. This id will be stored. - */ - void add_router_to_block_set(ClusterBlockId router_block_id); - - - public: - NocTrafficFlows(); - - //getters - - /** - * @brief Given a unique id of a traffic flow (t_noc_traffic_flow) - * retrieve it from the vector of all traffic flows in the design. The - * retrieved traffic flow cannot be modified but can be used to - * retireve information such as the routers involved. - * - * @param traffic_flow_id The unique identifier (NocTrafficFlowId) - * of the traffic flow to retrieve. - * @return const t_noc_traffic_flow& The traffic flow represented by - * the provided identifier. - */ - const t_noc_traffic_flow& get_single_noc_traffic_flow(NocTrafficFlowId traffic_flow_id) const; - - /** - * @brief Get a vector of all traffic flows that have a given router - * block in the clustered netlist as the source (starting point) in the - * flow. - * - * @param source_router_id A unique identifier that represents the - * a router block in the clustered netlist. This router block will - * be the source router in the retrieved traffic flow. - * @return const std::vector* A vector of traffic - * flows that have the input router block parameter as the source in the - * flow. - */ - const std::vector* get_traffic_flows_associated_to_source_router(ClusterBlockId source_router_id) const; - - /** - * @brief Get a vector of all traffic flows that have a given router - * block in the clustered netlist as the sink (end point) in the - * flow. - * - * @param sink_router_id A unique identifier that represents the - * a router block in the clustered netlist. This router block will - * be the sink router in the retrieved traffic flow. - * @return const std::vector* A vector of traffic - * flows that have the input router block parameter as the sink in the - * flow. - */ - const std::vector* get_traffic_flows_associated_to_sink_router(ClusterBlockId sink_router_id) const; - - /** - * @brief Given a traffic flow, determine whether it has been processed - * or not. By processed, it checks to see whether the traffic flow has - * been routed. This function should be used before routing a traffic - * flow. - * - * @param traffic_flow_id A unique identifier that represents a traffic - * flow - * @return true Represents the case where the traffic flow has been - * processed - * @return false Represents the case where the traffic flow has not - * been processed - */ - bool get_traffic_flow_processed_status(NocTrafficFlowId traffic_flow_id); - - /** - * @brief Gets the number of unique router blocks in the - * clustered netlist that were used within the user provided - * traffic flows description. - * - * @return int The total number of unique routers used in - * the traffic flows provided by the user. - */ - int get_number_of_routers_used_in_traffic_flows(void); - - - // setters - - /** - * @brief Given a set of parameters that describe a traffic - * flow, create it an add it to the vector of traffic flows in the - * design. Additionally, the two router blocks involved have their - * ids stored to to keep track of all router blocks that are used - * in traffic flows. Finally, the newly created traffic flow is - * also added to a vector of traffic flows that are associated to both - * the source and sink routers of the flow. - * - * @param source_router_module_name A string that represents the - * name of the source router block in the traffic flow. THis is - * provided by the user. - * @param sink_router_module_name A string that represents the name - * of the sink router block in the traffic flow. This is provided by - * the user. - * @param source_router_cluster_id The source router block id that - * uniquely identifies this block in the clustered netlist. - * @param sink_router_cluster_id The sink router block id that - * uniquely identifier this block in the clusterd netlist. - * @param traffic_flow_bandwidth The size of the data transmission - * in this traffic flow (units of bps). - * @param traffic_flow_latency The maximum allowable delay between - * transmitting data at the source router and having it received - * at the sink router. - */ - void create_noc_traffic_flow(std::string source_router_module_name, std::string sink_router_module_name, ClusterBlockId source_router_cluster_id, ClusterBlockId sink_router_cluster_id, double traffic_flow_bandwidth, double traffic_flow_latency); - - /** - * @brief Set the status of a given traffic flow. The status indicates - * whether the traffic flow has been routed or not. - * - * @param traffic_flow_id A unique identifier that represents a traffic - * flow. - * @param status THe updated status of the traffic flow. True indicating - * that the traffic flow has been router and False indicating that - * the traffic flow has not been routed. - */ - void set_traffic_flow_status(NocTrafficFlowId traffic_flow_id, bool status); - - //utility functions - - /** - * @brief Determines the total number of traffic flows in - * the design and creates a vector to keep track of the traffic - * flows processed status. This function should be called after - * all the traffic flows have been created. The traffic flows are - * all initialized to being not processed. - * - */ - void finshed_noc_traffic_flows_setup(void); - - /** - * @brief Goes through the status of all traffic flows - * and sets them to being not processed. This should be - * used before each iteraition of placement. - * - */ - void reset_traffic_flows_processed_status(void); - - /** - * @brief Resets the class by clearning internal - * satastructures. - * - */ - void clear_traffic_flows(void); - - /** - * @brief Given a block from the clustered netlist, determine - * if the block is a router. This function should be used during - * each iteration of placement to check whether two swapped clusters - * are routers or not. - * - * @param block_id A unique identifier that represents a cluster - * block in the clustered netlist - * @return true The block is a router - * @return false THe block is not a router - */ - bool check_if_cluster_block_is_a_noc_router(ClusterBlockId block_id); - - /** - * @brief Writes out the NocTrafficFlows class information to a file. - * This includes printing out each internal datastructure information. - * - * @param file_name The name of the file that contains the NoC - * traffic flow information - */ - void echo_noc_traffic_flows(char* file_name); - +class NocTrafficFlows { + private: + /** contains all the traffic flows provided by the user and their information*/ + vtr::vector noc_traffic_flows; + + /** + * A traffic flow has a source and destination router associated to it. So when either the source or destination router for a given flow is moved, we need to find a new route between them. + * + * Therefore, during placement if two router blocks are swapped, then the only traffic flows we need to re-route are the flows where the two routers are either the source or destination routers of those flows. + * + * The datastructures below store all traffic flows for each router where the router is a source for the traffic flow. Similarily, there is a another datastructure where all traffic flows are stored for each router where the router is a sink for the traffic flow. The routers are indexed by their ClusterBlockId. + * + * This is done so that the traffic that need to be re-routed during placement can be quickly found. + */ + std::unordered_map> source_router_associated_traffic_flows; + std::unordered_map> sink_router_associated_traffic_flows; + + /** keeps track of which traffic flows have already been processed. + * By processed, it tracks whether a traffic flow has been routed or + * not. During placement, two routers can be swapped, if the + * two routers share a traffic flow, then the shared traffic flow + * will be routed twice, where it will routed when processing the + * flows associated to the source router and then again when + * processing the flows associated to the sink router. By using the + * datastructure below, if whether a traffic flow is processed or not + * is tracked, then we can ensure that no traffic flows are routed + * more than once by referring to this datastructure. + */ + vtr::vector processed_traffic_flows; + + /** contains the cluster ID of all unique router modules in the design. + * and can quickly determine whether a given cluster in the netlist + * is a router block or not. whenever placement swaps two clusters, we + * need to check if the clusters a router blocks or not, this is needed + * so that we can deterimine if we need to re-route traffic flows. The + * datastructure below can be used to quickly identify whether a given + * cluster that was swapped furing palcement is a router block or not.*/ + std::unordered_set noc_router_blocks; + + // private functions + + /** + * @brief Given a router that is either a source or sink of + * a traffic flow, the corresponding traffic flow is added + * to a vector of traffic flows associated to the router. + * + * @param traffic_flow_id A unique id that represents a traffic flow. + * @param associated_router_id A ClusterblockId that represents a + * router block. + * @param router_associated_traffic_flows A datastructure that stores + * a vector of traffic flows for a given router block where the traffic + * flows have the router as a source or sink within the flow. + * + */ + void add_traffic_flow_to_associated_routers(NocTrafficFlowId traffic_flow_id, ClusterBlockId associated_router_id, std::unordered_map>& router_associated_traffic_flows); + + /** + * @brief Given a router block in the clustered netlist, store it + * internally. + * + * @param router_block_id A unique identifier that rerpesents a router block in the clustered netlist. This id will be stored. + */ + void add_router_to_block_set(ClusterBlockId router_block_id); + + public: + NocTrafficFlows(); + + //getters + + /** + * @brief Given a unique id of a traffic flow (t_noc_traffic_flow) + * retrieve it from the vector of all traffic flows in the design. The + * retrieved traffic flow cannot be modified but can be used to + * retireve information such as the routers involved. + * + * @param traffic_flow_id The unique identifier (NocTrafficFlowId) + * of the traffic flow to retrieve. + * @return const t_noc_traffic_flow& The traffic flow represented by + * the provided identifier. + */ + const t_noc_traffic_flow& get_single_noc_traffic_flow(NocTrafficFlowId traffic_flow_id) const; + + /** + * @brief Get a vector of all traffic flows that have a given router + * block in the clustered netlist as the source (starting point) in the + * flow. + * + * @param source_router_id A unique identifier that represents the + * a router block in the clustered netlist. This router block will + * be the source router in the retrieved traffic flow. + * @return const std::vector* A vector of traffic + * flows that have the input router block parameter as the source in the + * flow. + */ + const std::vector* get_traffic_flows_associated_to_source_router(ClusterBlockId source_router_id) const; + + /** + * @brief Get a vector of all traffic flows that have a given router + * block in the clustered netlist as the sink (end point) in the + * flow. + * + * @param sink_router_id A unique identifier that represents the + * a router block in the clustered netlist. This router block will + * be the sink router in the retrieved traffic flow. + * @return const std::vector* A vector of traffic + * flows that have the input router block parameter as the sink in the + * flow. + */ + const std::vector* get_traffic_flows_associated_to_sink_router(ClusterBlockId sink_router_id) const; + + /** + * @brief Given a traffic flow, determine whether it has been processed + * or not. By processed, it checks to see whether the traffic flow has + * been routed. This function should be used before routing a traffic + * flow. + * + * @param traffic_flow_id A unique identifier that represents a traffic + * flow + * @return true Represents the case where the traffic flow has been + * processed + * @return false Represents the case where the traffic flow has not + * been processed + */ + bool get_traffic_flow_processed_status(NocTrafficFlowId traffic_flow_id); + + /** + * @brief Gets the number of unique router blocks in the + * clustered netlist that were used within the user provided + * traffic flows description. + * + * @return int The total number of unique routers used in + * the traffic flows provided by the user. + */ + int get_number_of_routers_used_in_traffic_flows(void); + + // setters + + /** + * @brief Given a set of parameters that describe a traffic + * flow, create it an add it to the vector of traffic flows in the + * design. Additionally, the two router blocks involved have their + * ids stored to to keep track of all router blocks that are used + * in traffic flows. Finally, the newly created traffic flow is + * also added to a vector of traffic flows that are associated to both + * the source and sink routers of the flow. + * + * @param source_router_module_name A string that represents the + * name of the source router block in the traffic flow. THis is + * provided by the user. + * @param sink_router_module_name A string that represents the name + * of the sink router block in the traffic flow. This is provided by + * the user. + * @param source_router_cluster_id The source router block id that + * uniquely identifies this block in the clustered netlist. + * @param sink_router_cluster_id The sink router block id that + * uniquely identifier this block in the clusterd netlist. + * @param traffic_flow_bandwidth The size of the data transmission + * in this traffic flow (units of bps). + * @param traffic_flow_latency The maximum allowable delay between + * transmitting data at the source router and having it received + * at the sink router. + */ + void create_noc_traffic_flow(std::string source_router_module_name, std::string sink_router_module_name, ClusterBlockId source_router_cluster_id, ClusterBlockId sink_router_cluster_id, double traffic_flow_bandwidth, double traffic_flow_latency); + + /** + * @brief Set the status of a given traffic flow. The status indicates + * whether the traffic flow has been routed or not. + * + * @param traffic_flow_id A unique identifier that represents a traffic + * flow. + * @param status THe updated status of the traffic flow. True indicating + * that the traffic flow has been router and False indicating that + * the traffic flow has not been routed. + */ + void set_traffic_flow_status(NocTrafficFlowId traffic_flow_id, bool status); + + //utility functions + + /** + * @brief Determines the total number of traffic flows in + * the design and creates a vector to keep track of the traffic + * flows processed status. This function should be called after + * all the traffic flows have been created. The traffic flows are + * all initialized to being not processed. + * + */ + void finshed_noc_traffic_flows_setup(void); + + /** + * @brief Goes through the status of all traffic flows + * and sets them to being not processed. This should be + * used before each iteraition of placement. + * + */ + void reset_traffic_flows_processed_status(void); + + /** + * @brief Resets the class by clearning internal + * satastructures. + * + */ + void clear_traffic_flows(void); + + /** + * @brief Given a block from the clustered netlist, determine + * if the block is a router. This function should be used during + * each iteration of placement to check whether two swapped clusters + * are routers or not. + * + * @param block_id A unique identifier that represents a cluster + * block in the clustered netlist + * @return true The block is a router + * @return false THe block is not a router + */ + bool check_if_cluster_block_is_a_noc_router(ClusterBlockId block_id); + + /** + * @brief Writes out the NocTrafficFlows class information to a file. + * This includes printing out each internal datastructure information. + * + * @param file_name The name of the file that contains the NoC + * traffic flow information + */ + void echo_noc_traffic_flows(char* file_name); }; - #endif \ No newline at end of file diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index 83379dfc97b..d9a79cb5cd7 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -1,11 +1,9 @@ #include "read_xml_noc_traffic_flows_file.h" - -void read_xml_noc_traffic_flows_file(const char* noc_flows_file){ - +void read_xml_noc_traffic_flows_file(const char* noc_flows_file) { // start by checking that the provided file is a ".flows" file - if (vtr::check_file_name_extension(noc_flows_file, ".flows") == false){ + if (vtr::check_file_name_extension(noc_flows_file, ".flows") == false) { VPR_FATAL_ERROR(VPR_ERROR_OTHER, "NoC traffic flows file '%s' has an unknown extension. Expecting .flows for NoC traffic flow files.", noc_flows_file); } @@ -27,7 +25,6 @@ void read_xml_noc_traffic_flows_file(const char* noc_flows_file){ // go through the file try { - // load the file loc_data = pugiutil::load_xml(doc, noc_flows_file); @@ -38,14 +35,13 @@ void read_xml_noc_traffic_flows_file(const char* noc_flows_file){ pugiutil::expect_only_children(traffic_flows_tag, {"single_flow"}, loc_data); // process the individual traffic flows below - for (pugi::xml_node single_flow : traffic_flows_tag.children()){ + for (pugi::xml_node single_flow : traffic_flows_tag.children()) { // current tag is a valid "flow" so process it process_single_flow(single_flow, loc_data, cluster_ctx, noc_ctx, noc_router_tile_type); } - } - catch(pugiutil::XmlError& e) { // used for identifying any of the xml parsing library errors - + } catch (pugiutil::XmlError& e) { // used for identifying any of the xml parsing library errors + vpr_throw(VPR_ERROR_OTHER, noc_flows_file, e.line(), e.what()); } @@ -60,23 +56,21 @@ void read_xml_noc_traffic_flows_file(const char* noc_flows_file){ } return; - } -void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type){ - +void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type) { // contains all traffic flows NocTrafficFlows* noc_traffic_flow_storage = &noc_ctx.noc_traffic_flows_storage; - // an accepted set of attributes for the single flow tag + // an accepted list of attributes for the single flow tag std::vector expected_single_flow_attributes = {"src", "dst", "bandwidth", "latency_cons"}; // check that only the accepted single flow attributes are found in the tag pugiutil::expect_only_attributes(single_flow_tag, expected_single_flow_attributes, loc_data); - + // store the names of the routers part of this traffic flow std::string source_router_module_name = pugiutil::get_attribute(single_flow_tag, "src", loc_data, pugiutil::REQUIRED).as_string(); - + std::string sink_router_module_name = pugiutil::get_attribute(single_flow_tag, "dst", loc_data, pugiutil::REQUIRED).as_string(); //verify whether the router module names are legal @@ -98,127 +92,107 @@ void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_dat verify_traffic_flow_properties(traffic_flow_bandwidth, max_traffic_flow_latency, single_flow_tag, loc_data); // make sure that the current traffic flow was not added previously - check_for_duplicate_traffic_flow(source_router_id, sink_router_id,single_flow_tag, loc_data, *noc_traffic_flow_storage); + check_for_duplicate_traffic_flow(source_router_id, sink_router_id, single_flow_tag, loc_data, *noc_traffic_flow_storage); // The current flow information is legal, so store it noc_traffic_flow_storage->create_noc_traffic_flow(source_router_module_name, sink_router_module_name, source_router_id, sink_router_id, traffic_flow_bandwidth, max_traffic_flow_latency); return; - } -void verify_traffic_flow_router_modules(std::string source_router_name, std::string sink_router_name, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data){ - +void verify_traffic_flow_router_modules(std::string source_router_name, std::string sink_router_name, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data) { // check that the router module names were legal - if ((source_router_name == "") || (sink_router_name == "")){ - + if ((source_router_name == "") || (sink_router_name == "")) { vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "Invalid names for the source and sink NoC router modules."); - }// check if the source and sink routers have the same name - else if (source_router_name == sink_router_name) - { + } // check if the source and sink routers have the same name + else if (source_router_name == sink_router_name) { // Cannot have the source and sink routers have the same name (they need to be different). A flow cant go to a single router. vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "Source and sink NoC routers cannot be the same modules."); } return; - } -void verify_traffic_flow_properties(double traffic_flow_bandwidth, double max_traffic_flow_latency, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data){ - +void verify_traffic_flow_properties(double traffic_flow_bandwidth, double max_traffic_flow_latency, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data) { // check that the bandwidth and max latency are positive values - if ((traffic_flow_bandwidth < 0) || (max_traffic_flow_latency < 0)){ - + if ((traffic_flow_bandwidth < 0) || (max_traffic_flow_latency < 0)) { vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "The traffic flow bandwidth and latency constraints need to be positive values."); } return; } -ClusterBlockId get_router_module_cluster_id(std::string router_module_name, const ClusteringContext& cluster_ctx, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, t_physical_tile_type_ptr noc_router_tile_type){ - +ClusterBlockId get_router_module_cluster_id(std::string router_module_name, const ClusteringContext& cluster_ctx, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, t_physical_tile_type_ptr noc_router_tile_type) { ClusterBlockId router_module_id = ClusterBlockId::INVALID(); // get the subtiles of the noc router physical type - const std::vector* noc_router_subtiles = &noc_router_tile_type->sub_tiles; + const std::vector* noc_router_subtiles = &noc_router_tile_type->sub_tiles; /* - iterate through all the logical block types that can be placed on the - NoC router tile. Check if the there is a cluster block that matches - the input router module name and is one of the supported logical - block types. - */ - for (auto sub_tile = noc_router_subtiles->begin(); sub_tile != noc_router_subtiles->end(); sub_tile++){ - + * iterate through all the logical block types that can be placed on the + * NoC router tile. Check if the there is a cluster block that matches + * the input router module name and is one of the supported logical + * block types. + */ + for (auto sub_tile = noc_router_subtiles->begin(); sub_tile != noc_router_subtiles->end(); sub_tile++) { //get the logical types the current tile supports const std::vector* supported_noc_logical_types = &sub_tile->equivalent_sites; // go through each logical type and check if there is a cluster block // of that type that also matches the input module name - for (auto logical_type = supported_noc_logical_types->begin(); logical_type != supported_noc_logical_types->end(); logical_type++){ - - try{ + for (auto logical_type = supported_noc_logical_types->begin(); logical_type != supported_noc_logical_types->end(); logical_type++) { + try { router_module_id = cluster_ctx.clb_nlist.find_block_with_matching_name(router_module_name, *logical_type); - }catch(const std::regex_error& error){ + } catch (const std::regex_error& error) { // if there was an error with matching the regex string,report it to the user here vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), error.what()); } // found a block for the current logical type, so exit - if (router_module_id != ClusterBlockId::INVALID()){ + if (router_module_id != ClusterBlockId::INVALID()) { break; } - } // found a block for the current sub tile, so exit - if (router_module_id != ClusterBlockId::INVALID()){ + if (router_module_id != ClusterBlockId::INVALID()) { break; } - } // check if a valid block id was found - if (router_module_id == ClusterBlockId::INVALID()){ + if (router_module_id == ClusterBlockId::INVALID()) { // if here then the module did not exist in the design, so throw an error vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "The router module '%s' does not exist in the design.", router_module_name.c_str()); } return router_module_id; - } -void check_traffic_flow_router_module_type(std::string router_module_name, ClusterBlockId router_module_id, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, t_physical_tile_type_ptr noc_router_tile_type){ - +void check_traffic_flow_router_module_type(std::string router_module_name, ClusterBlockId router_module_id, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, t_physical_tile_type_ptr noc_router_tile_type) { // get the logical type of the provided router module t_logical_block_type_ptr router_module_logical_type = cluster_ctx.clb_nlist.block_type(router_module_id); /* - Check whether the current router modules logical type is compatible - with the physical type of a noc router (can the module be placed on a - noc router tile on the FPGA device). If not then this module is not a router so throw an error. - */ - if (!is_tile_compatible(noc_router_tile_type, router_module_logical_type)){ - + * Check whether the current router modules logical type is compatible + * with the physical type of a noc router (can the module be placed on a + * noc router tile on the FPGA device). If not then this module is not a router so throw an error. + */ + if (!is_tile_compatible(noc_router_tile_type, router_module_logical_type)) { vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "The supplied module name '%s' is not a NoC router.", router_module_name.c_str()); } - - return; + return; } -t_physical_tile_type_ptr get_physical_type_of_noc_router_tile(const DeviceContext& device_ctx, NocContext& noc_ctx){ - +t_physical_tile_type_ptr get_physical_type_of_noc_router_tile(const DeviceContext& device_ctx, NocContext& noc_ctx) { // get a reference to a single physical noc router auto physical_noc_router = noc_ctx.noc_model.get_noc_routers().begin(); - //Using the routers grid position go to the device and identify the physical type of the tile located there. return device_ctx.grid[physical_noc_router->get_router_grid_position_x()][physical_noc_router->get_router_grid_position_y()].type; - } -bool check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type, std::string noc_flows_file){ - +bool check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type, std::string noc_flows_file) { bool result = true; // contains the number of all the noc router blocks in the design @@ -229,55 +203,44 @@ bool check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& no const std::vector* noc_router_subtiles = &(noc_router_tile_type->sub_tiles); /* - Go through the router subtiles and get the router logical block types the subtiles support. Then determine how many of each router logical block types there are in the clustered netlist. The accumulated sum of all these clusters is the total number of router blocks in the design. */ - for (auto subtile = noc_router_subtiles->begin(); subtile != noc_router_subtiles->end(); subtile++){ - - for (auto router_logical_block = subtile->equivalent_sites.begin(); router_logical_block != subtile->equivalent_sites.end();router_logical_block++){ - + * Go through the router subtiles and get the router logical block types the subtiles support. Then determine how many of each router logical block types there are in the clustered netlist. The accumulated sum of all these clusters is the total number of router blocks in the design. */ + for (auto subtile = noc_router_subtiles->begin(); subtile != noc_router_subtiles->end(); subtile++) { + for (auto router_logical_block = subtile->equivalent_sites.begin(); router_logical_block != subtile->equivalent_sites.end(); router_logical_block++) { // get the number of logical blocks in the design of the current logical block type number_of_router_blocks_in_design += clustered_netlist_stats.num_blocks_type[(*router_logical_block)->index]; - } } /* - Every router block in the design needs to be part of a traffic flow. There can never be a router that isnt part of a traffic flow, other wise the router is doing nothing. So check that the number of unique routers in all traffic flows equals the number of router blocks in the design, otherwise throw an warning to let the user know. If there aren't - any traffic flows for any routers then the NoC is not being used. - */ - if (noc_ctx.noc_traffic_flows_storage.get_number_of_routers_used_in_traffic_flows() != number_of_router_blocks_in_design){ - + * Every router block in the design needs to be part of a traffic flow. There can never be a router that isnt part of a traffic flow, other wise the router is doing nothing. So check that the number of unique routers in all traffic flows equals the number of router blocks in the design, otherwise throw an warning to let the user know. If there aren't + * any traffic flows for any routers then the NoC is not being used. + */ + if (noc_ctx.noc_traffic_flows_storage.get_number_of_routers_used_in_traffic_flows() != number_of_router_blocks_in_design) { VTR_LOG_WARN("NoC traffic flows file '%s' does not contain all router modules in the design. Every router module in the design must be part of a traffic flow (communicating to another router). Otherwise the router is unused.\n", noc_flows_file.c_str()); result = false; } return result; - } -void check_for_duplicate_traffic_flow(ClusterBlockId source_router_id, ClusterBlockId sink_router_id, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const NocTrafficFlows& noc_traffic_flow_storage){ - - const std::vector* associated_traffic_flows_to_source_router = noc_traffic_flow_storage.get_traffic_flows_associated_to_source_router(source_router_id); +void check_for_duplicate_traffic_flow(ClusterBlockId source_router_id, ClusterBlockId sink_router_id, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const NocTrafficFlows& noc_traffic_flow_storage) { + const std::vector* associated_traffic_flows_to_source_router = noc_traffic_flow_storage.get_traffic_flows_associated_to_source_router(source_router_id); // make sure the router is associated to atleast one traffic flow - if (associated_traffic_flows_to_source_router != nullptr){ - + if (associated_traffic_flows_to_source_router != nullptr) { /* - Go through all the traffic flows that exist with the current source router and check to see if any of those traffic flows have a sink router - that matches current sink router. When this happens then the two traffic flows are duplicates and an error should be thrown. - */ - for (auto traffic_flow_id = associated_traffic_flows_to_source_router->begin(); traffic_flow_id != associated_traffic_flows_to_source_router->end(); traffic_flow_id++){ - + * Go through all the traffic flows that exist with the current source router and check to see if any of those traffic flows have a sink router + * that matches current sink router. When this happens then the two traffic flows are duplicates and an error should be thrown. + */ + for (auto traffic_flow_id = associated_traffic_flows_to_source_router->begin(); traffic_flow_id != associated_traffic_flows_to_source_router->end(); traffic_flow_id++) { ClusterBlockId curr_sink_router_id = noc_traffic_flow_storage.get_single_noc_traffic_flow(*traffic_flow_id).sink_router_cluster_id; // compare the current traffic flows sink router with the new traffic flows sink router - if (curr_sink_router_id == sink_router_id){ - + if (curr_sink_router_id == sink_router_id) { // the routers are the same, so this is a duplicate traffic flow. thrown an error vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "The supplied traffic flow is a duplicate of another traffic flow (contain the same source and sink routers). Duplicate traffic flows are not allowed."); - } - } } diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.h b/vpr/src/noc/read_xml_noc_traffic_flows_file.h index 8b6c3482649..30ad4c37ea2 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.h +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.h @@ -96,8 +96,7 @@ void verify_traffic_flow_router_modules(std::string source_router_name, std::str * @param single_flow_tag A xml tag that contains the traffic flow information * @param loc_data Contains location data about the current line in the xml file */ -void -verify_traffic_flow_properties(double traffic_flow_bandwidth, double max_traffic_flow_latency, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data); +void verify_traffic_flow_properties(double traffic_flow_bandwidth, double max_traffic_flow_latency, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data); /** * @brief Given a router module name in the design, retrieve the @@ -188,5 +187,4 @@ bool check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& no */ void check_for_duplicate_traffic_flow(ClusterBlockId source_router_id, ClusterBlockId sink_router_id, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const NocTrafficFlows& noc_traffic_flow_storage); - #endif \ No newline at end of file diff --git a/vpr/test/test_clustered_netlist.cpp b/vpr/test/test_clustered_netlist.cpp index 80608f443fe..88a4afc641a 100644 --- a/vpr/test/test_clustered_netlist.cpp +++ b/vpr/test/test_clustered_netlist.cpp @@ -1,7 +1,6 @@ #include "catch2/catch_test_macros.hpp" #include "catch2/matchers/catch_matchers_all.hpp" - #include "clustered_netlist.h" #include @@ -10,129 +9,121 @@ namespace { - TEST_CASE("test_find_block_with_matching_name", "[vpr_clustered_netlist]") { - - // create some sample logical types that we will use when creating new cluster blocks - t_logical_block_type router_block; - char router[] = "router"; - router_block.name = router; - t_logical_block_type_ptr router_ref = &router_block; - - t_logical_block_type i_o_block; - char i_o[] = "IO"; - i_o_block.name = i_o; - t_logical_block_type_ptr i_o_ref = &i_o_block; - - t_pb router_pb; - t_pb i_o_pb; - - // datastructure to keep track of blocks name to its id - std::map block_id_from_name; - - // need to create the cluster netlist object that will hold the blocks - ClusteredNetlist test_netlist("test_netlist", "77"); - - // creating some names for i_o_blocks - // These will act as fillers to make sure that the matching function correctly handles a netlist with different types of blocks - - char io_port_one[] = "io_port_one"; - char io_port_two[] = "io_port_two"; - char io_port_three[] = "io_port_three"; - char io_port_four[] = "io_port_four"; - - // add the io blocks to the netlist - block_id_from_name.emplace(io_port_one, test_netlist.create_block(io_port_one, &i_o_pb, i_o_ref)); - block_id_from_name.emplace(io_port_two, test_netlist.create_block(io_port_two, &i_o_pb, i_o_ref)); - block_id_from_name.emplace(io_port_three, test_netlist.create_block(io_port_three, &i_o_pb, i_o_ref)); - block_id_from_name.emplace(io_port_four, test_netlist.create_block(io_port_four, &i_o_pb, i_o_ref)); - - SECTION("Test find_block_with_matching_name when the input string is the instance name of the block"){ - - // create names for some router blocks - char router_one[] = "router:noc_router_one"; - char router_two[] = "router:noc_router_two"; - char router_three[] = "router:noc_router_three"; - char router_four[] = "router:noc_router_four"; - - // add the routers - block_id_from_name.emplace(router_one, test_netlist.create_block(router_one, &router_pb, router_ref)); - block_id_from_name.emplace(router_two, test_netlist.create_block(router_two, &router_pb, router_ref)); - block_id_from_name.emplace(router_three, test_netlist.create_block(router_three, &router_pb, router_ref)); - block_id_from_name.emplace(router_four, test_netlist.create_block(router_four, &router_pb, router_ref)); - - // now find a block just knowing its instance name - // the test names will have an arbritary number of characters in front and then the name of the instance and then maybe some characters after - std::string test_router_module_name = "(.*)(noc_router_one)(.*)"; - - //get the block id - ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, router_ref); - - // now check the block id with what we expect to be - REQUIRE((size_t)(block_id_from_name.find("router:noc_router_one")->second) == (size_t)test_router_id); - - } - SECTION("Test find_block_with_matching_name when the input string is a unique port name connecting to the block"){ - - // create the name of the router blocks - // the idea here is to create test cases where all the names of the blocks have the same block name but have a unique component identifying them - // this is a name identifying the net - char router_one[] = "router:new_router|q_a[1]"; - char router_two[] = "router:new_router|q_a[2]"; - char router_three[] = "router:new_router|q_a[3]"; - char router_four[] = "router:new_router|q_a[4]"; - - // add the routers - block_id_from_name.emplace(router_one, test_netlist.create_block(router_one, &router_pb, router_ref)); - block_id_from_name.emplace(router_two, test_netlist.create_block(router_two, &router_pb, router_ref)); - block_id_from_name.emplace(router_three, test_netlist.create_block(router_three, &router_pb, router_ref)); - block_id_from_name.emplace(router_four, test_netlist.create_block(router_four, &router_pb, router_ref)); - - // now find a block just knowing its unique identifier - // the test names will have an arbritary number of characters in front of them and the unique identifier at the end - std::string test_router_module_name = "(.*)(q_a\\[2\\])(.*)"; - - //get the block id - ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, router_ref); - - // now check the block id with what we expect to be - REQUIRE((size_t)(block_id_from_name.find("router:new_router|q_a[2]")->second) == (size_t)test_router_id); - - } - SECTION("Test find_block_with_matching_name when multiple blocks match the input string "){ - - // create the name of the router blocks - char router_one[] = "router:noc_router_one|flit_out_two[0]~reg0"; - char router_two[] = "router:noc_router_two|flit_out_two[0]~reg0"; - char router_three[] = "router:noc_router_three|flit_out_two[0]~reg0"; - char router_four[] = "router:noc_router_four|flit_out_two[0]~reg0"; - - // need to create another block of a different type that has the same name as one of the router blocks - char i_o_block_with_same_name[] = "io|router:noc_router_four|flit_out_two[0]~reg0"; - +TEST_CASE("test_find_block_with_matching_name", "[vpr_clustered_netlist]") { + // create some sample logical types that we will use when creating new cluster blocks + t_logical_block_type router_block; + char router[] = "router"; + router_block.name = router; + t_logical_block_type_ptr router_ref = &router_block; + + t_logical_block_type i_o_block; + char i_o[] = "IO"; + i_o_block.name = i_o; + t_logical_block_type_ptr i_o_ref = &i_o_block; + + t_pb router_pb; + t_pb i_o_pb; + + // datastructure to keep track of blocks name to its id + std::map block_id_from_name; + + // need to create the cluster netlist object that will hold the blocks + ClusteredNetlist test_netlist("test_netlist", "77"); + + // creating some names for i_o_blocks + // These will act as fillers to make sure that the matching function correctly handles a netlist with different types of blocks + + char io_port_one[] = "io_port_one"; + char io_port_two[] = "io_port_two"; + char io_port_three[] = "io_port_three"; + char io_port_four[] = "io_port_four"; + + // add the io blocks to the netlist + block_id_from_name.emplace(io_port_one, test_netlist.create_block(io_port_one, &i_o_pb, i_o_ref)); + block_id_from_name.emplace(io_port_two, test_netlist.create_block(io_port_two, &i_o_pb, i_o_ref)); + block_id_from_name.emplace(io_port_three, test_netlist.create_block(io_port_three, &i_o_pb, i_o_ref)); + block_id_from_name.emplace(io_port_four, test_netlist.create_block(io_port_four, &i_o_pb, i_o_ref)); + + SECTION("Test find_block_with_matching_name when the input string is the instance name of the block") { + // create names for some router blocks + char router_one[] = "router:noc_router_one"; + char router_two[] = "router:noc_router_two"; + char router_three[] = "router:noc_router_three"; + char router_four[] = "router:noc_router_four"; + + // add the routers + block_id_from_name.emplace(router_one, test_netlist.create_block(router_one, &router_pb, router_ref)); + block_id_from_name.emplace(router_two, test_netlist.create_block(router_two, &router_pb, router_ref)); + block_id_from_name.emplace(router_three, test_netlist.create_block(router_three, &router_pb, router_ref)); + block_id_from_name.emplace(router_four, test_netlist.create_block(router_four, &router_pb, router_ref)); + + // now find a block just knowing its instance name + // the test names will have an arbritary number of characters in front and then the name of the instance and then maybe some characters after + std::string test_router_module_name = "(.*)(noc_router_one)(.*)"; + + //get the block id + ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, router_ref); + + // now check the block id with what we expect to be + REQUIRE((size_t)(block_id_from_name.find("router:noc_router_one")->second) == (size_t)test_router_id); + } + SECTION("Test find_block_with_matching_name when the input string is a unique port name connecting to the block") { + // create the name of the router blocks + // the idea here is to create test cases where all the names of the blocks have the same block name but have a unique component identifying them + // this is a name identifying the net + char router_one[] = "router:new_router|q_a[1]"; + char router_two[] = "router:new_router|q_a[2]"; + char router_three[] = "router:new_router|q_a[3]"; + char router_four[] = "router:new_router|q_a[4]"; + + // add the routers + block_id_from_name.emplace(router_one, test_netlist.create_block(router_one, &router_pb, router_ref)); + block_id_from_name.emplace(router_two, test_netlist.create_block(router_two, &router_pb, router_ref)); + block_id_from_name.emplace(router_three, test_netlist.create_block(router_three, &router_pb, router_ref)); + block_id_from_name.emplace(router_four, test_netlist.create_block(router_four, &router_pb, router_ref)); + + // now find a block just knowing its unique identifier + // the test names will have an arbritary number of characters in front of them and the unique identifier at the end + std::string test_router_module_name = "(.*)(q_a\\[2\\])(.*)"; + + //get the block id + ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, router_ref); + + // now check the block id with what we expect to be + REQUIRE((size_t)(block_id_from_name.find("router:new_router|q_a[2]")->second) == (size_t)test_router_id); + } + SECTION("Test find_block_with_matching_name when multiple blocks match the input string ") { + // create the name of the router blocks + char router_one[] = "router:noc_router_one|flit_out_two[0]~reg0"; + char router_two[] = "router:noc_router_two|flit_out_two[0]~reg0"; + char router_three[] = "router:noc_router_three|flit_out_two[0]~reg0"; + char router_four[] = "router:noc_router_four|flit_out_two[0]~reg0"; - // add the routers and the IO block + // need to create another block of a different type that has the same name as one of the router blocks + char i_o_block_with_same_name[] = "io|router:noc_router_four|flit_out_two[0]~reg0"; - // add the IO block with a similiar name - block_id_from_name.emplace(i_o_block_with_same_name, test_netlist.create_block(i_o_block_with_same_name, &i_o_pb, i_o_ref)); + // add the routers and the IO block - // add routers - block_id_from_name.emplace(router_one, test_netlist.create_block(router_one, &router_pb, router_ref)); - block_id_from_name.emplace(router_two, test_netlist.create_block(router_two, &router_pb, router_ref)); - block_id_from_name.emplace(router_three, test_netlist.create_block(router_three, &router_pb, router_ref)); - block_id_from_name.emplace(router_four, test_netlist.create_block(router_four, &router_pb, router_ref)); + // add the IO block with a similiar name + block_id_from_name.emplace(i_o_block_with_same_name, test_netlist.create_block(i_o_block_with_same_name, &i_o_pb, i_o_ref)); - // now find a block just knowing its unique identifier - // THe identifier we use will match with multiple blocks in this test case - std::string test_router_module_name = "(.*)(noc_router_four\\|flit_out_two\\[0\\]~reg0)$"; + // add routers + block_id_from_name.emplace(router_one, test_netlist.create_block(router_one, &router_pb, router_ref)); + block_id_from_name.emplace(router_two, test_netlist.create_block(router_two, &router_pb, router_ref)); + block_id_from_name.emplace(router_three, test_netlist.create_block(router_three, &router_pb, router_ref)); + block_id_from_name.emplace(router_four, test_netlist.create_block(router_four, &router_pb, router_ref)); - //get the block id - ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, router_ref); + // now find a block just knowing its unique identifier + // THe identifier we use will match with multiple blocks in this test case + std::string test_router_module_name = "(.*)(noc_router_four\\|flit_out_two\\[0\\]~reg0)$"; - // since we passed in the router logical type, we expect the router block to be the returned id + //get the block id + ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, router_ref); - // now check the block id with what we expect to be - REQUIRE((size_t)(block_id_from_name.find("router:noc_router_four|flit_out_two[0]~reg0")->second) == (size_t)test_router_id); + // since we passed in the router logical type, we expect the router block to be the returned id - } + // now check the block id with what we expect to be + REQUIRE((size_t)(block_id_from_name.find("router:noc_router_four|flit_out_two[0]~reg0")->second) == (size_t)test_router_id); } -} \ No newline at end of file +} +} // namespace \ No newline at end of file diff --git a/vpr/test/test_noc_traffic_flows.cpp b/vpr/test/test_noc_traffic_flows.cpp index a8c8cc7ac16..d5afa360164 100644 --- a/vpr/test/test_noc_traffic_flows.cpp +++ b/vpr/test/test_noc_traffic_flows.cpp @@ -8,164 +8,143 @@ namespace { - TEST_CASE("test_adding_traffic_flows", "[vpr_noc_traffic_flows]") { - - // the traffic flows datastructure and reset it - NocTrafficFlows traffic_flow_storage; - traffic_flow_storage.clear_traffic_flows(); - - // parameters for each traffic flow - std::string source_router_name = "test_1"; - std::string sink_router_nanme = "test_2"; - double traffic_flow_bandwidth = 200; - double traffic_flow_latency = 10; - ClusterBlockId source_router_id; - ClusterBlockId sink_router_id; - NocTrafficFlowId curr_flow_id; - // setup the test data - - // create all the routers - std::vector golden_router_blocks_list; - for (int router = 0; router < NUM_OF_ROUTERS; router++){ - golden_router_blocks_list.push_back((ClusterBlockId)router); - } - - // total traffic flows will be NUM_OF_ROUTERS * (NUM_OF_ROUTERS - 1) - // create the traffic flows - std::vector golden_traffic_flow_list; - vtr::vector> golden_list_of_associated_links_source_router; - golden_list_of_associated_links_source_router.resize(NUM_OF_ROUTERS); +TEST_CASE("test_adding_traffic_flows", "[vpr_noc_traffic_flows]") { + // the traffic flows datastructure and reset it + NocTrafficFlows traffic_flow_storage; + traffic_flow_storage.clear_traffic_flows(); + + // parameters for each traffic flow + std::string source_router_name = "test_1"; + std::string sink_router_nanme = "test_2"; + double traffic_flow_bandwidth = 200; + double traffic_flow_latency = 10; + ClusterBlockId source_router_id; + ClusterBlockId sink_router_id; + NocTrafficFlowId curr_flow_id; + // setup the test data + + // create all the routers + std::vector golden_router_blocks_list; + for (int router = 0; router < NUM_OF_ROUTERS; router++) { + golden_router_blocks_list.push_back((ClusterBlockId)router); + } - vtr::vector> golden_list_of_associated_links_sink_router; - golden_list_of_associated_links_sink_router.resize(NUM_OF_ROUTERS); + // total traffic flows will be NUM_OF_ROUTERS * (NUM_OF_ROUTERS - 1) + // create the traffic flows + std::vector golden_traffic_flow_list; + vtr::vector> golden_list_of_associated_links_source_router; + golden_list_of_associated_links_source_router.resize(NUM_OF_ROUTERS); - for (int router = 0; router < NUM_OF_ROUTERS; router++){ + vtr::vector> golden_list_of_associated_links_sink_router; + golden_list_of_associated_links_sink_router.resize(NUM_OF_ROUTERS); - for (int second_router = 0; second_router < NUM_OF_ROUTERS; second_router++){ - - // dont want the case where the source and destination routers are the same - if (router == second_router){ - continue; - } - - source_router_id = (ClusterBlockId)router; - sink_router_id = (ClusterBlockId)second_router; + for (int router = 0; router < NUM_OF_ROUTERS; router++) { + for (int second_router = 0; second_router < NUM_OF_ROUTERS; second_router++) { + // dont want the case where the source and destination routers are the same + if (router == second_router) { + continue; + } - // need to match how the test function does it - golden_traffic_flow_list.emplace_back(source_router_name, sink_router_nanme, source_router_id, sink_router_id, traffic_flow_bandwidth, traffic_flow_latency); + source_router_id = (ClusterBlockId)router; + sink_router_id = (ClusterBlockId)second_router; - curr_flow_id = (NocTrafficFlowId)(golden_traffic_flow_list.size() - 1); + // need to match how the test function does it + golden_traffic_flow_list.emplace_back(source_router_name, sink_router_nanme, source_router_id, sink_router_id, traffic_flow_bandwidth, traffic_flow_latency); - // add the traffic flows to the source and sink routers - golden_list_of_associated_links_source_router[source_router_id].emplace_back(curr_flow_id); - golden_list_of_associated_links_sink_router[sink_router_id].emplace_back(curr_flow_id); + curr_flow_id = (NocTrafficFlowId)(golden_traffic_flow_list.size() - 1); - } + // add the traffic flows to the source and sink routers + golden_list_of_associated_links_source_router[source_router_id].emplace_back(curr_flow_id); + golden_list_of_associated_links_sink_router[sink_router_id].emplace_back(curr_flow_id); } - - // finished settting up all the golden information, so now perform the tests - SECTION("Verifying that all created traffic flows and their related information are stored correctly."){ - - // add all the traffic flows to the datastructure - for (int router = 0; router < NUM_OF_ROUTERS; router++){ - - for (int second_router = 0; second_router < NUM_OF_ROUTERS; second_router++){ - - // dont want the case where the source and destination routers are the same - if (router == second_router){ - continue; - } - - source_router_id = (ClusterBlockId)router; - sink_router_id = (ClusterBlockId)second_router; - - // create and add the traffic flow - traffic_flow_storage.create_noc_traffic_flow(source_router_name, sink_router_nanme, source_router_id, sink_router_id, traffic_flow_bandwidth, traffic_flow_latency); + } + // finished settting up all the golden information, so now perform the tests + SECTION("Verifying that all created traffic flows and their related information are stored correctly.") { + // add all the traffic flows to the datastructure + for (int router = 0; router < NUM_OF_ROUTERS; router++) { + for (int second_router = 0; second_router < NUM_OF_ROUTERS; second_router++) { + // dont want the case where the source and destination routers are the same + if (router == second_router) { + continue; } - } - - int size_of_router_block_list = golden_router_blocks_list.size(); - - // check the set of routers first to see that they were all added properly - for (int router = 0; router < size_of_router_block_list; router++){ - // every router in the golden list needs to exist in the traffic flow datastructure (this also tests cases where a router was added multiple times, this shouldnt affect it) - REQUIRE(traffic_flow_storage.check_if_cluster_block_is_a_noc_router(golden_router_blocks_list[router]) == true); - - } - - int size_of_traffic_flow_list = golden_traffic_flow_list.size(); - // check the traffic flows (make sure they are correct) - for (int traffic_flow = 0; traffic_flow < size_of_traffic_flow_list; traffic_flow++){ - - curr_flow_id = (NocTrafficFlowId)traffic_flow; - t_noc_traffic_flow curr_traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(curr_flow_id); - - // make sure that the source and destination routers match the golden set - REQUIRE(curr_traffic_flow.source_router_cluster_id == golden_traffic_flow_list[traffic_flow].source_router_cluster_id); - REQUIRE(curr_traffic_flow.sink_router_cluster_id == golden_traffic_flow_list[traffic_flow].sink_router_cluster_id); + source_router_id = (ClusterBlockId)router; + sink_router_id = (ClusterBlockId)second_router; + // create and add the traffic flow + traffic_flow_storage.create_noc_traffic_flow(source_router_name, sink_router_nanme, source_router_id, sink_router_id, traffic_flow_bandwidth, traffic_flow_latency); } + } - int size_of_associated_flows_for_source_routers = golden_list_of_associated_links_source_router.size(); - // make sure that the correct traffic flows are added to each router when it is a source - for (int source_router = 0; source_router < size_of_associated_flows_for_source_routers;source_router++){ - - source_router_id = (ClusterBlockId)source_router; - - int size_of_current_source_router_associated_traffic_flows = golden_list_of_associated_links_source_router[source_router_id].size(); - + int size_of_router_block_list = golden_router_blocks_list.size(); - const std::vector* associated_traffic_flows_to_source_router = traffic_flow_storage.get_traffic_flows_associated_to_source_router(source_router_id); + // check the set of routers first to see that they were all added properly + for (int router = 0; router < size_of_router_block_list; router++) { + // every router in the golden list needs to exist in the traffic flow datastructure (this also tests cases where a router was added multiple times, this shouldnt affect it) + REQUIRE(traffic_flow_storage.check_if_cluster_block_is_a_noc_router(golden_router_blocks_list[router]) == true); + } - for (int source_router_traffic_flow = 0; source_router_traffic_flow < size_of_current_source_router_associated_traffic_flows; source_router_traffic_flow++){ + int size_of_traffic_flow_list = golden_traffic_flow_list.size(); - REQUIRE((size_t)golden_list_of_associated_links_source_router[source_router_id][source_router_traffic_flow] == (size_t)(*associated_traffic_flows_to_source_router)[source_router_traffic_flow]); - } - } + // check the traffic flows (make sure they are correct) + for (int traffic_flow = 0; traffic_flow < size_of_traffic_flow_list; traffic_flow++) { + curr_flow_id = (NocTrafficFlowId)traffic_flow; + t_noc_traffic_flow curr_traffic_flow = traffic_flow_storage.get_single_noc_traffic_flow(curr_flow_id); - int size_of_associated_flows_for_sink_routers = golden_list_of_associated_links_sink_router.size(); - // make sure that the correct traffic flows are added to each router when it is a sink - for (int sink_router = 0; sink_router < size_of_associated_flows_for_sink_routers;sink_router++){ - - sink_router_id = (ClusterBlockId)sink_router; + // make sure that the source and destination routers match the golden set + REQUIRE(curr_traffic_flow.source_router_cluster_id == golden_traffic_flow_list[traffic_flow].source_router_cluster_id); + REQUIRE(curr_traffic_flow.sink_router_cluster_id == golden_traffic_flow_list[traffic_flow].sink_router_cluster_id); + } - int size_of_current_sink_router_associated_traffic_flows = golden_list_of_associated_links_sink_router[sink_router_id].size(); + int size_of_associated_flows_for_source_routers = golden_list_of_associated_links_source_router.size(); + // make sure that the correct traffic flows are added to each router when it is a source + for (int source_router = 0; source_router < size_of_associated_flows_for_source_routers; source_router++) { + source_router_id = (ClusterBlockId)source_router; - const std::vector* associated_traffic_flows_to_sink_router = traffic_flow_storage.get_traffic_flows_associated_to_sink_router(sink_router_id); + int size_of_current_source_router_associated_traffic_flows = golden_list_of_associated_links_source_router[source_router_id].size(); - for (int sink_router_traffic_flow = 0; sink_router_traffic_flow < size_of_current_sink_router_associated_traffic_flows; sink_router_traffic_flow++){ + const std::vector* associated_traffic_flows_to_source_router = traffic_flow_storage.get_traffic_flows_associated_to_source_router(source_router_id); - REQUIRE((size_t)golden_list_of_associated_links_sink_router[sink_router_id][sink_router_traffic_flow] == (size_t)(*associated_traffic_flows_to_sink_router)[sink_router_traffic_flow]); - } + for (int source_router_traffic_flow = 0; source_router_traffic_flow < size_of_current_source_router_associated_traffic_flows; source_router_traffic_flow++) { + REQUIRE((size_t)golden_list_of_associated_links_source_router[source_router_id][source_router_traffic_flow] == (size_t)(*associated_traffic_flows_to_source_router)[source_router_traffic_flow]); } } - SECTION("Checking to see if invalid blocks that are not routers exist in NocTrafficFlows."){ - // create a invalid block id - ClusterBlockId invalid_block = (ClusterBlockId)(NUM_OF_ROUTERS + 1); + int size_of_associated_flows_for_sink_routers = golden_list_of_associated_links_sink_router.size(); + // make sure that the correct traffic flows are added to each router when it is a sink + for (int sink_router = 0; sink_router < size_of_associated_flows_for_sink_routers; sink_router++) { + sink_router_id = (ClusterBlockId)sink_router; - // check that this block doesnt exist in the traffic flow datastructure - REQUIRE(traffic_flow_storage.check_if_cluster_block_is_a_noc_router(invalid_block) == false); + int size_of_current_sink_router_associated_traffic_flows = golden_list_of_associated_links_sink_router[sink_router_id].size(); - } - SECTION("Checking that when there are no traffics flows where a given router is a source there exists no traffic flows associated with said source router."){ + const std::vector* associated_traffic_flows_to_sink_router = traffic_flow_storage.get_traffic_flows_associated_to_sink_router(sink_router_id); - // create a invalid block id (mimics the effect where a router has no traffic flows associated with it) - ClusterBlockId invalid_block = (ClusterBlockId)(NUM_OF_ROUTERS + 1); - - // check that this router has no traffic flows associated with it - REQUIRE(traffic_flow_storage.get_traffic_flows_associated_to_source_router(invalid_block) == nullptr); + for (int sink_router_traffic_flow = 0; sink_router_traffic_flow < size_of_current_sink_router_associated_traffic_flows; sink_router_traffic_flow++) { + REQUIRE((size_t)golden_list_of_associated_links_sink_router[sink_router_id][sink_router_traffic_flow] == (size_t)(*associated_traffic_flows_to_sink_router)[sink_router_traffic_flow]); + } } - SECTION("Checking that when there are no traffics flows where a given router is a sink there exists no traffic flows associated with said sink router."){ + } + SECTION("Checking to see if invalid blocks that are not routers exist in NocTrafficFlows.") { + // create a invalid block id + ClusterBlockId invalid_block = (ClusterBlockId)(NUM_OF_ROUTERS + 1); - // create a invalid block id (mimics the effect where a router has no traffic flows associated with it) - ClusterBlockId invalid_block = (ClusterBlockId)(NUM_OF_ROUTERS + 1); + // check that this block doesnt exist in the traffic flow datastructure + REQUIRE(traffic_flow_storage.check_if_cluster_block_is_a_noc_router(invalid_block) == false); + } + SECTION("Checking that when there are no traffics flows where a given router is a source there exists no traffic flows associated with said source router.") { + // create a invalid block id (mimics the effect where a router has no traffic flows associated with it) + ClusterBlockId invalid_block = (ClusterBlockId)(NUM_OF_ROUTERS + 1); - // check that this router has no traffic flows associated with it - REQUIRE(traffic_flow_storage.get_traffic_flows_associated_to_sink_router(invalid_block) == nullptr); - } + // check that this router has no traffic flows associated with it + REQUIRE(traffic_flow_storage.get_traffic_flows_associated_to_source_router(invalid_block) == nullptr); + } + SECTION("Checking that when there are no traffics flows where a given router is a sink there exists no traffic flows associated with said sink router.") { + // create a invalid block id (mimics the effect where a router has no traffic flows associated with it) + ClusterBlockId invalid_block = (ClusterBlockId)(NUM_OF_ROUTERS + 1); + // check that this router has no traffic flows associated with it + REQUIRE(traffic_flow_storage.get_traffic_flows_associated_to_sink_router(invalid_block) == nullptr); } -} \ No newline at end of file +} +} // namespace \ No newline at end of file diff --git a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp index c1b31ad29f7..d6139d56971 100644 --- a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp +++ b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp @@ -5,410 +5,390 @@ #include -namespace{ +namespace { - TEST_CASE("test_verify_traffic_flow_router_modules", "[vpr_noc_traffic_flows_parser]"){ +TEST_CASE("test_verify_traffic_flow_router_modules", "[vpr_noc_traffic_flows_parser]") { + // filler data for the xml information + // data for the xml parsing + pugi::xml_node test; + pugiutil::loc_data test_location; - // filler data for the xml information - // data for the xml parsing - pugi::xml_node test; - pugiutil::loc_data test_location; - + SECTION("Test case where atleast one of the input strings for the source and destination router module name is empty") { + std::string src_router_name = ""; + std::string dst_router_name = "test"; - SECTION("Test case where atleast one of the input strings for the source and destination router module name is empty"){ + REQUIRE_THROWS_WITH(verify_traffic_flow_router_modules(src_router_name, dst_router_name, test, test_location), "Invalid names for the source and sink NoC router modules."); + } + SECTION("Test case where the router module names for both the source and destination routers are the same") { + std::string src_router_name = "same_router"; + std::string dst_router_name = "same_router"; - std::string src_router_name = ""; - std::string dst_router_name = "test"; + REQUIRE_THROWS_WITH(verify_traffic_flow_router_modules(src_router_name, dst_router_name, test, test_location), "Source and sink NoC routers cannot be the same modules."); + } + SECTION("Test case where the source and destination router module names are legeal") { + std::string src_router_name = "source_router"; + std::string dst_router_name = "destination_router"; - REQUIRE_THROWS_WITH(verify_traffic_flow_router_modules(src_router_name, dst_router_name, test, test_location), "Invalid names for the source and sink NoC router modules."); + REQUIRE_NOTHROW(verify_traffic_flow_router_modules(src_router_name, dst_router_name, test, test_location)); + } +} +TEST_CASE("test_verify_traffic_flow_properties", "[vpr_noc_traffic_flows_parser]") { + // filler data for the xml information + // data for the xml parsing + pugi::xml_node test; + pugiutil::loc_data test_location; + + SECTION("Test case where the noc traffic flow properties are illegal") { + double test_traffic_flow_bandwidth = 1.5; + // illegal value + double test_max_traffic_flow_latency = -1.5; + + REQUIRE_THROWS_WITH(verify_traffic_flow_properties(test_traffic_flow_bandwidth, test_max_traffic_flow_latency, test, test_location), "The traffic flow bandwidth and latency constraints need to be positive values."); + } + SECTION("Test case where the noc traffic flows properties are legal") { + double test_traffic_flow_bandwidth = 1.5; + double test_max_traffic_flow_latency = 1.5; - } - SECTION("Test case where the router module names for both the source and destination routers are the same"){ + REQUIRE_NOTHROW(verify_traffic_flow_properties(test_traffic_flow_bandwidth, test_max_traffic_flow_latency, test, test_location)); + } +} +TEST_CASE("test_get_router_module_cluster_id", "[vpr_noc_traffic_flows_parser]") { + // filler data for the xml information + // data for the xml parsing + pugi::xml_node test; + pugiutil::loc_data test_location; + + // datastructure to keep track of blocks name to its id + std::map block_id_from_name; + + // get the global netlist + ClusteringContext& cluster_ctx = g_vpr_ctx.mutable_clustering(); + ClusteredNetlist* test_netlist = &cluster_ctx.clb_nlist; + + // create a new clustered netlist + *test_netlist = ClusteredNetlist("test_netlist", "77"); + + /* need to create the noc router physical type */ + + t_physical_tile_type noc_router; + + // create a single subtile + t_sub_tile router_tile; + + // there are two logical router types that are compatible with this subtile + t_logical_block_type router_block; + char router[] = "router"; + router_block.name = router; + t_logical_block_type_ptr router_ref = &router_block; + t_pb router_pb; + + // second logical router block + t_logical_block_type router_block_2; + char router_2[] = "router_2"; + router_block_2.name = router_2; + t_logical_block_type_ptr router_ref_2 = &router_block_2; + t_pb router_2_pb; + + // add these two logical tyes as the equivalent sites of the subtile + router_tile.equivalent_sites.push_back(router_ref); + router_tile.equivalent_sites.push_back(router_ref_2); + + // add the subtile to the physical noc router type + noc_router.sub_tiles.push_back(router_tile); + + // create a reference to the physical type + t_physical_tile_type_ptr noc_router_ref = &noc_router; + + /* finished creating noc router physical type */ + + // creating an IO logical type + t_logical_block_type i_o_block; + char i_o[] = "IO"; + i_o_block.name = i_o; + t_logical_block_type_ptr i_o_ref = &i_o_block; + t_pb io_pb; + + // create some sample IO blocks in the clustered netlist + // These will act as fillers to make sure that the find block function correctly handles a netlist with different types of blocks + + // the block names + char io_port_one[] = "io_port_one"; + char io_port_two[] = "io_port_two"; + char io_port_three[] = "io_port_three"; + char io_port_four[] = "io_port_four"; + + // add the io blocks to the netlist + block_id_from_name.emplace(io_port_one, test_netlist->create_block(io_port_one, &io_pb, i_o_ref)); + block_id_from_name.emplace(io_port_two, test_netlist->create_block(io_port_two, &io_pb, i_o_ref)); + block_id_from_name.emplace(io_port_three, test_netlist->create_block(io_port_three, &io_pb, i_o_ref)); + block_id_from_name.emplace(io_port_four, test_netlist->create_block(io_port_four, &io_pb, i_o_ref)); + + SECTION("Test case where the block is found in the clustered netlist") { + // create names for some router blocks + char router_one[] = "router:noc_router_one|flit_out_two[0]~reg0"; + char router_two[] = "router:noc_router_two|flit_out_two[0]~reg0"; + char router_three[] = "router:noc_router_three|flit_out_two[0]~reg0"; + char router_four[] = "router:noc_router_four|flit_out_two[0]~reg0"; + + // add the router blocks + block_id_from_name.emplace(router_one, test_netlist->create_block(router_one, &router_pb, router_ref)); + block_id_from_name.emplace(router_two, test_netlist->create_block(router_two, &router_pb, router_ref)); + block_id_from_name.emplace(router_three, test_netlist->create_block(router_three, &router_pb, router_ref)); + block_id_from_name.emplace(router_four, test_netlist->create_block(router_four, &router_pb, router_ref)); + + // create additional router blocks + char router_five[] = "router:noc_router_five|flit_out_two[0]~reg0"; + char router_six[] = "router:noc_router_six|flit_out_two[0]~reg0"; + + block_id_from_name.emplace(router_five, test_netlist->create_block(router_five, &router_2_pb, router_ref_2)); + block_id_from_name.emplace(router_six, test_netlist->create_block(router_six, &router_2_pb, router_ref_2)); + + // now find a block just knowing its instance name + std::string test_router_module_name = ".*noc_router_five.*"; + + // now get the cluster id of the block with the test router name using the function we are testing + ClusterBlockId test_router_block_id; + REQUIRE_NOTHROW(test_router_block_id = get_router_module_cluster_id(test_router_module_name, cluster_ctx, test, test_location, noc_router_ref)); + + REQUIRE((size_t)(block_id_from_name.find("router:noc_router_five|flit_out_two[0]~reg0")->second) == (size_t)test_router_block_id); + } + SECTION("Test case where the block is not found in the clustered netlist") { + // create names for some router blocks + char router_one[] = "router:noc_router_one|flit_out_two[0]~reg0"; + char router_two[] = "router:noc_router_two|flit_out_two[0]~reg0"; + char router_three[] = "router:noc_router_three|flit_out_two[0]~reg0"; + char router_four[] = "router:noc_router_four|flit_out_two[0]~reg0"; + + // add the router blocks + block_id_from_name.emplace(router_one, test_netlist->create_block(router_one, &router_pb, router_ref)); + block_id_from_name.emplace(router_two, test_netlist->create_block(router_two, &router_pb, router_ref)); + block_id_from_name.emplace(router_three, test_netlist->create_block(router_three, &router_pb, router_ref)); + block_id_from_name.emplace(router_four, test_netlist->create_block(router_four, &router_pb, router_ref)); + + // create additional router blocks + char router_five[] = "router:noc_router_five|flit_out_two[0]~reg0"; + char router_six[] = "router:noc_router_six|flit_out_two[0]~reg0"; + + block_id_from_name.emplace(router_five, test_netlist->create_block(router_five, &router_2_pb, router_ref_2)); + block_id_from_name.emplace(router_six, test_netlist->create_block(router_six, &router_2_pb, router_ref_2)); + + // now find a block just knowing its name. Choosing a block name that doesn't exist + std::string test_router_module_name = "^router:noc_router_seven|flit_out_two[0]~reg0$"; + + // now get the cluster id of the block with the test router name using the function we are testing + // This should fail, so check that it does + REQUIRE_THROWS_WITH(get_router_module_cluster_id(test_router_module_name, cluster_ctx, test, test_location, noc_router_ref), "The router module '^router:noc_router_seven|flit_out_two[0]~reg0$' does not exist in the design."); + } +} +TEST_CASE("test_check_traffic_flow_router_module_type", "[vpr_noc_traffic_flows_parser]") { + // filler data for the xml information + // data for the xml parsing + pugi::xml_node test; + pugiutil::loc_data test_location; - std::string src_router_name = "same_router"; - std::string dst_router_name = "same_router"; + // get the global netlist + ClusteringContext& cluster_ctx = g_vpr_ctx.mutable_clustering(); + ClusteredNetlist* test_netlist = &cluster_ctx.clb_nlist; - REQUIRE_THROWS_WITH(verify_traffic_flow_router_modules(src_router_name, dst_router_name, test, test_location), "Source and sink NoC routers cannot be the same modules."); - } - SECTION("Test case where the source and destination router module names are legeal"){ + // create a new clustered netlist + *test_netlist = ClusteredNetlist("test_netlist", "77"); - std::string src_router_name = "source_router"; - std::string dst_router_name = "destination_router"; + /* need to create the noc router physical type */ - REQUIRE_NOTHROW(verify_traffic_flow_router_modules(src_router_name, dst_router_name, test, test_location)); + t_physical_tile_type noc_router; - } - } - TEST_CASE("test_verify_traffic_flow_properties", "[vpr_noc_traffic_flows_parser]"){ + // create a single subtile + t_sub_tile router_tile; - // filler data for the xml information - // data for the xml parsing - pugi::xml_node test; - pugiutil::loc_data test_location; + // there is a single logical type that is compatible with this subtile and it is a router + t_logical_block_type router_block; + char router[] = "router"; + router_block.name = router; + t_logical_block_type_ptr router_ref = &router_block; + t_pb router_pb; - SECTION("Test case where the noc traffic flow properties are illegal"){ + // add the logical tyes as the equivalent sites of the subtile + router_tile.equivalent_sites.push_back(router_ref); - double test_traffic_flow_bandwidth = 1.5; - // illegal value - double test_max_traffic_flow_latency = -1.5; + // add the subtile to the physical noc router type + noc_router.sub_tiles.push_back(router_tile); - REQUIRE_THROWS_WITH(verify_traffic_flow_properties(test_traffic_flow_bandwidth, test_max_traffic_flow_latency, test, test_location), "The traffic flow bandwidth and latency constraints need to be positive values."); - } - SECTION("Test case where the noc traffic flows properties are legal"){ + // create a reference to the physical type + t_physical_tile_type_ptr noc_router_ref = &noc_router; - double test_traffic_flow_bandwidth = 1.5; - double test_max_traffic_flow_latency = 1.5; + /* finished creating noc router physical type */ - REQUIRE_NOTHROW(verify_traffic_flow_properties(test_traffic_flow_bandwidth, test_max_traffic_flow_latency, test, test_location)); - } - } - TEST_CASE("test_get_router_module_cluster_id", "[vpr_noc_traffic_flows_parser]"){ - - // filler data for the xml information - // data for the xml parsing - pugi::xml_node test; - pugiutil::loc_data test_location; - - // datastructure to keep track of blocks name to its id - std::map block_id_from_name; - - // get the global netlist - ClusteringContext& cluster_ctx = g_vpr_ctx.mutable_clustering(); - ClusteredNetlist* test_netlist = &cluster_ctx.clb_nlist; - - // create a new clustered netlist - *test_netlist = ClusteredNetlist("test_netlist", "77"); - - /* need to create the noc router physical type */ - - t_physical_tile_type noc_router; - - // create a single subtile - t_sub_tile router_tile; - - // there are two logical router types that are compatible with this subtile - t_logical_block_type router_block; - char router[] = "router"; - router_block.name = router; - t_logical_block_type_ptr router_ref = &router_block; - t_pb router_pb; - - // second logical router block - t_logical_block_type router_block_2; - char router_2[] = "router_2"; - router_block_2.name = router_2; - t_logical_block_type_ptr router_ref_2 = &router_block_2; - t_pb router_2_pb; - - // add these two logical tyes as the equivalent sites of the subtile - router_tile.equivalent_sites.push_back(router_ref); - router_tile.equivalent_sites.push_back(router_ref_2); - - // add the subtile to the physical noc router type - noc_router.sub_tiles.push_back(router_tile); - - // create a reference to the physical type - t_physical_tile_type_ptr noc_router_ref = &noc_router; - - /* finished creating noc router physical type */ - - // creating an IO logical type - t_logical_block_type i_o_block; - char i_o[] = "IO"; - i_o_block.name = i_o; - t_logical_block_type_ptr i_o_ref = &i_o_block; - t_pb io_pb; - - // create some sample IO blocks in the clustered netlist - // These will act as fillers to make sure that the find block function correctly handles a netlist with different types of blocks - - // the block names - char io_port_one[] = "io_port_one"; - char io_port_two[] = "io_port_two"; - char io_port_three[] = "io_port_three"; - char io_port_four[] = "io_port_four"; - - // add the io blocks to the netlist - block_id_from_name.emplace(io_port_one, test_netlist->create_block(io_port_one, &io_pb, i_o_ref)); - block_id_from_name.emplace(io_port_two, test_netlist->create_block(io_port_two, &io_pb, i_o_ref)); - block_id_from_name.emplace(io_port_three, test_netlist->create_block(io_port_three, &io_pb, i_o_ref)); - block_id_from_name.emplace(io_port_four, test_netlist->create_block(io_port_four, &io_pb, i_o_ref)); - - SECTION("Test case where the block is found in the clustered netlist"){ - - // create names for some router blocks - char router_one[] = "router:noc_router_one|flit_out_two[0]~reg0"; - char router_two[] = "router:noc_router_two|flit_out_two[0]~reg0"; - char router_three[] = "router:noc_router_three|flit_out_two[0]~reg0"; - char router_four[] = "router:noc_router_four|flit_out_two[0]~reg0"; - - // add the router blocks - block_id_from_name.emplace(router_one, test_netlist->create_block(router_one, &router_pb, router_ref)); - block_id_from_name.emplace(router_two, test_netlist->create_block(router_two, &router_pb, router_ref)); - block_id_from_name.emplace(router_three, test_netlist->create_block(router_three, &router_pb, router_ref)); - block_id_from_name.emplace(router_four, test_netlist->create_block(router_four, &router_pb, router_ref)); - - // create additional router blocks - char router_five[] = "router:noc_router_five|flit_out_two[0]~reg0"; - char router_six[] = "router:noc_router_six|flit_out_two[0]~reg0"; - - block_id_from_name.emplace(router_five, test_netlist->create_block(router_five, &router_2_pb, router_ref_2)); - block_id_from_name.emplace(router_six, test_netlist->create_block(router_six, &router_2_pb, router_ref_2)); - - // now find a block just knowing its instance name - std::string test_router_module_name = ".*noc_router_five.*"; - - // now get the cluster id of the block with the test router name using the function we are testing - ClusterBlockId test_router_block_id; - REQUIRE_NOTHROW(test_router_block_id = get_router_module_cluster_id(test_router_module_name, cluster_ctx, test, test_location, noc_router_ref)); - - REQUIRE((size_t)(block_id_from_name.find("router:noc_router_five|flit_out_two[0]~reg0")->second) == (size_t)test_router_block_id); - } - SECTION("Test case where the block is not found in the clustered netlist"){ - - // create names for some router blocks - char router_one[] = "router:noc_router_one|flit_out_two[0]~reg0"; - char router_two[] = "router:noc_router_two|flit_out_two[0]~reg0"; - char router_three[] = "router:noc_router_three|flit_out_two[0]~reg0"; - char router_four[] = "router:noc_router_four|flit_out_two[0]~reg0"; - - // add the router blocks - block_id_from_name.emplace(router_one, test_netlist->create_block(router_one, &router_pb, router_ref)); - block_id_from_name.emplace(router_two, test_netlist->create_block(router_two, &router_pb, router_ref)); - block_id_from_name.emplace(router_three, test_netlist->create_block(router_three, &router_pb, router_ref)); - block_id_from_name.emplace(router_four, test_netlist->create_block(router_four, &router_pb, router_ref)); - - // create additional router blocks - char router_five[] = "router:noc_router_five|flit_out_two[0]~reg0"; - char router_six[] = "router:noc_router_six|flit_out_two[0]~reg0"; - - block_id_from_name.emplace(router_five, test_netlist->create_block(router_five, &router_2_pb, router_ref_2)); - block_id_from_name.emplace(router_six, test_netlist->create_block(router_six, &router_2_pb, router_ref_2)); - - // now find a block just knowing its name. Choosing a block name that doesn't exist - std::string test_router_module_name = "^router:noc_router_seven|flit_out_two[0]~reg0$"; - - // now get the cluster id of the block with the test router name using the function we are testing - // This should fail, so check that it does - REQUIRE_THROWS_WITH(get_router_module_cluster_id(test_router_module_name, cluster_ctx, test, test_location, noc_router_ref), "The router module '^router:noc_router_seven|flit_out_two[0]~reg0$' does not exist in the design."); - } - } - TEST_CASE("test_check_traffic_flow_router_module_type", "[vpr_noc_traffic_flows_parser]"){ - - // filler data for the xml information - // data for the xml parsing - pugi::xml_node test; - pugiutil::loc_data test_location; - - // get the global netlist - ClusteringContext& cluster_ctx = g_vpr_ctx.mutable_clustering(); - ClusteredNetlist* test_netlist = &cluster_ctx.clb_nlist; - - // create a new clustered netlist - *test_netlist = ClusteredNetlist("test_netlist", "77"); - - /* need to create the noc router physical type */ - - t_physical_tile_type noc_router; - - // create a single subtile - t_sub_tile router_tile; - - // there is a single logical type that is compatible with this subtile and it is a router - t_logical_block_type router_block; - char router[] = "router"; - router_block.name = router; - t_logical_block_type_ptr router_ref = &router_block; - t_pb router_pb; - - // add the logical tyes as the equivalent sites of the subtile - router_tile.equivalent_sites.push_back(router_ref); - - // add the subtile to the physical noc router type - noc_router.sub_tiles.push_back(router_tile); - - // create a reference to the physical type - t_physical_tile_type_ptr noc_router_ref = &noc_router; - - /* finished creating noc router physical type */ - - // need to add the physical type to the logical block types equivalent tiles - router_block.equivalent_tiles.push_back(noc_router_ref); - - // creating an IO logical type - t_logical_block_type i_o_block; - char i_o[] = "IO"; - i_o_block.name = i_o; - t_logical_block_type_ptr i_o_ref = &i_o_block; - t_pb io_pb; - - SECTION("Test case where the traffic flow module is of type router"){ - // create a name for a router block - char router_one[] = "router:noc_router_one|flit_out_two[0]~reg0"; - - // create a cluster block that represents a router module - ClusterBlockId router_module_id = test_netlist->create_block(router_one, &router_pb, router_ref); - - // now run the test function to verify that the current router module has a logical type of a router - // the function should not fail since the module is a router - REQUIRE_NOTHROW(check_traffic_flow_router_module_type(router_one, router_module_id, test, test_location, cluster_ctx, noc_router_ref)); - } - SECTION("Test case where the traffic flow module is not of type router"){ - // create a name for a IO block - char io_block_one[] = "io_block_one"; - - // create a cluster blcok that represents a IO block - ClusterBlockId io_module_id = test_netlist->create_block(io_block_one, &io_pb, i_o_ref); - - // now run the test function to verify that the current IO module doesnt have a logical type of a router - // the function should faile since the module is of type IO - REQUIRE_THROWS_WITH(check_traffic_flow_router_module_type(io_block_one, io_module_id, test, test_location, cluster_ctx, noc_router_ref), "The supplied module name 'io_block_one' is not a NoC router."); - } + // need to add the physical type to the logical block types equivalent tiles + router_block.equivalent_tiles.push_back(noc_router_ref); + + // creating an IO logical type + t_logical_block_type i_o_block; + char i_o[] = "IO"; + i_o_block.name = i_o; + t_logical_block_type_ptr i_o_ref = &i_o_block; + t_pb io_pb; + + SECTION("Test case where the traffic flow module is of type router") { + // create a name for a router block + char router_one[] = "router:noc_router_one|flit_out_two[0]~reg0"; + + // create a cluster block that represents a router module + ClusterBlockId router_module_id = test_netlist->create_block(router_one, &router_pb, router_ref); + + // now run the test function to verify that the current router module has a logical type of a router + // the function should not fail since the module is a router + REQUIRE_NOTHROW(check_traffic_flow_router_module_type(router_one, router_module_id, test, test_location, cluster_ctx, noc_router_ref)); } - TEST_CASE("test_check_that_all_router_blocks_have_an_associated_traffic_flow", "[vpr_noc_traffic_flows_parser]"){ + SECTION("Test case where the traffic flow module is not of type router") { + // create a name for a IO block + char io_block_one[] = "io_block_one"; - // get the global netlist - ClusteringContext& cluster_ctx = g_vpr_ctx.mutable_clustering(); - ClusteredNetlist* test_netlist = &cluster_ctx.clb_nlist; + // create a cluster blcok that represents a IO block + ClusterBlockId io_module_id = test_netlist->create_block(io_block_one, &io_pb, i_o_ref); - // create a new clustered netlist - *test_netlist = ClusteredNetlist("test_netlist", "77"); + // now run the test function to verify that the current IO module doesnt have a logical type of a router + // the function should faile since the module is of type IO + REQUIRE_THROWS_WITH(check_traffic_flow_router_module_type(io_block_one, io_module_id, test, test_location, cluster_ctx, noc_router_ref), "The supplied module name 'io_block_one' is not a NoC router."); + } +} +TEST_CASE("test_check_that_all_router_blocks_have_an_associated_traffic_flow", "[vpr_noc_traffic_flows_parser]") { + // get the global netlist + ClusteringContext& cluster_ctx = g_vpr_ctx.mutable_clustering(); + ClusteredNetlist* test_netlist = &cluster_ctx.clb_nlist; + + // create a new clustered netlist + *test_netlist = ClusteredNetlist("test_netlist", "77"); - // get the global device information - DeviceContext& device_ctx = g_vpr_ctx.mutable_device(); + // get the global device information + DeviceContext& device_ctx = g_vpr_ctx.mutable_device(); - // get the global noc information - NocContext& noc_ctx = g_vpr_ctx.mutable_noc(); - // delete any previously created traffic flow info - noc_ctx.noc_traffic_flows_storage.clear_traffic_flows(); + // get the global noc information + NocContext& noc_ctx = g_vpr_ctx.mutable_noc(); + // delete any previously created traffic flow info + noc_ctx.noc_traffic_flows_storage.clear_traffic_flows(); - // create the logical type of a noc router - // there is a single logical type that is compatible with this subtile and it is a router - t_logical_block_type router_block; - char router[] = "router"; - router_block.name = router; - t_logical_block_type_ptr router_ref = &router_block; - t_pb router_pb; + // create the logical type of a noc router + // there is a single logical type that is compatible with this subtile and it is a router + t_logical_block_type router_block; + char router[] = "router"; + router_block.name = router; + t_logical_block_type_ptr router_ref = &router_block; + t_pb router_pb; - //set the index of the logical type as 0 (its the only block type in this test device) - router_block.index = 0; - // now add this logical type to the device - device_ctx.logical_block_types.push_back(router_block); + //set the index of the logical type as 0 (its the only block type in this test device) + router_block.index = 0; + // now add this logical type to the device + device_ctx.logical_block_types.push_back(router_block); - //need to create the noc router physical type - t_physical_tile_type noc_router; + //need to create the noc router physical type + t_physical_tile_type noc_router; - // indicate that the noc_router physical tile is not an input/output - noc_router.is_input_type = false; - noc_router.is_output_type = false; - - // create a single subtile - t_sub_tile router_tile; + // indicate that the noc_router physical tile is not an input/output + noc_router.is_input_type = false; + noc_router.is_output_type = false; - // add the logical tyes as the equivalent sites of the subtile - router_tile.equivalent_sites.push_back(router_ref); + // create a single subtile + t_sub_tile router_tile; - // add the subtile to the physical noc router type - noc_router.sub_tiles.push_back(router_tile); + // add the logical tyes as the equivalent sites of the subtile + router_tile.equivalent_sites.push_back(router_ref); - // create a reference to the physical type - t_physical_tile_type_ptr noc_router_ref = &noc_router; - // need to add the physical type of the router to the list of physical tiles that match to the router logical block - router_block.equivalent_tiles.push_back(noc_router_ref); + // add the subtile to the physical noc router type + noc_router.sub_tiles.push_back(router_tile); - // define arbritary values for traffic flow bandwidths and latency - double traffic_flow_bandwidth = 0.0; - double traffic_flow_latency = 0.0; + // create a reference to the physical type + t_physical_tile_type_ptr noc_router_ref = &noc_router; + // need to add the physical type of the router to the list of physical tiles that match to the router logical block + router_block.equivalent_tiles.push_back(noc_router_ref); - // start by creating a set of router blocks in the design and add them to the clustered netlist + // define arbritary values for traffic flow bandwidths and latency + double traffic_flow_bandwidth = 0.0; + double traffic_flow_latency = 0.0; - // define the test router block names - char router_one[] = "router_block_one"; - char router_two[] = "router_block_two"; - char router_three[] = "router_block_three"; + // start by creating a set of router blocks in the design and add them to the clustered netlist - ClusterBlockId router_block_one_id = test_netlist->create_block(router_one, &router_pb, router_ref); - ClusterBlockId router_block_two_id = test_netlist->create_block(router_two, &router_pb, router_ref); - ClusterBlockId router_block_three_id = test_netlist->create_block(router_three, &router_pb, router_ref); + // define the test router block names + char router_one[] = "router_block_one"; + char router_two[] = "router_block_two"; + char router_three[] = "router_block_three"; - // define the name of the test noc traffic flows file - std::string test_noc_traffic_flows_file_name = "noc_traffic_flows_file.flows"; + ClusterBlockId router_block_one_id = test_netlist->create_block(router_one, &router_pb, router_ref); + ClusterBlockId router_block_two_id = test_netlist->create_block(router_two, &router_pb, router_ref); + ClusterBlockId router_block_three_id = test_netlist->create_block(router_three, &router_pb, router_ref); - SECTION("Test case when all router blocks in the design have an associated traffic flow"){ - - // create a number of traffic flows that include all router blocks in the design - noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_one, router_two, router_block_one_id, router_block_two_id, traffic_flow_bandwidth, traffic_flow_latency); + // define the name of the test noc traffic flows file + std::string test_noc_traffic_flows_file_name = "noc_traffic_flows_file.flows"; - noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_two, router_three, router_block_two_id, router_block_three_id, traffic_flow_bandwidth, traffic_flow_latency); + SECTION("Test case when all router blocks in the design have an associated traffic flow") { + // create a number of traffic flows that include all router blocks in the design + noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_one, router_two, router_block_one_id, router_block_two_id, traffic_flow_bandwidth, traffic_flow_latency); - noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_three, router_one, router_block_three_id, router_block_one_id, traffic_flow_bandwidth, traffic_flow_latency); + noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_two, router_three, router_block_two_id, router_block_three_id, traffic_flow_bandwidth, traffic_flow_latency); - // now check to see whether all router blocks in the design have an associated traffic flow (this is the function tested here) - // we expect this to pass - CHECK(check_that_all_router_blocks_have_an_associated_traffic_flow(noc_ctx, noc_router_ref, test_noc_traffic_flows_file_name) == true); - } - SECTION("Test case where some router blocks in the design do not have an associated traffic flow"){ + noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_three, router_one, router_block_three_id, router_block_one_id, traffic_flow_bandwidth, traffic_flow_latency); - // create a number of traffic flows that includes router_one and router_twp but does not include router_three - noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_one, router_two, router_block_one_id, router_block_two_id, traffic_flow_bandwidth, traffic_flow_latency); + // now check to see whether all router blocks in the design have an associated traffic flow (this is the function tested here) + // we expect this to pass + CHECK(check_that_all_router_blocks_have_an_associated_traffic_flow(noc_ctx, noc_router_ref, test_noc_traffic_flows_file_name) == true); + } + SECTION("Test case where some router blocks in the design do not have an associated traffic flow") { + // create a number of traffic flows that includes router_one and router_twp but does not include router_three + noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_one, router_two, router_block_one_id, router_block_two_id, traffic_flow_bandwidth, traffic_flow_latency); - noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_two, router_one, router_block_two_id, router_block_one_id, traffic_flow_bandwidth, traffic_flow_latency); + noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_two, router_one, router_block_two_id, router_block_one_id, traffic_flow_bandwidth, traffic_flow_latency); - // now check to see whether all router blocks in the design have an associated traffic flow (this is the function tested here) - // we expect this fail - CHECK(check_that_all_router_blocks_have_an_associated_traffic_flow(noc_ctx, noc_router_ref, test_noc_traffic_flows_file_name) == false); - } + // now check to see whether all router blocks in the design have an associated traffic flow (this is the function tested here) + // we expect this fail + CHECK(check_that_all_router_blocks_have_an_associated_traffic_flow(noc_ctx, noc_router_ref, test_noc_traffic_flows_file_name) == false); + } +} +TEST_CASE("test_check_for_duplicate_traffic_flow", "[vpr_noc_traffic_flows_parser]") { + // filler data for the xml information + // data for the xml parsing + pugi::xml_node test; + pugiutil::loc_data test_location; + + // get the global noc information + NocContext& noc_ctx = g_vpr_ctx.mutable_noc(); + // delete any previously created traffic flow info + noc_ctx.noc_traffic_flows_storage.clear_traffic_flows(); + + // define arbritary values for traffic flow bandwidths and latency + double traffic_flow_bandwidth = 0.0; + double traffic_flow_latency = 0.0; + + SECTION("Test case where there are duplicate traffic flows") { + // create some sample clusterblock ids that can be used to generate traffic flows + ClusterBlockId router_block_zero_id(0); + ClusterBlockId router_block_one_id(1); + + // create sample router block names that can be used to create a traffic flow + std::string router_block_zero = "router_block_zero"; + std::string router_block_one = "router_block_one"; + + // now create a traffic flow + noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_block_zero, router_block_one, router_block_zero_id, router_block_one_id, traffic_flow_bandwidth, traffic_flow_latency); + + // now run the test function with the situation where another traffic flow is being added with the exact same source and sink routers as above + // we expect the function to fail and erro to be thrown + REQUIRE_THROWS_WITH(check_for_duplicate_traffic_flow(router_block_zero_id, router_block_one_id, test, test_location, noc_ctx.noc_traffic_flows_storage), "The supplied traffic flow is a duplicate of another traffic flow (contain the same source and sink routers). Duplicate traffic flows are not allowed."); } - TEST_CASE("test_check_for_duplicate_traffic_flow", "[vpr_noc_traffic_flows_parser]"){ - - // filler data for the xml information - // data for the xml parsing - pugi::xml_node test; - pugiutil::loc_data test_location; - - // get the global noc information - NocContext& noc_ctx = g_vpr_ctx.mutable_noc(); - // delete any previously created traffic flow info - noc_ctx.noc_traffic_flows_storage.clear_traffic_flows(); - - // define arbritary values for traffic flow bandwidths and latency - double traffic_flow_bandwidth = 0.0; - double traffic_flow_latency = 0.0; - - SECTION("Test case where there are duplicate traffic flows"){ - - // create some sample clusterblock ids that can be used to generate traffic flows - ClusterBlockId router_block_zero_id(0); - ClusterBlockId router_block_one_id(1); - - // create sample router block names that can be used to create a traffic flow - std::string router_block_zero = "router_block_zero"; - std::string router_block_one = "router_block_one"; - - // now create a traffic flow - noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_block_zero, router_block_one, router_block_zero_id, router_block_one_id, traffic_flow_bandwidth, traffic_flow_latency); - - // now run the test function with the situation where another traffic flow is being added with the exact same source and sink routers as above - // we expect the function to fail and erro to be thrown - REQUIRE_THROWS_WITH(check_for_duplicate_traffic_flow(router_block_zero_id, router_block_one_id, test, test_location, noc_ctx.noc_traffic_flows_storage), "The supplied traffic flow is a duplicate of another traffic flow (contain the same source and sink routers). Duplicate traffic flows are not allowed."); - } - SECTION("Test case where there are no duplicate traffic flows"){ - - // create some sample clusterblock ids that can be used to generate traffic flows - ClusterBlockId router_block_zero_id(0); - ClusterBlockId router_block_one_id(1); - ClusterBlockId router_block_two_id(2); - - // create sample router block names that can be used to create a traffic flow - std::string router_block_zero = "router_block_zero"; - std::string router_block_one = "router_block_one"; - - // now create a traffic flow - noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_block_zero, router_block_one, router_block_zero_id, router_block_one_id, traffic_flow_bandwidth, traffic_flow_latency); - - // now run the test function with the situation where another traffic flow is being added with sink router than what was used above - // we expect the function to pass and no error to be thrown - REQUIRE_NOTHROW(check_for_duplicate_traffic_flow(router_block_zero_id, router_block_two_id, test, test_location, noc_ctx.noc_traffic_flows_storage)); - } + SECTION("Test case where there are no duplicate traffic flows") { + // create some sample clusterblock ids that can be used to generate traffic flows + ClusterBlockId router_block_zero_id(0); + ClusterBlockId router_block_one_id(1); + ClusterBlockId router_block_two_id(2); + + // create sample router block names that can be used to create a traffic flow + std::string router_block_zero = "router_block_zero"; + std::string router_block_one = "router_block_one"; + + // now create a traffic flow + noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_block_zero, router_block_one, router_block_zero_id, router_block_one_id, traffic_flow_bandwidth, traffic_flow_latency); + + // now run the test function with the situation where another traffic flow is being added with sink router than what was used above + // we expect the function to pass and no error to be thrown + REQUIRE_NOTHROW(check_for_duplicate_traffic_flow(router_block_zero_id, router_block_two_id, test, test_location, noc_ctx.noc_traffic_flows_storage)); } -} \ No newline at end of file +} +} // namespace \ No newline at end of file From 957862683ee8ee3286b77e93c0cbe45737450a1d Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Thu, 30 Jun 2022 15:39:30 -0400 Subject: [PATCH 102/128] adding benchmark designs that were used to verify the noc traffic flows file parser feature. Also added a file to guide future users on how the benchmarks used to test the NoC flow in VPR are arranged, so they can find/add new benchmarks correctly. --- vtr_flow/benchmarks/noc/Readme.txt | 44 + .../multiple_noc_routers.blif | 810 ++++++++++++++++++ .../multiple_noc_routers.flows | 7 + 3 files changed, 861 insertions(+) create mode 100644 vtr_flow/benchmarks/noc/Readme.txt create mode 100755 vtr_flow/benchmarks/noc/Test_Designs/test_design_for_noc_traffic_flows_feature/multiple_noc_routers.blif create mode 100755 vtr_flow/benchmarks/noc/Test_Designs/test_design_for_noc_traffic_flows_feature/multiple_noc_routers.flows diff --git a/vtr_flow/benchmarks/noc/Readme.txt b/vtr_flow/benchmarks/noc/Readme.txt new file mode 100644 index 00000000000..a9f2aee2d7b --- /dev/null +++ b/vtr_flow/benchmarks/noc/Readme.txt @@ -0,0 +1,44 @@ +################################################### +# NoC Benchmark Design Files +################################################### + +This directory contains sample benchmark design files that incorporate +and embedded Network-on-Chip (NoC). + +Each benchmark design consists of a design file (.blif circuit netlist) and a +noc traffic flows file (.flows file). The names of the two files for +each benchmark design are the same. For example, below is an example of two +files for a sample benchmark design. + +test_benchmark_circuit: + test_benchmark_circuit.blif + test_benchmark_circuit.flows + + +# Test Benchmark Designs + +The benchmark designs found under the "Test_Designs" folder are relatively +simple designs that are mainly used to verify components NoC flow in the VPR software. +Whenever a new or existing feature needs to be tested, the benchmark designs found here +should be used. + + +# Synthetic Benchmark Designs + +The benchmark designs found under the "Synthetic_Designs" folder are small to medium +sized designs that are used verify the correctness of the VPR software. These designs +are manually created to guarantee and optimal reference solution. By running these designs +through VPR, we can determine the correctness of the NoC flow based on the reference solution. + +# Large Benchmark Designs + +The benchmark designs found under the "Large Designs" folder and medium to large complex +designs to determine the performance of the NoC flow within the VPR software. Changes made +to the NoC flow in VPR can be evaluated by running these benchmark designs and comparing +the results with previous versions. + +# Adding New Benchmark Designs + +First determine what type of benchmark this is (one of the three types above). Create a new folder +for this benchmark within one of the three sections described above. Add the circuit netlist and +noc traffic_flows files (ensure the files are properly named, as shown in the example above). diff --git a/vtr_flow/benchmarks/noc/Test_Designs/test_design_for_noc_traffic_flows_feature/multiple_noc_routers.blif b/vtr_flow/benchmarks/noc/Test_Designs/test_design_for_noc_traffic_flows_feature/multiple_noc_routers.blif new file mode 100755 index 00000000000..579eca1e852 --- /dev/null +++ b/vtr_flow/benchmarks/noc/Test_Designs/test_design_for_noc_traffic_flows_feature/multiple_noc_routers.blif @@ -0,0 +1,810 @@ +#BLIF OUTPUT: /mnt/hgfs/Research_shared_folder/noc_project/multiple_router.blif + +#MAIN MODEL + +.model test_noc +.inputs \ + i_id[0] \ + i_id[1] \ + i_id[2] \ + i_id[3] \ + i_ctrl[0] \ + i_ctrl[1] \ + i_valid \ + i_sum_a[0] \ + i_sum_a[1] \ + i_sum_a[2] \ + i_sum_a[3] \ + i_sum_a[4] \ + i_sum_a[5] \ + i_sum_a[6] \ + i_sum_a[7] \ + i_sum_b[0] \ + i_sum_b[1] \ + i_sum_b[2] \ + i_sum_b[3] \ + i_sum_b[4] \ + i_sum_b[5] \ + i_sum_b[6] \ + i_sum_b[7] \ + clk +.outputs \ + o_flag + +.names gnd +0 + +.names vcc +1 + + +# Subckt 0: Add0~1_I +.subckt stratixiv_lcell_comb \ + cin=gnd \ + dataf=i_sum_a[0] \ + datad=i_sum_b[0] \ + cout=Add0~2 \ + sumout=Add0~1 + +# Subckt 1: Add0~5_I +.subckt stratixiv_lcell_comb \ + cin=Add0~2 \ + dataf=i_sum_a[1] \ + datad=i_sum_b[1] \ + cout=Add0~6 \ + sumout=Add0~5 + +# Subckt 2: Add0~9_I +.subckt stratixiv_lcell_comb \ + cin=Add0~6 \ + dataf=i_sum_a[2] \ + datad=i_sum_b[2] \ + cout=Add0~10 \ + sumout=Add0~9 + +# Subckt 3: Add0~13_I +.subckt stratixiv_lcell_comb \ + cin=Add0~10 \ + dataf=i_sum_a[3] \ + datad=i_sum_b[3] \ + cout=Add0~14 \ + sumout=Add0~13 + +# Subckt 4: Add0~17_I +.subckt stratixiv_lcell_comb \ + cin=Add0~14 \ + dataf=i_sum_a[4] \ + datad=i_sum_b[4] \ + cout=Add0~18 \ + sumout=Add0~17 + +# Subckt 5: Add0~21_I +.subckt stratixiv_lcell_comb \ + cin=Add0~18 \ + dataf=i_sum_a[5] \ + datad=i_sum_b[5] \ + cout=Add0~22 \ + sumout=Add0~21 + +# Subckt 6: Add0~25_I +.subckt stratixiv_lcell_comb \ + cin=Add0~22 \ + dataf=i_sum_a[6] \ + datad=i_sum_b[6] \ + cout=Add0~26 \ + sumout=Add0~25 + +# Subckt 7: Add0~29_I +.subckt stratixiv_lcell_comb \ + cin=Add0~26 \ + dataf=i_sum_a[7] \ + datad=i_sum_b[7] \ + cout=Add0~30 \ + sumout=Add0~29 + +# Subckt 8: Add0~33_I +.subckt stratixiv_lcell_comb \ + cin=Add0~30 \ + sumout=Add0~33 + +# Subckt 9: noc_input[16]~I +.subckt stratixiv_lcell_comb \ + datab=i_valid \ + dataa=i_ctrl[0] \ + combout=noc_input[16] + +# Subckt 10: ~GND~I +.subckt stratixiv_lcell_comb \ + combout=~GND + +# Subckt 11: router:noc_router_four| +.subckt router \ + i_clk=clk \ + flit_in_two[0]=~GND \ + flit_in_two[1]=~GND \ + flit_in_two[2]=~GND \ + flit_in_two[3]=~GND \ + flit_in_two[4]=~GND \ + flit_in_two[5]=~GND \ + flit_in_two[6]=~GND \ + flit_in_two[7]=~GND \ + flit_in_two[8]=~GND \ + flit_in_two[9]=~GND \ + flit_in_two[10]=~GND \ + flit_in_two[11]=~GND \ + flit_in_two[12]=~GND \ + flit_in_two[13]=~GND \ + flit_in_two[14]=~GND \ + flit_in_two[15]=~GND \ + flit_in_two[16]=~GND \ + flit_in_two[17]=~GND \ + flit_in_two[18]=~GND \ + flit_in_two[19]=~GND \ + flit_in_two[20]=~GND \ + flit_in_two[21]=~GND \ + flit_in_two[22]=~GND \ + flit_in_two[23]=~GND \ + flit_in_two[24]=~GND \ + flit_in_two[25]=~GND \ + flit_in_two[26]=~GND \ + flit_in_two[27]=~GND \ + flit_in_two[28]=~GND \ + flit_in_two[29]=~GND \ + flit_in_two[30]=~GND \ + flit_in_two[31]=~GND \ + flit_in_one[0]=router:noc_router_three|flit_out_two[0]~reg0 \ + flit_in_one[1]=router:noc_router_three|flit_out_two[1]~reg0 \ + flit_in_one[2]=router:noc_router_three|flit_out_two[2]~reg0 \ + flit_in_one[3]=router:noc_router_three|flit_out_two[3]~reg0 \ + flit_in_one[4]=router:noc_router_three|flit_out_two[4]~reg0 \ + flit_in_one[5]=router:noc_router_three|flit_out_two[5]~reg0 \ + flit_in_one[6]=router:noc_router_three|flit_out_two[6]~reg0 \ + flit_in_one[7]=router:noc_router_three|flit_out_two[7]~reg0 \ + flit_in_one[8]=router:noc_router_three|flit_out_two[8]~reg0 \ + flit_in_one[9]=router:noc_router_three|flit_out_two[9]~reg0 \ + flit_in_one[10]=router:noc_router_three|flit_out_two[10]~reg0 \ + flit_in_one[11]=router:noc_router_three|flit_out_two[11]~reg0 \ + flit_in_one[12]=router:noc_router_three|flit_out_two[12]~reg0 \ + flit_in_one[13]=router:noc_router_three|flit_out_two[13]~reg0 \ + flit_in_one[14]=router:noc_router_three|flit_out_two[14]~reg0 \ + flit_in_one[15]=router:noc_router_three|flit_out_two[15]~reg0 \ + flit_in_one[16]=router:noc_router_three|flit_out_two[16]~reg0 \ + flit_in_one[17]=router:noc_router_three|flit_out_two[17]~reg0 \ + flit_in_one[18]=router:noc_router_three|flit_out_two[18]~reg0 \ + flit_in_one[19]=router:noc_router_three|flit_out_two[19]~reg0 \ + flit_in_one[20]=router:noc_router_three|flit_out_two[20]~reg0 \ + flit_in_one[21]=router:noc_router_three|flit_out_two[21]~reg0 \ + flit_in_one[22]=router:noc_router_three|flit_out_two[22]~reg0 \ + flit_in_one[23]=router:noc_router_three|flit_out_two[23]~reg0 \ + flit_in_one[24]=router:noc_router_three|flit_out_two[24]~reg0 \ + flit_in_one[25]=router:noc_router_three|flit_out_two[25]~reg0 \ + flit_in_one[26]=router:noc_router_three|flit_out_two[26]~reg0 \ + flit_in_one[27]=router:noc_router_three|flit_out_two[27]~reg0 \ + flit_in_one[28]=router:noc_router_three|flit_out_two[28]~reg0 \ + flit_in_one[29]=router:noc_router_three|flit_out_two[29]~reg0 \ + flit_in_one[30]=router:noc_router_three|flit_out_two[30]~reg0 \ + flit_in_one[31]=router:noc_router_three|flit_out_two[31]~reg0 \ + flit_out_two[0]=router:noc_router_four|flit_out_two[0]~reg0 \ + flit_out_two[1]=router:noc_router_four|flit_out_two[1]~reg0 \ + flit_out_two[2]=router:noc_router_four|flit_out_two[2]~reg0 \ + flit_out_two[3]=router:noc_router_four|flit_out_two[3]~reg0 \ + flit_out_two[4]=router:noc_router_four|flit_out_two[4]~reg0 \ + flit_out_two[5]=router:noc_router_four|flit_out_two[5]~reg0 \ + flit_out_two[6]=router:noc_router_four|flit_out_two[6]~reg0 \ + flit_out_two[7]=router:noc_router_four|flit_out_two[7]~reg0 \ + flit_out_two[8]=router:noc_router_four|flit_out_two[8]~reg0 \ + flit_out_two[9]=router:noc_router_four|flit_out_two[9]~reg0 \ + flit_out_two[10]=router:noc_router_four|flit_out_two[10]~reg0 \ + flit_out_two[11]=router:noc_router_four|flit_out_two[11]~reg0 \ + flit_out_two[12]=router:noc_router_four|flit_out_two[12]~reg0 \ + flit_out_two[13]=router:noc_router_four|flit_out_two[13]~reg0 \ + flit_out_two[14]=router:noc_router_four|flit_out_two[14]~reg0 \ + flit_out_two[15]=router:noc_router_four|flit_out_two[15]~reg0 \ + flit_out_two[16]=router:noc_router_four|flit_out_two[16]~reg0 \ + flit_out_two[17]=router:noc_router_four|flit_out_two[17]~reg0 \ + flit_out_two[18]=router:noc_router_four|flit_out_two[18]~reg0 \ + flit_out_two[19]=router:noc_router_four|flit_out_two[19]~reg0 \ + flit_out_two[20]=router:noc_router_four|flit_out_two[20]~reg0 \ + flit_out_two[21]=router:noc_router_four|flit_out_two[21]~reg0 \ + flit_out_two[22]=router:noc_router_four|flit_out_two[22]~reg0 \ + flit_out_two[23]=router:noc_router_four|flit_out_two[23]~reg0 \ + flit_out_two[24]=router:noc_router_four|flit_out_two[24]~reg0 \ + flit_out_two[25]=router:noc_router_four|flit_out_two[25]~reg0 \ + flit_out_two[26]=router:noc_router_four|flit_out_two[26]~reg0 \ + flit_out_two[27]=router:noc_router_four|flit_out_two[27]~reg0 \ + flit_out_two[28]=router:noc_router_four|flit_out_two[28]~reg0 \ + flit_out_two[29]=router:noc_router_four|flit_out_two[29]~reg0 \ + flit_out_two[30]=router:noc_router_four|flit_out_two[30]~reg0 \ + flit_out_two[31]=router:noc_router_four|flit_out_two[31]~reg0 \ + flit_out_one[0]=router:noc_router_four|flit_out_one[0]~reg0 \ + flit_out_one[1]=router:noc_router_four|flit_out_one[1]~reg0 \ + flit_out_one[2]=router:noc_router_four|flit_out_one[2]~reg0 \ + flit_out_one[3]=router:noc_router_four|flit_out_one[3]~reg0 \ + flit_out_one[4]=router:noc_router_four|flit_out_one[4]~reg0 \ + flit_out_one[5]=router:noc_router_four|flit_out_one[5]~reg0 \ + flit_out_one[6]=router:noc_router_four|flit_out_one[6]~reg0 \ + flit_out_one[7]=router:noc_router_four|flit_out_one[7]~reg0 \ + flit_out_one[8]=router:noc_router_four|flit_out_one[8]~reg0 \ + flit_out_one[9]=router:noc_router_four|flit_out_one[9]~reg0 \ + flit_out_one[10]=router:noc_router_four|flit_out_one[10]~reg0 \ + flit_out_one[11]=router:noc_router_four|flit_out_one[11]~reg0 \ + flit_out_one[12]=router:noc_router_four|flit_out_one[12]~reg0 \ + flit_out_one[13]=router:noc_router_four|flit_out_one[13]~reg0 \ + flit_out_one[14]=router:noc_router_four|flit_out_one[14]~reg0 \ + flit_out_one[15]=router:noc_router_four|flit_out_one[15]~reg0 \ + flit_out_one[16]=router:noc_router_four|flit_out_one[16]~reg0 \ + flit_out_one[17]=router:noc_router_four|flit_out_one[17]~reg0 \ + flit_out_one[18]=router:noc_router_four|flit_out_one[18]~reg0 \ + flit_out_one[19]=router:noc_router_four|flit_out_one[19]~reg0 \ + flit_out_one[20]=router:noc_router_four|flit_out_one[20]~reg0 \ + flit_out_one[21]=router:noc_router_four|flit_out_one[21]~reg0 \ + flit_out_one[22]=router:noc_router_four|flit_out_one[22]~reg0 \ + flit_out_one[23]=router:noc_router_four|flit_out_one[23]~reg0 \ + flit_out_one[24]=router:noc_router_four|flit_out_one[24]~reg0 \ + flit_out_one[25]=router:noc_router_four|flit_out_one[25]~reg0 \ + flit_out_one[26]=router:noc_router_four|flit_out_one[26]~reg0 \ + flit_out_one[27]=router:noc_router_four|flit_out_one[27]~reg0 \ + flit_out_one[28]=router:noc_router_four|flit_out_one[28]~reg0 \ + flit_out_one[29]=router:noc_router_four|flit_out_one[29]~reg0 \ + flit_out_one[30]=router:noc_router_four|flit_out_one[30]~reg0 \ + flit_out_one[31]=router:noc_router_four|flit_out_one[31]~reg0 + +# Subckt 12: router:noc_router_two| +.subckt router \ + i_clk=clk \ + flit_in_two[0]=~GND \ + flit_in_two[1]=~GND \ + flit_in_two[2]=~GND \ + flit_in_two[3]=~GND \ + flit_in_two[4]=~GND \ + flit_in_two[5]=~GND \ + flit_in_two[6]=~GND \ + flit_in_two[7]=~GND \ + flit_in_two[8]=~GND \ + flit_in_two[9]=~GND \ + flit_in_two[10]=~GND \ + flit_in_two[11]=~GND \ + flit_in_two[12]=~GND \ + flit_in_two[13]=~GND \ + flit_in_two[14]=~GND \ + flit_in_two[15]=~GND \ + flit_in_two[16]=~GND \ + flit_in_two[17]=~GND \ + flit_in_two[18]=~GND \ + flit_in_two[19]=~GND \ + flit_in_two[20]=~GND \ + flit_in_two[21]=~GND \ + flit_in_two[22]=~GND \ + flit_in_two[23]=~GND \ + flit_in_two[24]=~GND \ + flit_in_two[25]=~GND \ + flit_in_two[26]=~GND \ + flit_in_two[27]=~GND \ + flit_in_two[28]=~GND \ + flit_in_two[29]=~GND \ + flit_in_two[30]=~GND \ + flit_in_two[31]=~GND \ + flit_in_one[0]=router:noc_router_one|flit_out_one[0]~reg0 \ + flit_in_one[1]=router:noc_router_one|flit_out_one[1]~reg0 \ + flit_in_one[2]=router:noc_router_one|flit_out_one[2]~reg0 \ + flit_in_one[3]=router:noc_router_one|flit_out_one[3]~reg0 \ + flit_in_one[4]=router:noc_router_one|flit_out_one[4]~reg0 \ + flit_in_one[5]=router:noc_router_one|flit_out_one[5]~reg0 \ + flit_in_one[6]=router:noc_router_one|flit_out_one[6]~reg0 \ + flit_in_one[7]=router:noc_router_one|flit_out_one[7]~reg0 \ + flit_in_one[8]=router:noc_router_one|flit_out_one[8]~reg0 \ + flit_in_one[9]=router:noc_router_one|flit_out_one[9]~reg0 \ + flit_in_one[10]=router:noc_router_one|flit_out_one[10]~reg0 \ + flit_in_one[11]=router:noc_router_one|flit_out_one[11]~reg0 \ + flit_in_one[12]=router:noc_router_one|flit_out_one[12]~reg0 \ + flit_in_one[13]=router:noc_router_one|flit_out_one[13]~reg0 \ + flit_in_one[14]=router:noc_router_one|flit_out_one[14]~reg0 \ + flit_in_one[15]=router:noc_router_one|flit_out_one[15]~reg0 \ + flit_in_one[16]=router:noc_router_one|flit_out_one[16]~reg0 \ + flit_in_one[17]=router:noc_router_one|flit_out_one[17]~reg0 \ + flit_in_one[18]=router:noc_router_one|flit_out_one[18]~reg0 \ + flit_in_one[19]=router:noc_router_one|flit_out_one[19]~reg0 \ + flit_in_one[20]=router:noc_router_one|flit_out_one[20]~reg0 \ + flit_in_one[21]=router:noc_router_one|flit_out_one[21]~reg0 \ + flit_in_one[22]=router:noc_router_one|flit_out_one[22]~reg0 \ + flit_in_one[23]=router:noc_router_one|flit_out_one[23]~reg0 \ + flit_in_one[24]=router:noc_router_one|flit_out_one[24]~reg0 \ + flit_in_one[25]=router:noc_router_one|flit_out_one[25]~reg0 \ + flit_in_one[26]=router:noc_router_one|flit_out_one[26]~reg0 \ + flit_in_one[27]=router:noc_router_one|flit_out_one[27]~reg0 \ + flit_in_one[28]=router:noc_router_one|flit_out_one[28]~reg0 \ + flit_in_one[29]=router:noc_router_one|flit_out_one[29]~reg0 \ + flit_in_one[30]=router:noc_router_one|flit_out_one[30]~reg0 \ + flit_in_one[31]=router:noc_router_one|flit_out_one[31]~reg0 \ + flit_out_two[0]=router:noc_router_two|flit_out_two[0]~reg0 \ + flit_out_two[1]=router:noc_router_two|flit_out_two[1]~reg0 \ + flit_out_two[2]=router:noc_router_two|flit_out_two[2]~reg0 \ + flit_out_two[3]=router:noc_router_two|flit_out_two[3]~reg0 \ + flit_out_two[4]=router:noc_router_two|flit_out_two[4]~reg0 \ + flit_out_two[5]=router:noc_router_two|flit_out_two[5]~reg0 \ + flit_out_two[6]=router:noc_router_two|flit_out_two[6]~reg0 \ + flit_out_two[7]=router:noc_router_two|flit_out_two[7]~reg0 \ + flit_out_two[8]=router:noc_router_two|flit_out_two[8]~reg0 \ + flit_out_two[9]=router:noc_router_two|flit_out_two[9]~reg0 \ + flit_out_two[10]=router:noc_router_two|flit_out_two[10]~reg0 \ + flit_out_two[11]=router:noc_router_two|flit_out_two[11]~reg0 \ + flit_out_two[12]=router:noc_router_two|flit_out_two[12]~reg0 \ + flit_out_two[13]=router:noc_router_two|flit_out_two[13]~reg0 \ + flit_out_two[14]=router:noc_router_two|flit_out_two[14]~reg0 \ + flit_out_two[15]=router:noc_router_two|flit_out_two[15]~reg0 \ + flit_out_two[16]=router:noc_router_two|flit_out_two[16]~reg0 \ + flit_out_two[17]=router:noc_router_two|flit_out_two[17]~reg0 \ + flit_out_two[18]=router:noc_router_two|flit_out_two[18]~reg0 \ + flit_out_two[19]=router:noc_router_two|flit_out_two[19]~reg0 \ + flit_out_two[20]=router:noc_router_two|flit_out_two[20]~reg0 \ + flit_out_two[21]=router:noc_router_two|flit_out_two[21]~reg0 \ + flit_out_two[22]=router:noc_router_two|flit_out_two[22]~reg0 \ + flit_out_two[23]=router:noc_router_two|flit_out_two[23]~reg0 \ + flit_out_two[24]=router:noc_router_two|flit_out_two[24]~reg0 \ + flit_out_two[25]=router:noc_router_two|flit_out_two[25]~reg0 \ + flit_out_two[26]=router:noc_router_two|flit_out_two[26]~reg0 \ + flit_out_two[27]=router:noc_router_two|flit_out_two[27]~reg0 \ + flit_out_two[28]=router:noc_router_two|flit_out_two[28]~reg0 \ + flit_out_two[29]=router:noc_router_two|flit_out_two[29]~reg0 \ + flit_out_two[30]=router:noc_router_two|flit_out_two[30]~reg0 \ + flit_out_two[31]=router:noc_router_two|flit_out_two[31]~reg0 \ + flit_out_one[0]=router:noc_router_two|flit_out_one[0]~reg0 \ + flit_out_one[1]=router:noc_router_two|flit_out_one[1]~reg0 \ + flit_out_one[2]=router:noc_router_two|flit_out_one[2]~reg0 \ + flit_out_one[3]=router:noc_router_two|flit_out_one[3]~reg0 \ + flit_out_one[4]=router:noc_router_two|flit_out_one[4]~reg0 \ + flit_out_one[5]=router:noc_router_two|flit_out_one[5]~reg0 \ + flit_out_one[6]=router:noc_router_two|flit_out_one[6]~reg0 \ + flit_out_one[7]=router:noc_router_two|flit_out_one[7]~reg0 \ + flit_out_one[8]=router:noc_router_two|flit_out_one[8]~reg0 \ + flit_out_one[9]=router:noc_router_two|flit_out_one[9]~reg0 \ + flit_out_one[10]=router:noc_router_two|flit_out_one[10]~reg0 \ + flit_out_one[11]=router:noc_router_two|flit_out_one[11]~reg0 \ + flit_out_one[12]=router:noc_router_two|flit_out_one[12]~reg0 \ + flit_out_one[13]=router:noc_router_two|flit_out_one[13]~reg0 \ + flit_out_one[14]=router:noc_router_two|flit_out_one[14]~reg0 \ + flit_out_one[15]=router:noc_router_two|flit_out_one[15]~reg0 \ + flit_out_one[16]=router:noc_router_two|flit_out_one[16]~reg0 \ + flit_out_one[17]=router:noc_router_two|flit_out_one[17]~reg0 \ + flit_out_one[18]=router:noc_router_two|flit_out_one[18]~reg0 \ + flit_out_one[19]=router:noc_router_two|flit_out_one[19]~reg0 \ + flit_out_one[20]=router:noc_router_two|flit_out_one[20]~reg0 \ + flit_out_one[21]=router:noc_router_two|flit_out_one[21]~reg0 \ + flit_out_one[22]=router:noc_router_two|flit_out_one[22]~reg0 \ + flit_out_one[23]=router:noc_router_two|flit_out_one[23]~reg0 \ + flit_out_one[24]=router:noc_router_two|flit_out_one[24]~reg0 \ + flit_out_one[25]=router:noc_router_two|flit_out_one[25]~reg0 \ + flit_out_one[26]=router:noc_router_two|flit_out_one[26]~reg0 \ + flit_out_one[27]=router:noc_router_two|flit_out_one[27]~reg0 \ + flit_out_one[28]=router:noc_router_two|flit_out_one[28]~reg0 \ + flit_out_one[29]=router:noc_router_two|flit_out_one[29]~reg0 \ + flit_out_one[30]=router:noc_router_two|flit_out_one[30]~reg0 \ + flit_out_one[31]=router:noc_router_two|flit_out_one[31]~reg0 + +# Subckt 13: router:noc_router_three| +.subckt router \ + i_clk=clk \ + flit_in_two[0]=router:noc_router_two|flit_out_one[0]~reg0 \ + flit_in_two[1]=router:noc_router_two|flit_out_one[1]~reg0 \ + flit_in_two[2]=router:noc_router_two|flit_out_one[2]~reg0 \ + flit_in_two[3]=router:noc_router_two|flit_out_one[3]~reg0 \ + flit_in_two[4]=router:noc_router_two|flit_out_one[4]~reg0 \ + flit_in_two[5]=router:noc_router_two|flit_out_one[5]~reg0 \ + flit_in_two[6]=router:noc_router_two|flit_out_one[6]~reg0 \ + flit_in_two[7]=router:noc_router_two|flit_out_one[7]~reg0 \ + flit_in_two[8]=router:noc_router_two|flit_out_one[8]~reg0 \ + flit_in_two[9]=router:noc_router_two|flit_out_one[9]~reg0 \ + flit_in_two[10]=router:noc_router_two|flit_out_one[10]~reg0 \ + flit_in_two[11]=router:noc_router_two|flit_out_one[11]~reg0 \ + flit_in_two[12]=router:noc_router_two|flit_out_one[12]~reg0 \ + flit_in_two[13]=router:noc_router_two|flit_out_one[13]~reg0 \ + flit_in_two[14]=router:noc_router_two|flit_out_one[14]~reg0 \ + flit_in_two[15]=router:noc_router_two|flit_out_one[15]~reg0 \ + flit_in_two[16]=router:noc_router_two|flit_out_one[16]~reg0 \ + flit_in_two[17]=router:noc_router_two|flit_out_one[17]~reg0 \ + flit_in_two[18]=router:noc_router_two|flit_out_one[18]~reg0 \ + flit_in_two[19]=router:noc_router_two|flit_out_one[19]~reg0 \ + flit_in_two[20]=router:noc_router_two|flit_out_one[20]~reg0 \ + flit_in_two[21]=router:noc_router_two|flit_out_one[21]~reg0 \ + flit_in_two[22]=router:noc_router_two|flit_out_one[22]~reg0 \ + flit_in_two[23]=router:noc_router_two|flit_out_one[23]~reg0 \ + flit_in_two[24]=router:noc_router_two|flit_out_one[24]~reg0 \ + flit_in_two[25]=router:noc_router_two|flit_out_one[25]~reg0 \ + flit_in_two[26]=router:noc_router_two|flit_out_one[26]~reg0 \ + flit_in_two[27]=router:noc_router_two|flit_out_one[27]~reg0 \ + flit_in_two[28]=router:noc_router_two|flit_out_one[28]~reg0 \ + flit_in_two[29]=router:noc_router_two|flit_out_one[29]~reg0 \ + flit_in_two[30]=router:noc_router_two|flit_out_one[30]~reg0 \ + flit_in_two[31]=router:noc_router_two|flit_out_one[31]~reg0 \ + flit_in_one[0]=~GND \ + flit_in_one[1]=~GND \ + flit_in_one[2]=~GND \ + flit_in_one[3]=~GND \ + flit_in_one[4]=~GND \ + flit_in_one[5]=~GND \ + flit_in_one[6]=~GND \ + flit_in_one[7]=~GND \ + flit_in_one[8]=~GND \ + flit_in_one[9]=~GND \ + flit_in_one[10]=~GND \ + flit_in_one[11]=~GND \ + flit_in_one[12]=~GND \ + flit_in_one[13]=~GND \ + flit_in_one[14]=~GND \ + flit_in_one[15]=~GND \ + flit_in_one[16]=~GND \ + flit_in_one[17]=~GND \ + flit_in_one[18]=~GND \ + flit_in_one[19]=~GND \ + flit_in_one[20]=~GND \ + flit_in_one[21]=~GND \ + flit_in_one[22]=~GND \ + flit_in_one[23]=~GND \ + flit_in_one[24]=~GND \ + flit_in_one[25]=~GND \ + flit_in_one[26]=~GND \ + flit_in_one[27]=~GND \ + flit_in_one[28]=~GND \ + flit_in_one[29]=~GND \ + flit_in_one[30]=~GND \ + flit_in_one[31]=~GND \ + flit_out_two[0]=router:noc_router_three|flit_out_two[0]~reg0 \ + flit_out_two[1]=router:noc_router_three|flit_out_two[1]~reg0 \ + flit_out_two[2]=router:noc_router_three|flit_out_two[2]~reg0 \ + flit_out_two[3]=router:noc_router_three|flit_out_two[3]~reg0 \ + flit_out_two[4]=router:noc_router_three|flit_out_two[4]~reg0 \ + flit_out_two[5]=router:noc_router_three|flit_out_two[5]~reg0 \ + flit_out_two[6]=router:noc_router_three|flit_out_two[6]~reg0 \ + flit_out_two[7]=router:noc_router_three|flit_out_two[7]~reg0 \ + flit_out_two[8]=router:noc_router_three|flit_out_two[8]~reg0 \ + flit_out_two[9]=router:noc_router_three|flit_out_two[9]~reg0 \ + flit_out_two[10]=router:noc_router_three|flit_out_two[10]~reg0 \ + flit_out_two[11]=router:noc_router_three|flit_out_two[11]~reg0 \ + flit_out_two[12]=router:noc_router_three|flit_out_two[12]~reg0 \ + flit_out_two[13]=router:noc_router_three|flit_out_two[13]~reg0 \ + flit_out_two[14]=router:noc_router_three|flit_out_two[14]~reg0 \ + flit_out_two[15]=router:noc_router_three|flit_out_two[15]~reg0 \ + flit_out_two[16]=router:noc_router_three|flit_out_two[16]~reg0 \ + flit_out_two[17]=router:noc_router_three|flit_out_two[17]~reg0 \ + flit_out_two[18]=router:noc_router_three|flit_out_two[18]~reg0 \ + flit_out_two[19]=router:noc_router_three|flit_out_two[19]~reg0 \ + flit_out_two[20]=router:noc_router_three|flit_out_two[20]~reg0 \ + flit_out_two[21]=router:noc_router_three|flit_out_two[21]~reg0 \ + flit_out_two[22]=router:noc_router_three|flit_out_two[22]~reg0 \ + flit_out_two[23]=router:noc_router_three|flit_out_two[23]~reg0 \ + flit_out_two[24]=router:noc_router_three|flit_out_two[24]~reg0 \ + flit_out_two[25]=router:noc_router_three|flit_out_two[25]~reg0 \ + flit_out_two[26]=router:noc_router_three|flit_out_two[26]~reg0 \ + flit_out_two[27]=router:noc_router_three|flit_out_two[27]~reg0 \ + flit_out_two[28]=router:noc_router_three|flit_out_two[28]~reg0 \ + flit_out_two[29]=router:noc_router_three|flit_out_two[29]~reg0 \ + flit_out_two[30]=router:noc_router_three|flit_out_two[30]~reg0 \ + flit_out_two[31]=router:noc_router_three|flit_out_two[31]~reg0 \ + flit_out_one[0]=router:noc_router_three|flit_out_one[0]~reg0 \ + flit_out_one[1]=router:noc_router_three|flit_out_one[1]~reg0 \ + flit_out_one[2]=router:noc_router_three|flit_out_one[2]~reg0 \ + flit_out_one[3]=router:noc_router_three|flit_out_one[3]~reg0 \ + flit_out_one[4]=router:noc_router_three|flit_out_one[4]~reg0 \ + flit_out_one[5]=router:noc_router_three|flit_out_one[5]~reg0 \ + flit_out_one[6]=router:noc_router_three|flit_out_one[6]~reg0 \ + flit_out_one[7]=router:noc_router_three|flit_out_one[7]~reg0 \ + flit_out_one[8]=router:noc_router_three|flit_out_one[8]~reg0 \ + flit_out_one[9]=router:noc_router_three|flit_out_one[9]~reg0 \ + flit_out_one[10]=router:noc_router_three|flit_out_one[10]~reg0 \ + flit_out_one[11]=router:noc_router_three|flit_out_one[11]~reg0 \ + flit_out_one[12]=router:noc_router_three|flit_out_one[12]~reg0 \ + flit_out_one[13]=router:noc_router_three|flit_out_one[13]~reg0 \ + flit_out_one[14]=router:noc_router_three|flit_out_one[14]~reg0 \ + flit_out_one[15]=router:noc_router_three|flit_out_one[15]~reg0 \ + flit_out_one[16]=router:noc_router_three|flit_out_one[16]~reg0 \ + flit_out_one[17]=router:noc_router_three|flit_out_one[17]~reg0 \ + flit_out_one[18]=router:noc_router_three|flit_out_one[18]~reg0 \ + flit_out_one[19]=router:noc_router_three|flit_out_one[19]~reg0 \ + flit_out_one[20]=router:noc_router_three|flit_out_one[20]~reg0 \ + flit_out_one[21]=router:noc_router_three|flit_out_one[21]~reg0 \ + flit_out_one[22]=router:noc_router_three|flit_out_one[22]~reg0 \ + flit_out_one[23]=router:noc_router_three|flit_out_one[23]~reg0 \ + flit_out_one[24]=router:noc_router_three|flit_out_one[24]~reg0 \ + flit_out_one[25]=router:noc_router_three|flit_out_one[25]~reg0 \ + flit_out_one[26]=router:noc_router_three|flit_out_one[26]~reg0 \ + flit_out_one[27]=router:noc_router_three|flit_out_one[27]~reg0 \ + flit_out_one[28]=router:noc_router_three|flit_out_one[28]~reg0 \ + flit_out_one[29]=router:noc_router_three|flit_out_one[29]~reg0 \ + flit_out_one[30]=router:noc_router_three|flit_out_one[30]~reg0 \ + flit_out_one[31]=router:noc_router_three|flit_out_one[31]~reg0 + +# Subckt 14: router:noc_router_one| +.subckt router \ + i_clk=clk \ + flit_in_two[0]=~GND \ + flit_in_two[1]=~GND \ + flit_in_two[2]=~GND \ + flit_in_two[3]=~GND \ + flit_in_two[4]=~GND \ + flit_in_two[5]=~GND \ + flit_in_two[6]=~GND \ + flit_in_two[7]=~GND \ + flit_in_two[8]=~GND \ + flit_in_two[9]=~GND \ + flit_in_two[10]=~GND \ + flit_in_two[11]=~GND \ + flit_in_two[12]=~GND \ + flit_in_two[13]=~GND \ + flit_in_two[14]=~GND \ + flit_in_two[15]=~GND \ + flit_in_two[16]=~GND \ + flit_in_two[17]=~GND \ + flit_in_two[18]=~GND \ + flit_in_two[19]=~GND \ + flit_in_two[20]=~GND \ + flit_in_two[21]=~GND \ + flit_in_two[22]=~GND \ + flit_in_two[23]=~GND \ + flit_in_two[24]=~GND \ + flit_in_two[25]=~GND \ + flit_in_two[26]=~GND \ + flit_in_two[27]=~GND \ + flit_in_two[28]=~GND \ + flit_in_two[29]=~GND \ + flit_in_two[30]=~GND \ + flit_in_two[31]=~GND \ + flit_in_one[0]=Add0~1 \ + flit_in_one[1]=Add0~5 \ + flit_in_one[2]=Add0~9 \ + flit_in_one[3]=Add0~13 \ + flit_in_one[4]=Add0~17 \ + flit_in_one[5]=Add0~21 \ + flit_in_one[6]=Add0~25 \ + flit_in_one[7]=Add0~29 \ + flit_in_one[8]=Add0~33 \ + flit_in_one[9]=~GND \ + flit_in_one[10]=~GND \ + flit_in_one[11]=~GND \ + flit_in_one[12]=~GND \ + flit_in_one[13]=~GND \ + flit_in_one[14]=~GND \ + flit_in_one[15]=~GND \ + flit_in_one[16]=noc_input[16] \ + flit_in_one[17]=i_id[0] \ + flit_in_one[18]=i_id[1] \ + flit_in_one[19]=i_id[2] \ + flit_in_one[20]=i_id[3] \ + flit_in_one[21]=~GND \ + flit_in_one[22]=~GND \ + flit_in_one[23]=~GND \ + flit_in_one[24]=~GND \ + flit_in_one[25]=~GND \ + flit_in_one[26]=~GND \ + flit_in_one[27]=~GND \ + flit_in_one[28]=~GND \ + flit_in_one[29]=~GND \ + flit_in_one[30]=~GND \ + flit_in_one[31]=~GND \ + flit_out_two[0]=router:noc_router_one|flit_out_two[0]~reg0 \ + flit_out_two[1]=router:noc_router_one|flit_out_two[1]~reg0 \ + flit_out_two[2]=router:noc_router_one|flit_out_two[2]~reg0 \ + flit_out_two[3]=router:noc_router_one|flit_out_two[3]~reg0 \ + flit_out_two[4]=router:noc_router_one|flit_out_two[4]~reg0 \ + flit_out_two[5]=router:noc_router_one|flit_out_two[5]~reg0 \ + flit_out_two[6]=router:noc_router_one|flit_out_two[6]~reg0 \ + flit_out_two[7]=router:noc_router_one|flit_out_two[7]~reg0 \ + flit_out_two[8]=router:noc_router_one|flit_out_two[8]~reg0 \ + flit_out_two[9]=router:noc_router_one|flit_out_two[9]~reg0 \ + flit_out_two[10]=router:noc_router_one|flit_out_two[10]~reg0 \ + flit_out_two[11]=router:noc_router_one|flit_out_two[11]~reg0 \ + flit_out_two[12]=router:noc_router_one|flit_out_two[12]~reg0 \ + flit_out_two[13]=router:noc_router_one|flit_out_two[13]~reg0 \ + flit_out_two[14]=router:noc_router_one|flit_out_two[14]~reg0 \ + flit_out_two[15]=router:noc_router_one|flit_out_two[15]~reg0 \ + flit_out_two[16]=router:noc_router_one|flit_out_two[16]~reg0 \ + flit_out_two[17]=router:noc_router_one|flit_out_two[17]~reg0 \ + flit_out_two[18]=router:noc_router_one|flit_out_two[18]~reg0 \ + flit_out_two[19]=router:noc_router_one|flit_out_two[19]~reg0 \ + flit_out_two[20]=router:noc_router_one|flit_out_two[20]~reg0 \ + flit_out_two[21]=router:noc_router_one|flit_out_two[21]~reg0 \ + flit_out_two[22]=router:noc_router_one|flit_out_two[22]~reg0 \ + flit_out_two[23]=router:noc_router_one|flit_out_two[23]~reg0 \ + flit_out_two[24]=router:noc_router_one|flit_out_two[24]~reg0 \ + flit_out_two[25]=router:noc_router_one|flit_out_two[25]~reg0 \ + flit_out_two[26]=router:noc_router_one|flit_out_two[26]~reg0 \ + flit_out_two[27]=router:noc_router_one|flit_out_two[27]~reg0 \ + flit_out_two[28]=router:noc_router_one|flit_out_two[28]~reg0 \ + flit_out_two[29]=router:noc_router_one|flit_out_two[29]~reg0 \ + flit_out_two[30]=router:noc_router_one|flit_out_two[30]~reg0 \ + flit_out_two[31]=router:noc_router_one|flit_out_two[31]~reg0 \ + flit_out_one[0]=router:noc_router_one|flit_out_one[0]~reg0 \ + flit_out_one[1]=router:noc_router_one|flit_out_one[1]~reg0 \ + flit_out_one[2]=router:noc_router_one|flit_out_one[2]~reg0 \ + flit_out_one[3]=router:noc_router_one|flit_out_one[3]~reg0 \ + flit_out_one[4]=router:noc_router_one|flit_out_one[4]~reg0 \ + flit_out_one[5]=router:noc_router_one|flit_out_one[5]~reg0 \ + flit_out_one[6]=router:noc_router_one|flit_out_one[6]~reg0 \ + flit_out_one[7]=router:noc_router_one|flit_out_one[7]~reg0 \ + flit_out_one[8]=router:noc_router_one|flit_out_one[8]~reg0 \ + flit_out_one[9]=router:noc_router_one|flit_out_one[9]~reg0 \ + flit_out_one[10]=router:noc_router_one|flit_out_one[10]~reg0 \ + flit_out_one[11]=router:noc_router_one|flit_out_one[11]~reg0 \ + flit_out_one[12]=router:noc_router_one|flit_out_one[12]~reg0 \ + flit_out_one[13]=router:noc_router_one|flit_out_one[13]~reg0 \ + flit_out_one[14]=router:noc_router_one|flit_out_one[14]~reg0 \ + flit_out_one[15]=router:noc_router_one|flit_out_one[15]~reg0 \ + flit_out_one[16]=router:noc_router_one|flit_out_one[16]~reg0 \ + flit_out_one[17]=router:noc_router_one|flit_out_one[17]~reg0 \ + flit_out_one[18]=router:noc_router_one|flit_out_one[18]~reg0 \ + flit_out_one[19]=router:noc_router_one|flit_out_one[19]~reg0 \ + flit_out_one[20]=router:noc_router_one|flit_out_one[20]~reg0 \ + flit_out_one[21]=router:noc_router_one|flit_out_one[21]~reg0 \ + flit_out_one[22]=router:noc_router_one|flit_out_one[22]~reg0 \ + flit_out_one[23]=router:noc_router_one|flit_out_one[23]~reg0 \ + flit_out_one[24]=router:noc_router_one|flit_out_one[24]~reg0 \ + flit_out_one[25]=router:noc_router_one|flit_out_one[25]~reg0 \ + flit_out_one[26]=router:noc_router_one|flit_out_one[26]~reg0 \ + flit_out_one[27]=router:noc_router_one|flit_out_one[27]~reg0 \ + flit_out_one[28]=router:noc_router_one|flit_out_one[28]~reg0 \ + flit_out_one[29]=router:noc_router_one|flit_out_one[29]~reg0 \ + flit_out_one[30]=router:noc_router_one|flit_out_one[30]~reg0 \ + flit_out_one[31]=router:noc_router_one|flit_out_one[31]~reg0 + +# Subckt 15: o_flag~0_I +.subckt stratixiv_lcell_comb \ + datab=router:noc_router_four|flit_out_one[3]~reg0 \ + dataa=router:noc_router_four|flit_out_one[0]~reg0 \ + combout=o_flag + +.end + +#SUBCKT MODELS + +.model router +.inputs \ + i_clk \ + flit_in_two[0] \ + flit_in_two[1] \ + flit_in_two[2] \ + flit_in_two[3] \ + flit_in_two[4] \ + flit_in_two[5] \ + flit_in_two[6] \ + flit_in_two[7] \ + flit_in_two[8] \ + flit_in_two[9] \ + flit_in_two[10] \ + flit_in_two[11] \ + flit_in_two[12] \ + flit_in_two[13] \ + flit_in_two[14] \ + flit_in_two[15] \ + flit_in_two[16] \ + flit_in_two[17] \ + flit_in_two[18] \ + flit_in_two[19] \ + flit_in_two[20] \ + flit_in_two[21] \ + flit_in_two[22] \ + flit_in_two[23] \ + flit_in_two[24] \ + flit_in_two[25] \ + flit_in_two[26] \ + flit_in_two[27] \ + flit_in_two[28] \ + flit_in_two[29] \ + flit_in_two[30] \ + flit_in_two[31] \ + flit_in_one[0] \ + flit_in_one[1] \ + flit_in_one[2] \ + flit_in_one[3] \ + flit_in_one[4] \ + flit_in_one[5] \ + flit_in_one[6] \ + flit_in_one[7] \ + flit_in_one[8] \ + flit_in_one[9] \ + flit_in_one[10] \ + flit_in_one[11] \ + flit_in_one[12] \ + flit_in_one[13] \ + flit_in_one[14] \ + flit_in_one[15] \ + flit_in_one[16] \ + flit_in_one[17] \ + flit_in_one[18] \ + flit_in_one[19] \ + flit_in_one[20] \ + flit_in_one[21] \ + flit_in_one[22] \ + flit_in_one[23] \ + flit_in_one[24] \ + flit_in_one[25] \ + flit_in_one[26] \ + flit_in_one[27] \ + flit_in_one[28] \ + flit_in_one[29] \ + flit_in_one[30] \ + flit_in_one[31] +.outputs \ + flit_out_two[0] \ + flit_out_two[1] \ + flit_out_two[2] \ + flit_out_two[3] \ + flit_out_two[4] \ + flit_out_two[5] \ + flit_out_two[6] \ + flit_out_two[7] \ + flit_out_two[8] \ + flit_out_two[9] \ + flit_out_two[10] \ + flit_out_two[11] \ + flit_out_two[12] \ + flit_out_two[13] \ + flit_out_two[14] \ + flit_out_two[15] \ + flit_out_two[16] \ + flit_out_two[17] \ + flit_out_two[18] \ + flit_out_two[19] \ + flit_out_two[20] \ + flit_out_two[21] \ + flit_out_two[22] \ + flit_out_two[23] \ + flit_out_two[24] \ + flit_out_two[25] \ + flit_out_two[26] \ + flit_out_two[27] \ + flit_out_two[28] \ + flit_out_two[29] \ + flit_out_two[30] \ + flit_out_two[31] \ + flit_out_one[0] \ + flit_out_one[1] \ + flit_out_one[2] \ + flit_out_one[3] \ + flit_out_one[4] \ + flit_out_one[5] \ + flit_out_one[6] \ + flit_out_one[7] \ + flit_out_one[8] \ + flit_out_one[9] \ + flit_out_one[10] \ + flit_out_one[11] \ + flit_out_one[12] \ + flit_out_one[13] \ + flit_out_one[14] \ + flit_out_one[15] \ + flit_out_one[16] \ + flit_out_one[17] \ + flit_out_one[18] \ + flit_out_one[19] \ + flit_out_one[20] \ + flit_out_one[21] \ + flit_out_one[22] \ + flit_out_one[23] \ + flit_out_one[24] \ + flit_out_one[25] \ + flit_out_one[26] \ + flit_out_one[27] \ + flit_out_one[28] \ + flit_out_one[29] \ + flit_out_one[30] \ + flit_out_one[31] +.blackbox +.end + +.model stratixiv_lcell_comb +.inputs \ + sharein \ + cin \ + datag \ + dataf \ + datae \ + datad \ + datac \ + datab \ + dataa +.outputs \ + shareout \ + cout \ + sumout \ + combout +.blackbox +.end diff --git a/vtr_flow/benchmarks/noc/Test_Designs/test_design_for_noc_traffic_flows_feature/multiple_noc_routers.flows b/vtr_flow/benchmarks/noc/Test_Designs/test_design_for_noc_traffic_flows_feature/multiple_noc_routers.flows new file mode 100755 index 00000000000..6b8a7fa385b --- /dev/null +++ b/vtr_flow/benchmarks/noc/Test_Designs/test_design_for_noc_traffic_flows_feature/multiple_noc_routers.flows @@ -0,0 +1,7 @@ + + + + + + + From 55c8ae4a46fc4481a0481634b359a2b0b538ba15 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Thu, 30 Jun 2022 15:59:51 -0400 Subject: [PATCH 103/128] Grouped all NoC related files together within the noc folder inside ./vpr/src. This was done so that related files are found together. --- vpr/src/{base => noc}/noc_data_types.h | 0 vpr/src/{base => noc}/noc_link.cpp | 0 vpr/src/{base => noc}/noc_link.h | 0 vpr/src/{base => noc}/noc_router.cpp | 0 vpr/src/{base => noc}/noc_router.h | 0 vpr/src/{base => noc}/noc_storage.cpp | 0 vpr/src/{base => noc}/noc_storage.h | 0 7 files changed, 0 insertions(+), 0 deletions(-) rename vpr/src/{base => noc}/noc_data_types.h (100%) rename vpr/src/{base => noc}/noc_link.cpp (100%) rename vpr/src/{base => noc}/noc_link.h (100%) rename vpr/src/{base => noc}/noc_router.cpp (100%) rename vpr/src/{base => noc}/noc_router.h (100%) rename vpr/src/{base => noc}/noc_storage.cpp (100%) rename vpr/src/{base => noc}/noc_storage.h (100%) diff --git a/vpr/src/base/noc_data_types.h b/vpr/src/noc/noc_data_types.h similarity index 100% rename from vpr/src/base/noc_data_types.h rename to vpr/src/noc/noc_data_types.h diff --git a/vpr/src/base/noc_link.cpp b/vpr/src/noc/noc_link.cpp similarity index 100% rename from vpr/src/base/noc_link.cpp rename to vpr/src/noc/noc_link.cpp diff --git a/vpr/src/base/noc_link.h b/vpr/src/noc/noc_link.h similarity index 100% rename from vpr/src/base/noc_link.h rename to vpr/src/noc/noc_link.h diff --git a/vpr/src/base/noc_router.cpp b/vpr/src/noc/noc_router.cpp similarity index 100% rename from vpr/src/base/noc_router.cpp rename to vpr/src/noc/noc_router.cpp diff --git a/vpr/src/base/noc_router.h b/vpr/src/noc/noc_router.h similarity index 100% rename from vpr/src/base/noc_router.h rename to vpr/src/noc/noc_router.h diff --git a/vpr/src/base/noc_storage.cpp b/vpr/src/noc/noc_storage.cpp similarity index 100% rename from vpr/src/base/noc_storage.cpp rename to vpr/src/noc/noc_storage.cpp diff --git a/vpr/src/base/noc_storage.h b/vpr/src/noc/noc_storage.h similarity index 100% rename from vpr/src/base/noc_storage.h rename to vpr/src/noc/noc_storage.h From abc735b2e8430932e2a60481384ad177b5f54450 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 4 Jul 2022 18:22:08 -0400 Subject: [PATCH 104/128] Added a function to clear the global clustered netlist. This function was then called at the end of all unit tests that used the global clustered netlist. This was done because multiple unit tests use the global clustered netlist, and not clearing the netlist would cause corruption in other unit tests. There was also a segfault with the clear function that was caused by passing an empty physical type whenever a new cluster was created, so this was changed to just passing a null physical type. --- .../test_read_xml_noc_traffic_flows_file.cpp | 81 ++++++++++++------- 1 file changed, 54 insertions(+), 27 deletions(-) diff --git a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp index d6139d56971..83f6f45cb95 100644 --- a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp +++ b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp @@ -7,6 +7,21 @@ namespace { +/* + * Delete all the blocks in the global clustered netlist. + * Then create an empty clustered netlist and assign it + * to the globabl clustered netlist. + */ +void free_clustered_netlist(void) { + auto& cluster_ctx = g_vpr_ctx.mutable_clustering(); + + for (auto blk_id : cluster_ctx.clb_nlist.blocks()) { + cluster_ctx.clb_nlist.remove_block(blk_id); + } + + cluster_ctx.clb_nlist = ClusteredNetlist(); +} + TEST_CASE("test_verify_traffic_flow_router_modules", "[vpr_noc_traffic_flows_parser]") { // filler data for the xml information // data for the xml parsing @@ -80,14 +95,12 @@ TEST_CASE("test_get_router_module_cluster_id", "[vpr_noc_traffic_flows_parser]") char router[] = "router"; router_block.name = router; t_logical_block_type_ptr router_ref = &router_block; - t_pb router_pb; // second logical router block t_logical_block_type router_block_2; char router_2[] = "router_2"; router_block_2.name = router_2; t_logical_block_type_ptr router_ref_2 = &router_block_2; - t_pb router_2_pb; // add these two logical tyes as the equivalent sites of the subtile router_tile.equivalent_sites.push_back(router_ref); @@ -106,7 +119,6 @@ TEST_CASE("test_get_router_module_cluster_id", "[vpr_noc_traffic_flows_parser]") char i_o[] = "IO"; i_o_block.name = i_o; t_logical_block_type_ptr i_o_ref = &i_o_block; - t_pb io_pb; // create some sample IO blocks in the clustered netlist // These will act as fillers to make sure that the find block function correctly handles a netlist with different types of blocks @@ -118,10 +130,10 @@ TEST_CASE("test_get_router_module_cluster_id", "[vpr_noc_traffic_flows_parser]") char io_port_four[] = "io_port_four"; // add the io blocks to the netlist - block_id_from_name.emplace(io_port_one, test_netlist->create_block(io_port_one, &io_pb, i_o_ref)); - block_id_from_name.emplace(io_port_two, test_netlist->create_block(io_port_two, &io_pb, i_o_ref)); - block_id_from_name.emplace(io_port_three, test_netlist->create_block(io_port_three, &io_pb, i_o_ref)); - block_id_from_name.emplace(io_port_four, test_netlist->create_block(io_port_four, &io_pb, i_o_ref)); + block_id_from_name.emplace(io_port_one, test_netlist->create_block(io_port_one, nullptr, i_o_ref)); + block_id_from_name.emplace(io_port_two, test_netlist->create_block(io_port_two, nullptr, i_o_ref)); + block_id_from_name.emplace(io_port_three, test_netlist->create_block(io_port_three, nullptr, i_o_ref)); + block_id_from_name.emplace(io_port_four, test_netlist->create_block(io_port_four, nullptr, i_o_ref)); SECTION("Test case where the block is found in the clustered netlist") { // create names for some router blocks @@ -131,17 +143,17 @@ TEST_CASE("test_get_router_module_cluster_id", "[vpr_noc_traffic_flows_parser]") char router_four[] = "router:noc_router_four|flit_out_two[0]~reg0"; // add the router blocks - block_id_from_name.emplace(router_one, test_netlist->create_block(router_one, &router_pb, router_ref)); - block_id_from_name.emplace(router_two, test_netlist->create_block(router_two, &router_pb, router_ref)); - block_id_from_name.emplace(router_three, test_netlist->create_block(router_three, &router_pb, router_ref)); - block_id_from_name.emplace(router_four, test_netlist->create_block(router_four, &router_pb, router_ref)); + block_id_from_name.emplace(router_one, test_netlist->create_block(router_one, nullptr, router_ref)); + block_id_from_name.emplace(router_two, test_netlist->create_block(router_two, nullptr, router_ref)); + block_id_from_name.emplace(router_three, test_netlist->create_block(router_three, nullptr, router_ref)); + block_id_from_name.emplace(router_four, test_netlist->create_block(router_four, nullptr, router_ref)); // create additional router blocks char router_five[] = "router:noc_router_five|flit_out_two[0]~reg0"; char router_six[] = "router:noc_router_six|flit_out_two[0]~reg0"; - block_id_from_name.emplace(router_five, test_netlist->create_block(router_five, &router_2_pb, router_ref_2)); - block_id_from_name.emplace(router_six, test_netlist->create_block(router_six, &router_2_pb, router_ref_2)); + block_id_from_name.emplace(router_five, test_netlist->create_block(router_five, nullptr, router_ref_2)); + block_id_from_name.emplace(router_six, test_netlist->create_block(router_six, nullptr, router_ref_2)); // now find a block just knowing its instance name std::string test_router_module_name = ".*noc_router_five.*"; @@ -151,6 +163,9 @@ TEST_CASE("test_get_router_module_cluster_id", "[vpr_noc_traffic_flows_parser]") REQUIRE_NOTHROW(test_router_block_id = get_router_module_cluster_id(test_router_module_name, cluster_ctx, test, test_location, noc_router_ref)); REQUIRE((size_t)(block_id_from_name.find("router:noc_router_five|flit_out_two[0]~reg0")->second) == (size_t)test_router_block_id); + + // clear the global netlist datastructure so other unit tests that rely on dont use a corrupted netlist + free_clustered_netlist(); } SECTION("Test case where the block is not found in the clustered netlist") { // create names for some router blocks @@ -160,17 +175,17 @@ TEST_CASE("test_get_router_module_cluster_id", "[vpr_noc_traffic_flows_parser]") char router_four[] = "router:noc_router_four|flit_out_two[0]~reg0"; // add the router blocks - block_id_from_name.emplace(router_one, test_netlist->create_block(router_one, &router_pb, router_ref)); - block_id_from_name.emplace(router_two, test_netlist->create_block(router_two, &router_pb, router_ref)); - block_id_from_name.emplace(router_three, test_netlist->create_block(router_three, &router_pb, router_ref)); - block_id_from_name.emplace(router_four, test_netlist->create_block(router_four, &router_pb, router_ref)); + block_id_from_name.emplace(router_one, test_netlist->create_block(router_one, nullptr, router_ref)); + block_id_from_name.emplace(router_two, test_netlist->create_block(router_two, nullptr, router_ref)); + block_id_from_name.emplace(router_three, test_netlist->create_block(router_three, nullptr, router_ref)); + block_id_from_name.emplace(router_four, test_netlist->create_block(router_four, nullptr, router_ref)); // create additional router blocks char router_five[] = "router:noc_router_five|flit_out_two[0]~reg0"; char router_six[] = "router:noc_router_six|flit_out_two[0]~reg0"; - block_id_from_name.emplace(router_five, test_netlist->create_block(router_five, &router_2_pb, router_ref_2)); - block_id_from_name.emplace(router_six, test_netlist->create_block(router_six, &router_2_pb, router_ref_2)); + block_id_from_name.emplace(router_five, test_netlist->create_block(router_five, nullptr, router_ref_2)); + block_id_from_name.emplace(router_six, test_netlist->create_block(router_six, nullptr, router_ref_2)); // now find a block just knowing its name. Choosing a block name that doesn't exist std::string test_router_module_name = "^router:noc_router_seven|flit_out_two[0]~reg0$"; @@ -178,6 +193,9 @@ TEST_CASE("test_get_router_module_cluster_id", "[vpr_noc_traffic_flows_parser]") // now get the cluster id of the block with the test router name using the function we are testing // This should fail, so check that it does REQUIRE_THROWS_WITH(get_router_module_cluster_id(test_router_module_name, cluster_ctx, test, test_location, noc_router_ref), "The router module '^router:noc_router_seven|flit_out_two[0]~reg0$' does not exist in the design."); + + // clear the global netlist datastructure so other unit tests that rely on dont use a corrupted netlist + free_clustered_netlist(); } } TEST_CASE("test_check_traffic_flow_router_module_type", "[vpr_noc_traffic_flows_parser]") { @@ -205,7 +223,6 @@ TEST_CASE("test_check_traffic_flow_router_module_type", "[vpr_noc_traffic_flows_ char router[] = "router"; router_block.name = router; t_logical_block_type_ptr router_ref = &router_block; - t_pb router_pb; // add the logical tyes as the equivalent sites of the subtile router_tile.equivalent_sites.push_back(router_ref); @@ -226,29 +243,34 @@ TEST_CASE("test_check_traffic_flow_router_module_type", "[vpr_noc_traffic_flows_ char i_o[] = "IO"; i_o_block.name = i_o; t_logical_block_type_ptr i_o_ref = &i_o_block; - t_pb io_pb; SECTION("Test case where the traffic flow module is of type router") { // create a name for a router block char router_one[] = "router:noc_router_one|flit_out_two[0]~reg0"; // create a cluster block that represents a router module - ClusterBlockId router_module_id = test_netlist->create_block(router_one, &router_pb, router_ref); + ClusterBlockId router_module_id = test_netlist->create_block(router_one, nullptr, router_ref); // now run the test function to verify that the current router module has a logical type of a router // the function should not fail since the module is a router REQUIRE_NOTHROW(check_traffic_flow_router_module_type(router_one, router_module_id, test, test_location, cluster_ctx, noc_router_ref)); + + // clear the global netlist datastructure so other unit tests that rely on dont use a corrupted netlist + free_clustered_netlist(); } SECTION("Test case where the traffic flow module is not of type router") { // create a name for a IO block char io_block_one[] = "io_block_one"; // create a cluster blcok that represents a IO block - ClusterBlockId io_module_id = test_netlist->create_block(io_block_one, &io_pb, i_o_ref); + ClusterBlockId io_module_id = test_netlist->create_block(io_block_one, nullptr, i_o_ref); // now run the test function to verify that the current IO module doesnt have a logical type of a router // the function should faile since the module is of type IO REQUIRE_THROWS_WITH(check_traffic_flow_router_module_type(io_block_one, io_module_id, test, test_location, cluster_ctx, noc_router_ref), "The supplied module name 'io_block_one' is not a NoC router."); + + // clear the global netlist datastructure so other unit tests that rely on dont use a corrupted netlist + free_clustered_netlist(); } } TEST_CASE("test_check_that_all_router_blocks_have_an_associated_traffic_flow", "[vpr_noc_traffic_flows_parser]") { @@ -273,7 +295,6 @@ TEST_CASE("test_check_that_all_router_blocks_have_an_associated_traffic_flow", " char router[] = "router"; router_block.name = router; t_logical_block_type_ptr router_ref = &router_block; - t_pb router_pb; //set the index of the logical type as 0 (its the only block type in this test device) router_block.index = 0; @@ -312,9 +333,9 @@ TEST_CASE("test_check_that_all_router_blocks_have_an_associated_traffic_flow", " char router_two[] = "router_block_two"; char router_three[] = "router_block_three"; - ClusterBlockId router_block_one_id = test_netlist->create_block(router_one, &router_pb, router_ref); - ClusterBlockId router_block_two_id = test_netlist->create_block(router_two, &router_pb, router_ref); - ClusterBlockId router_block_three_id = test_netlist->create_block(router_three, &router_pb, router_ref); + ClusterBlockId router_block_one_id = test_netlist->create_block(router_one, nullptr, router_ref); + ClusterBlockId router_block_two_id = test_netlist->create_block(router_two, nullptr, router_ref); + ClusterBlockId router_block_three_id = test_netlist->create_block(router_three, nullptr, router_ref); // define the name of the test noc traffic flows file std::string test_noc_traffic_flows_file_name = "noc_traffic_flows_file.flows"; @@ -330,6 +351,9 @@ TEST_CASE("test_check_that_all_router_blocks_have_an_associated_traffic_flow", " // now check to see whether all router blocks in the design have an associated traffic flow (this is the function tested here) // we expect this to pass CHECK(check_that_all_router_blocks_have_an_associated_traffic_flow(noc_ctx, noc_router_ref, test_noc_traffic_flows_file_name) == true); + + // clear the global netlist datastructure so other unit tests that rely on dont use a corrupted netlist + free_clustered_netlist(); } SECTION("Test case where some router blocks in the design do not have an associated traffic flow") { // create a number of traffic flows that includes router_one and router_twp but does not include router_three @@ -340,6 +364,9 @@ TEST_CASE("test_check_that_all_router_blocks_have_an_associated_traffic_flow", " // now check to see whether all router blocks in the design have an associated traffic flow (this is the function tested here) // we expect this fail CHECK(check_that_all_router_blocks_have_an_associated_traffic_flow(noc_ctx, noc_router_ref, test_noc_traffic_flows_file_name) == false); + + // clear the global netlist datastructure so other unit tests that rely on dont use a corrupted netlist + free_clustered_netlist(); } } TEST_CASE("test_check_for_duplicate_traffic_flow", "[vpr_noc_traffic_flows_parser]") { From 5001d144f6fa1077085f42a684719145951b043a Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 4 Jul 2022 18:47:00 -0400 Subject: [PATCH 105/128] Added a function clear the global device datastructure. This function was then called at the end of all unit tests that used the global device. This was done so that other unit tests don't use a corrupted global device datastructure. --- vpr/test/test_read_xml_noc_traffic_flows_file.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp index 83f6f45cb95..d80165acc74 100644 --- a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp +++ b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp @@ -22,6 +22,14 @@ void free_clustered_netlist(void) { cluster_ctx.clb_nlist = ClusteredNetlist(); } +/* + * Delete all the logical block types within the global device. + */ +void free_device(void) { + auto& device_ctx = g_vpr_ctx.mutable_device(); + device_ctx.logical_block_types.clear(); +} + TEST_CASE("test_verify_traffic_flow_router_modules", "[vpr_noc_traffic_flows_parser]") { // filler data for the xml information // data for the xml parsing @@ -354,6 +362,9 @@ TEST_CASE("test_check_that_all_router_blocks_have_an_associated_traffic_flow", " // clear the global netlist datastructure so other unit tests that rely on dont use a corrupted netlist free_clustered_netlist(); + + // clear the global device + free_device(); } SECTION("Test case where some router blocks in the design do not have an associated traffic flow") { // create a number of traffic flows that includes router_one and router_twp but does not include router_three @@ -367,6 +378,9 @@ TEST_CASE("test_check_that_all_router_blocks_have_an_associated_traffic_flow", " // clear the global netlist datastructure so other unit tests that rely on dont use a corrupted netlist free_clustered_netlist(); + + // clear the global device + free_device(); } } TEST_CASE("test_check_for_duplicate_traffic_flow", "[vpr_noc_traffic_flows_parser]") { From b6aaa9abc9becaf32a9cd4d75b16ab0af2009b3b Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 4 Jul 2022 19:00:54 -0400 Subject: [PATCH 106/128] removed unneccessary files generated from running unit tests that were added accidently before --- vpr/test/packing_pin_util.rpt | 33 ----------------------- vpr/test/pre_pack.report_timing.setup.rpt | 31 --------------------- 2 files changed, 64 deletions(-) delete mode 100644 vpr/test/packing_pin_util.rpt delete mode 100644 vpr/test/pre_pack.report_timing.setup.rpt diff --git a/vpr/test/packing_pin_util.rpt b/vpr/test/packing_pin_util.rpt deleted file mode 100644 index 70137d479b3..00000000000 --- a/vpr/test/packing_pin_util.rpt +++ /dev/null @@ -1,33 +0,0 @@ -#Packing pin usage report -Type: io - Input Pin Usage: - Max: 1.00 (0.50) - Avg: 0.50 (0.25) - Min: 0.00 (0.00) - Histogram: - [ 0: 0.2) 1 ( 50.0%) |************************************************** - [ 0.2: 0.4) 0 ( 0.0%) | - [ 0.4: 0.6) 0 ( 0.0%) | - [ 0.6: 0.8) 0 ( 0.0%) | - [ 0.8: 1) 1 ( 50.0%) |************************************************** - [ 1: 1.2) 0 ( 0.0%) | - [ 1.2: 1.4) 0 ( 0.0%) | - [ 1.4: 1.6) 0 ( 0.0%) | - [ 1.6: 1.8) 0 ( 0.0%) | - [ 1.8: 2) 0 ( 0.0%) | - Output Pin Usage: - Max: 1.00 (1.00) - Avg: 0.50 (0.50) - Min: 0.00 (0.00) - Histogram: - [ 0: 0.1) 1 ( 50.0%) |************************************************** - [ 0.1: 0.2) 0 ( 0.0%) | - [ 0.2: 0.3) 0 ( 0.0%) | - [ 0.3: 0.4) 0 ( 0.0%) | - [ 0.4: 0.5) 0 ( 0.0%) | - [ 0.5: 0.6) 0 ( 0.0%) | - [ 0.6: 0.7) 0 ( 0.0%) | - [ 0.7: 0.8) 0 ( 0.0%) | - [ 0.8: 0.9) 0 ( 0.0%) | - [ 0.9: 1) 1 ( 50.0%) |************************************************** - diff --git a/vpr/test/pre_pack.report_timing.setup.rpt b/vpr/test/pre_pack.report_timing.setup.rpt deleted file mode 100644 index d56702b182a..00000000000 --- a/vpr/test/pre_pack.report_timing.setup.rpt +++ /dev/null @@ -1,31 +0,0 @@ -#Timing report of worst 1 path(s) -# Unit scale: 1e-09 seconds -# Output precision: 3 - -#Path 1 -Startpoint: di.inpad[0] (.input clocked by virtual_io_clock) -Endpoint : out:do.outpad[0] (.output clocked by virtual_io_clock) -Path Type : setup - -Point Incr Path --------------------------------------------------------------------------------- -clock virtual_io_clock (rise edge) 0.000 0.000 -clock source latency 0.000 0.000 -input external delay 0.000 0.000 -di.inpad[0] (.input) 0.000 0.000 -out:do.outpad[0] (.output) 1.338 1.338 -data arrival time 1.338 - -clock virtual_io_clock (rise edge) 0.000 0.000 -clock source latency 0.000 0.000 -clock uncertainty 0.000 0.000 -output external delay 0.000 0.000 -data required time 0.000 --------------------------------------------------------------------------------- -data required time 0.000 -data arrival time -1.338 --------------------------------------------------------------------------------- -slack (VIOLATED) -1.338 - - -#End of timing report From ae2734f004e285083cadfa8843ddba761ae759fa Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 18 Jul 2022 22:22:34 -0400 Subject: [PATCH 107/128] removed a global datastructure within the clustered netlist class that sorted clusteres by their logical block type. This removal then requried the 'find_block_with_matching_name' function to be modified as it used the deleted datastructure. Now this function accepts a vector of clusters that it searches through, instead of the entire netlist. Also updated the unit test for the modified function. --- vpr/src/base/clustered_netlist.cpp | 45 ++++------------------------- vpr/src/base/clustered_netlist.h | 15 +++++----- vpr/test/test_clustered_netlist.cpp | 27 +++++++++++++++-- 3 files changed, 37 insertions(+), 50 deletions(-) diff --git a/vpr/src/base/clustered_netlist.cpp b/vpr/src/base/clustered_netlist.cpp index e1c22b55b2b..27d40a8034b 100644 --- a/vpr/src/base/clustered_netlist.cpp +++ b/vpr/src/base/clustered_netlist.cpp @@ -121,8 +121,6 @@ ClusterBlockId ClusteredNetlist::create_block(const char* name, t_pb* pb, t_logi //Allocate and initialize every potential pin of the block block_logical_pins_.insert(blk_id, std::vector(get_max_num_pins(type), ClusterPinId::INVALID())); - - add_block_to_logical_type(blk_id, type); } //Check post-conditions: size @@ -276,28 +274,6 @@ void ClusteredNetlist::shrink_to_fit_impl() { net_is_global_.shrink_to_fit(); } -/** - * @brief Given a newly created block, find its logical type and store the - * block in a list where all the other blocks in the list are of the - * blocks logical type. - */ -void ClusteredNetlist::add_block_to_logical_type(ClusterBlockId blk_id, t_logical_block_type_ptr type) { - std::string logical_block_type_name = type->name; - - // check if a group of blocks exist for the current logical block type - // basically checking if this is the first time we are seeing this logical block type - auto logical_type_blocks = block_type_to_id.find(logical_block_type_name); - - if (logical_type_blocks == block_type_to_id.end()) { - // if the current logical block doesnt exist then create a new group of blocks for it and add it - block_type_to_id.emplace(logical_block_type_name, std::vector({blk_id})); - } else { - // current logical block exists, so add the current block to the group other blocks of this type - logical_type_blocks->second.push_back(blk_id); - } - return; -} - /* * * Sanity Checks @@ -357,25 +333,16 @@ bool ClusteredNetlist::validate_net_sizes_impl(size_t num_nets) const { * and this should help improve run time. * */ -ClusterBlockId ClusteredNetlist::find_block_with_matching_name(const std::string& name, t_logical_block_type_ptr blk_type) const { +ClusterBlockId ClusteredNetlist::find_block_with_matching_name(const std::string& name, const std::vector& cluster_block_candidates) const { ClusterBlockId blk_id = ClusterBlockId::INVALID(); - auto blks_of_logical_type = block_type_to_id.find(blk_type->name); std::regex name_to_match(name); - if (blks_of_logical_type != block_type_to_id.end()) { - // get the list of blocks that are of the specified logical type - const std::vector* blk_list = &blks_of_logical_type->second; - - // go through the list of blocks to find if any block name matches the provided name (contains the input string in its name) - for (auto blk = blk_list->begin(); blk != blk_list->end(); blk++) { - // another thing you can do is go through blocks and instead string.find(), you can use a regular expression version (so match a regular expression) - - // check for the string match - if (std::regex_match(Netlist::block_name(*blk), name_to_match)) { - blk_id = *blk; - break; - } + for (auto compatible_block_id = cluster_block_candidates.begin(); compatible_block_id != cluster_block_candidates.end(); compatible_block_id++) { + if (std::regex_match(Netlist::block_name(*compatible_block_id), name_to_match)) { + blk_id = *compatible_block_id; + break; } } + return blk_id; } diff --git a/vpr/src/base/clustered_netlist.h b/vpr/src/base/clustered_netlist.h index c2dfea65c46..2465a742af7 100644 --- a/vpr/src/base/clustered_netlist.h +++ b/vpr/src/base/clustered_netlist.h @@ -229,12 +229,13 @@ class ClusteredNetlist : public Netlist& cluster_block_candidates) const; private: //Private Members /* @@ -288,10 +289,8 @@ class ClusteredNetlist : public Netlist block_pbs_; /// block_types_; ///> block_logical_pins_; ///> block_type_to_id; /// noc_router_logical_type_clusters; + // add the io blocks to the netlist block_id_from_name.emplace(io_port_one, test_netlist.create_block(io_port_one, &i_o_pb, i_o_ref)); block_id_from_name.emplace(io_port_two, test_netlist.create_block(io_port_two, &i_o_pb, i_o_ref)); @@ -57,12 +60,18 @@ TEST_CASE("test_find_block_with_matching_name", "[vpr_clustered_netlist]") { block_id_from_name.emplace(router_three, test_netlist.create_block(router_three, &router_pb, router_ref)); block_id_from_name.emplace(router_four, test_netlist.create_block(router_four, &router_pb, router_ref)); + // get the added router cluster block ids and store them + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_one)->second); + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_two)->second); + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_three)->second); + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_four)->second); + // now find a block just knowing its instance name // the test names will have an arbritary number of characters in front and then the name of the instance and then maybe some characters after std::string test_router_module_name = "(.*)(noc_router_one)(.*)"; //get the block id - ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, router_ref); + ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, noc_router_logical_type_clusters); // now check the block id with what we expect to be REQUIRE((size_t)(block_id_from_name.find("router:noc_router_one")->second) == (size_t)test_router_id); @@ -82,12 +91,18 @@ TEST_CASE("test_find_block_with_matching_name", "[vpr_clustered_netlist]") { block_id_from_name.emplace(router_three, test_netlist.create_block(router_three, &router_pb, router_ref)); block_id_from_name.emplace(router_four, test_netlist.create_block(router_four, &router_pb, router_ref)); + // get the added router cluster block ids and store them + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_one)->second); + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_two)->second); + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_three)->second); + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_four)->second); + // now find a block just knowing its unique identifier // the test names will have an arbritary number of characters in front of them and the unique identifier at the end std::string test_router_module_name = "(.*)(q_a\\[2\\])(.*)"; //get the block id - ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, router_ref); + ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, noc_router_logical_type_clusters); // now check the block id with what we expect to be REQUIRE((size_t)(block_id_from_name.find("router:new_router|q_a[2]")->second) == (size_t)test_router_id); @@ -113,12 +128,18 @@ TEST_CASE("test_find_block_with_matching_name", "[vpr_clustered_netlist]") { block_id_from_name.emplace(router_three, test_netlist.create_block(router_three, &router_pb, router_ref)); block_id_from_name.emplace(router_four, test_netlist.create_block(router_four, &router_pb, router_ref)); + // get the added router cluster block ids and store them + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_one)->second); + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_two)->second); + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_three)->second); + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_four)->second); + // now find a block just knowing its unique identifier // THe identifier we use will match with multiple blocks in this test case std::string test_router_module_name = "(.*)(noc_router_four\\|flit_out_two\\[0\\]~reg0)$"; //get the block id - ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, router_ref); + ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, noc_router_logical_type_clusters); // since we passed in the router logical type, we expect the router block to be the returned id From 5372ba66ee6972570b7caa9fe8eba0e75d19b65f Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 19 Jul 2022 01:58:39 -0400 Subject: [PATCH 108/128] Created a new function that searches the clustered netlist and stores all cluster blocks that are compatible with physical noc router tiles. This was done due to the modifactions made the 'find_block_with_matching_name' function in the previous commit. Added a corresponding unit test for this function. Also modified other functios in read_xml_noc_traffic_flows_file.cpp to bring in the changes made made to 'find_block_with_matching_name' --- .../noc/read_xml_noc_traffic_flows_file.cpp | 82 ++++----- vpr/src/noc/read_xml_noc_traffic_flows_file.h | 32 +++- .../test_read_xml_noc_traffic_flows_file.cpp | 157 +++++++++++++++++- 3 files changed, 227 insertions(+), 44 deletions(-) diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index d9a79cb5cd7..04776eb8cf3 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -19,6 +19,21 @@ void read_xml_noc_traffic_flows_file(const char* noc_flows_file) { // get the physical type of a noc router t_physical_tile_type_ptr noc_router_tile_type = get_physical_type_of_noc_router_tile(device_ctx, noc_ctx); + /* Get the cluster blocks that are compatible with a physical NoC router + * tile. These blocks are essentially the "logical routers" that the user + * instantiated in the HDL design. + * + * This is done so that while parsing the traffic flows file, the cluster + * identification can be sped up. The traffic flows file provides a string + * which represents the name of the router modules in the HDL design. Each + * time the cluster id is needed, the name of the block needs to be + * compared to every block in the clustered netlist. This can be very + * time consuming, so instead we can compare to only blocks that are + * compatible to physical NoC router tiles. + */ + std::vector cluster_blocks_compatible_with_noc_router_tiles; + get_cluster_blocks_compatible_with_noc_router_tiles(cluster_ctx, noc_router_tile_type, cluster_blocks_compatible_with_noc_router_tiles); + /* variabled used when parsing the file */ pugi::xml_document doc; pugiutil::loc_data loc_data; @@ -37,7 +52,7 @@ void read_xml_noc_traffic_flows_file(const char* noc_flows_file) { // process the individual traffic flows below for (pugi::xml_node single_flow : traffic_flows_tag.children()) { // current tag is a valid "flow" so process it - process_single_flow(single_flow, loc_data, cluster_ctx, noc_ctx, noc_router_tile_type); + process_single_flow(single_flow, loc_data, cluster_ctx, noc_ctx, noc_router_tile_type, cluster_blocks_compatible_with_noc_router_tiles); } } catch (pugiutil::XmlError& e) { // used for identifying any of the xml parsing library errors @@ -58,7 +73,7 @@ void read_xml_noc_traffic_flows_file(const char* noc_flows_file) { return; } -void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type) { +void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type, const std::vector& cluster_blocks_compatible_with_noc_router_tiles) { // contains all traffic flows NocTrafficFlows* noc_traffic_flow_storage = &noc_ctx.noc_traffic_flows_storage; @@ -77,8 +92,8 @@ void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_dat verify_traffic_flow_router_modules(source_router_module_name, sink_router_module_name, single_flow_tag, loc_data); // assign the unique block ids of the two router modules after clustering - ClusterBlockId source_router_id = get_router_module_cluster_id(source_router_module_name, cluster_ctx, single_flow_tag, loc_data, noc_router_tile_type); - ClusterBlockId sink_router_id = get_router_module_cluster_id(sink_router_module_name, cluster_ctx, single_flow_tag, loc_data, noc_router_tile_type); + ClusterBlockId source_router_id = get_router_module_cluster_id(source_router_module_name, cluster_ctx, single_flow_tag, loc_data, cluster_blocks_compatible_with_noc_router_tiles); + ClusterBlockId sink_router_id = get_router_module_cluster_id(sink_router_module_name, cluster_ctx, single_flow_tag, loc_data, cluster_blocks_compatible_with_noc_router_tiles); // verify that the source and sink modules are actually noc routers check_traffic_flow_router_module_type(source_router_module_name, source_router_id, single_flow_tag, loc_data, cluster_ctx, noc_router_tile_type); @@ -122,41 +137,16 @@ void verify_traffic_flow_properties(double traffic_flow_bandwidth, double max_tr return; } -ClusterBlockId get_router_module_cluster_id(std::string router_module_name, const ClusteringContext& cluster_ctx, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, t_physical_tile_type_ptr noc_router_tile_type) { +ClusterBlockId get_router_module_cluster_id(std::string router_module_name, const ClusteringContext& cluster_ctx, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const std::vector& cluster_blocks_compatible_with_noc_router_tiles) { ClusterBlockId router_module_id = ClusterBlockId::INVALID(); - // get the subtiles of the noc router physical type - const std::vector* noc_router_subtiles = &noc_router_tile_type->sub_tiles; - - /* - * iterate through all the logical block types that can be placed on the - * NoC router tile. Check if the there is a cluster block that matches - * the input router module name and is one of the supported logical - * block types. - */ - for (auto sub_tile = noc_router_subtiles->begin(); sub_tile != noc_router_subtiles->end(); sub_tile++) { - //get the logical types the current tile supports - const std::vector* supported_noc_logical_types = &sub_tile->equivalent_sites; - - // go through each logical type and check if there is a cluster block - // of that type that also matches the input module name - for (auto logical_type = supported_noc_logical_types->begin(); logical_type != supported_noc_logical_types->end(); logical_type++) { - try { - router_module_id = cluster_ctx.clb_nlist.find_block_with_matching_name(router_module_name, *logical_type); - } catch (const std::regex_error& error) { - // if there was an error with matching the regex string,report it to the user here - vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), error.what()); - } - - // found a block for the current logical type, so exit - if (router_module_id != ClusterBlockId::INVALID()) { - break; - } - } - // found a block for the current sub tile, so exit - if (router_module_id != ClusterBlockId::INVALID()) { - break; - } + // find the cluster block whos name matches to the provided router module name provided by the user + // Then get the corresponding cluster block id if a valid block was found + try { + router_module_id = cluster_ctx.clb_nlist.find_block_with_matching_name(router_module_name, cluster_blocks_compatible_with_noc_router_tiles); + } catch (const std::regex_error& error) { + // if there was an error with matching the regex string,report it to the user here + vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), error.what()); } // check if a valid block id was found @@ -244,5 +234,23 @@ void check_for_duplicate_traffic_flow(ClusterBlockId source_router_id, ClusterBl } } + return; +} + +void get_cluster_blocks_compatible_with_noc_router_tiles(const ClusteringContext& cluster_ctx, t_physical_tile_type_ptr noc_router_tile_type, std::vector& cluster_blocks_compatible_with_noc_router_tiles) { + // get the ids of all cluster blocks in the netlist + auto cluster_netlist_blocks = cluster_ctx.clb_nlist.blocks(); + + for (auto cluster_block_id = cluster_netlist_blocks.begin(); cluster_block_id != cluster_netlist_blocks.end(); cluster_block_id++) { + // get the logical type of the block + t_logical_block_type_ptr cluster_block_type = cluster_ctx.clb_nlist.block_type(*cluster_block_id); + + // check if the current block is compatible with a NoC router tile + // if it is, then this block is a NoC outer instantiated by the user in the design, so add it to the vector compatible blocks + if (is_tile_compatible(noc_router_tile_type, cluster_block_type)) { + cluster_blocks_compatible_with_noc_router_tiles.push_back(*cluster_block_id); + } + } + return; } \ No newline at end of file diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.h b/vpr/src/noc/read_xml_noc_traffic_flows_file.h index 30ad4c37ea2..24ba4efd94c 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.h +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.h @@ -67,8 +67,11 @@ void read_xml_noc_traffic_flows_file(const char* noc_flows_file); * the NocTrafficFlows class and store current flow. * @param noc_router_tile_type The physical type of a Noc router tile in the * FPGA. + * @param cluster_blocks_compatible_with_noc_router_tiles A vector of cluster + * blocks in the netlist that are + * compatible with a noc router tile. */ -void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type); +void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const ClusteringContext& cluster_ctx, NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type, const std::vector& cluster_blocks_compatible_with_noc_router_tiles); /** * @brief Checks to see that the two router module names provided in the @@ -110,10 +113,13 @@ void verify_traffic_flow_properties(double traffic_flow_bandwidth, double max_tr * a cluster block id. * @param single_flow_tag A xml tag that contains the traffic flow information * @param loc_data Contains location data about the current line in the xml file + * @param cluster_blocks_compatible_with_noc_router_tiles A vector of cluster + * blocks in the netlist that are + * compatible with a noc router tile. * @return ClusterBlockId The corresponding router block id of the provided * router module name. */ -ClusterBlockId get_router_module_cluster_id(std::string router_module_name, const ClusteringContext& cluster_ctx, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, t_physical_tile_type_ptr noc_router_tile_type); +ClusterBlockId get_router_module_cluster_id(std::string router_module_name, const ClusteringContext& cluster_ctx, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const std::vector& cluster_blocks_compatible_with_noc_router_tiles); /** * @brief Checks to see whether a given router block is compatible with a NoC @@ -187,4 +193,26 @@ bool check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& no */ void check_for_duplicate_traffic_flow(ClusterBlockId source_router_id, ClusterBlockId sink_router_id, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const NocTrafficFlows& noc_traffic_flow_storage); +/** + * @brief Goes through the blocks within the clustered netlist and indetifies + * all blocks that are compatible with a NoC router tile. BY compatible + * it means that we can place the cluster block on a NoC router tile. + * The run time for this function is O(N) where N is the number of + * cluster blocks in the netlist. + * + * @param cluster_ctx Global variable that contains clustering information. + * Contains the clustered netlist, which is used here + * to retrieve the logical block type of every cluster block. + * @param noc_router_tile_type The physical type of a Noc router tile in the + * FPGA. Used to check if the router block is + * compatible with a router tile. + * @param cluster_blocks_compatible_with_noc_router_tiles A vector of cluster + * blocks in the netlist that are + * compatible with a noc router tile. + * The cluster blocks in the netlist + * are added to this vector in this + * function. + */ +void get_cluster_blocks_compatible_with_noc_router_tiles(const ClusteringContext& cluster_ctx, t_physical_tile_type_ptr noc_router_tile_type, std::vector& cluster_blocks_compatible_with_noc_router_tiles); + #endif \ No newline at end of file diff --git a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp index d80165acc74..dce859aa50d 100644 --- a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp +++ b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp @@ -117,9 +117,6 @@ TEST_CASE("test_get_router_module_cluster_id", "[vpr_noc_traffic_flows_parser]") // add the subtile to the physical noc router type noc_router.sub_tiles.push_back(router_tile); - // create a reference to the physical type - t_physical_tile_type_ptr noc_router_ref = &noc_router; - /* finished creating noc router physical type */ // creating an IO logical type @@ -143,6 +140,9 @@ TEST_CASE("test_get_router_module_cluster_id", "[vpr_noc_traffic_flows_parser]") block_id_from_name.emplace(io_port_three, test_netlist->create_block(io_port_three, nullptr, i_o_ref)); block_id_from_name.emplace(io_port_four, test_netlist->create_block(io_port_four, nullptr, i_o_ref)); + // datastructure to store all the cluster block IDs of the noc router logical block type clusters + std::vector noc_router_logical_type_clusters; + SECTION("Test case where the block is found in the clustered netlist") { // create names for some router blocks char router_one[] = "router:noc_router_one|flit_out_two[0]~reg0"; @@ -156,6 +156,12 @@ TEST_CASE("test_get_router_module_cluster_id", "[vpr_noc_traffic_flows_parser]") block_id_from_name.emplace(router_three, test_netlist->create_block(router_three, nullptr, router_ref)); block_id_from_name.emplace(router_four, test_netlist->create_block(router_four, nullptr, router_ref)); + // get the added router cluster block ids and store them + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_one)->second); + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_two)->second); + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_three)->second); + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_four)->second); + // create additional router blocks char router_five[] = "router:noc_router_five|flit_out_two[0]~reg0"; char router_six[] = "router:noc_router_six|flit_out_two[0]~reg0"; @@ -163,12 +169,16 @@ TEST_CASE("test_get_router_module_cluster_id", "[vpr_noc_traffic_flows_parser]") block_id_from_name.emplace(router_five, test_netlist->create_block(router_five, nullptr, router_ref_2)); block_id_from_name.emplace(router_six, test_netlist->create_block(router_six, nullptr, router_ref_2)); + // get the added router cluster block ids and store them + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_five)->second); + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_six)->second); + // now find a block just knowing its instance name std::string test_router_module_name = ".*noc_router_five.*"; // now get the cluster id of the block with the test router name using the function we are testing ClusterBlockId test_router_block_id; - REQUIRE_NOTHROW(test_router_block_id = get_router_module_cluster_id(test_router_module_name, cluster_ctx, test, test_location, noc_router_ref)); + REQUIRE_NOTHROW(test_router_block_id = get_router_module_cluster_id(test_router_module_name, cluster_ctx, test, test_location, noc_router_logical_type_clusters)); REQUIRE((size_t)(block_id_from_name.find("router:noc_router_five|flit_out_two[0]~reg0")->second) == (size_t)test_router_block_id); @@ -188,6 +198,12 @@ TEST_CASE("test_get_router_module_cluster_id", "[vpr_noc_traffic_flows_parser]") block_id_from_name.emplace(router_three, test_netlist->create_block(router_three, nullptr, router_ref)); block_id_from_name.emplace(router_four, test_netlist->create_block(router_four, nullptr, router_ref)); + // get the added router cluster block ids and store them + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_one)->second); + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_two)->second); + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_three)->second); + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_four)->second); + // create additional router blocks char router_five[] = "router:noc_router_five|flit_out_two[0]~reg0"; char router_six[] = "router:noc_router_six|flit_out_two[0]~reg0"; @@ -195,12 +211,16 @@ TEST_CASE("test_get_router_module_cluster_id", "[vpr_noc_traffic_flows_parser]") block_id_from_name.emplace(router_five, test_netlist->create_block(router_five, nullptr, router_ref_2)); block_id_from_name.emplace(router_six, test_netlist->create_block(router_six, nullptr, router_ref_2)); + // get the added router cluster block ids and store them + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_five)->second); + noc_router_logical_type_clusters.push_back(block_id_from_name.find(router_six)->second); + // now find a block just knowing its name. Choosing a block name that doesn't exist std::string test_router_module_name = "^router:noc_router_seven|flit_out_two[0]~reg0$"; // now get the cluster id of the block with the test router name using the function we are testing // This should fail, so check that it does - REQUIRE_THROWS_WITH(get_router_module_cluster_id(test_router_module_name, cluster_ctx, test, test_location, noc_router_ref), "The router module '^router:noc_router_seven|flit_out_two[0]~reg0$' does not exist in the design."); + REQUIRE_THROWS_WITH(get_router_module_cluster_id(test_router_module_name, cluster_ctx, test, test_location, noc_router_logical_type_clusters), "The router module '^router:noc_router_seven|flit_out_two[0]~reg0$' does not exist in the design."); // clear the global netlist datastructure so other unit tests that rely on dont use a corrupted netlist free_clustered_netlist(); @@ -432,4 +452,131 @@ TEST_CASE("test_check_for_duplicate_traffic_flow", "[vpr_noc_traffic_flows_parse REQUIRE_NOTHROW(check_for_duplicate_traffic_flow(router_block_zero_id, router_block_two_id, test, test_location, noc_ctx.noc_traffic_flows_storage)); } } +TEST_CASE("test_get_cluster_blocks_compatible_with_noc_router_tiles", "[vpr_noc_traffic_flows_parser]") { + + // get the global netlist + ClusteringContext& cluster_ctx = g_vpr_ctx.mutable_clustering(); + ClusteredNetlist* test_netlist = &cluster_ctx.clb_nlist; + + // create a new clustered netlist + *test_netlist = ClusteredNetlist("test_netlist", "77"); + + // create the logical type of a noc router + // there is a single logical type that is compatible with this subtile and it is a router + t_logical_block_type router_block; + char router[] = "router"; + router_block.name = router; + t_logical_block_type_ptr router_ref = &router_block; + + //need to create the noc router physical type + t_physical_tile_type noc_router; + + // indicate that the noc_router physical tile is not an input/output + noc_router.is_input_type = false; + noc_router.is_output_type = false; + + // create a reference to the physical type + t_physical_tile_type_ptr noc_router_ref = &noc_router; + // need to add the physical type of the router to the list of physical tiles that match to the router logical block + router_block.equivalent_tiles.push_back(noc_router_ref); + + // create a second tupe of router logical block + t_logical_block_type router_block_type_two; + char router_two_name[] = "router_2"; + router_block_type_two.name = router_two_name; + t_logical_block_type_ptr router_ref_two = &router_block_type_two; + + // set the router blocks physical type as a noc router + router_block_type_two.equivalent_tiles.push_back(noc_router_ref); + + // creating an IO logical type + t_logical_block_type i_o_block; + char i_o[] = "IO"; + i_o_block.name = i_o; + t_logical_block_type_ptr i_o_ref = &i_o_block; + + // create a physical tile for I/O blocks + t_physical_tile_type i_o_block_tile; + + // indicate that the io physical tile is not an input/output. Just for this test + i_o_block_tile.is_input_type = false; + i_o_block_tile.is_output_type = false; + + // create a reference to the physical type + t_physical_tile_type_ptr i_o_block_ref = &i_o_block_tile; + // need to add the physical type of the io block to the list of physical tiles that match to the io logical block + router_block.equivalent_tiles.push_back(i_o_block_ref); + + // stores all router cluster blocks within the netlist + // this is a golden set that the output of this test will be compared to + std::vector golden_set_of_router_cluster_blocks_in_netlist; + + + SECTION("Test case where all router cluster blocks are correctly identified within the netlist and stored."){ + + // create some sample router blocks and add them to the clustered netlsit + + // create names for some router blocks + char router_one[] = "noc_router_one"; + char router_two[] = "noc_router_two"; + char router_three[] = "noc_router_three"; + char router_four[] = "noc_router_four"; + + // add the router blocks + golden_set_of_router_cluster_blocks_in_netlist.emplace_back(test_netlist->create_block(router_one, nullptr, router_ref)); + golden_set_of_router_cluster_blocks_in_netlist.emplace_back(test_netlist->create_block(router_two, nullptr, router_ref)); + golden_set_of_router_cluster_blocks_in_netlist.emplace_back(test_netlist->create_block(router_three, nullptr, router_ref_two)); + golden_set_of_router_cluster_blocks_in_netlist.emplace_back(test_netlist->create_block(router_four, nullptr, router_ref_two)); + + // stores the found cluster blocks in the netlist that are router blocks which are compatible with a NoC router tile + std::vector found_cluster_blocks_that_are_noc_router_compatible; + + // execute the test function + get_cluster_blocks_compatible_with_noc_router_tiles(cluster_ctx, noc_router_ref, found_cluster_blocks_that_are_noc_router_compatible); + + // check that the correct number of router blocks were found + REQUIRE(golden_set_of_router_cluster_blocks_in_netlist.size() == found_cluster_blocks_that_are_noc_router_compatible.size()); + + // now go through the golden set and check that the router blocks in the golden set were correctly found by the test function + for (auto golden_set_router_block_id = golden_set_of_router_cluster_blocks_in_netlist.begin(); golden_set_router_block_id != golden_set_of_router_cluster_blocks_in_netlist.end(); golden_set_router_block_id++){ + + // no check that the current router block in the golden set was also found by the test and recognized as being a router logical block + REQUIRE(std::find(found_cluster_blocks_that_are_noc_router_compatible.begin(), found_cluster_blocks_that_are_noc_router_compatible.end(), *golden_set_router_block_id) != found_cluster_blocks_that_are_noc_router_compatible.end()); + + } + + // clear the global netlist datastructure so other unit tests that rely on dont use a corrupted netlist + free_clustered_netlist(); + + } + SECTION("Test case where non router blocks are correctly identified within the netlist and ignored."){ + + // add some I/O blocks which are not compatible with a physical noc router tile + + // create names for some io blocks + char io_one[] = "io_one"; + char io_two[] = "io_two"; + char io_three[] = "io_three"; + char io_four[] = "io_four"; + + // add the io blocks + // Note: we do not add these cluster blocks to the golden set since they are not router blocks and incompatible with physical noc router tiles + test_netlist->create_block(io_one, nullptr, i_o_ref); + test_netlist->create_block(io_two, nullptr, i_o_ref); + test_netlist->create_block(io_three, nullptr, i_o_ref); + test_netlist->create_block(io_four, nullptr, i_o_ref); + + // stores the found cluster blocks in the netlist that are router blocks which are compatible with a NoC router tile + std::vector found_cluster_blocks_that_are_noc_router_compatible; + + // execute the test function + get_cluster_blocks_compatible_with_noc_router_tiles(cluster_ctx, noc_router_ref, found_cluster_blocks_that_are_noc_router_compatible); + + // since there were no router blocks in this netlist, check that the test found function 0 blocks that were compatible with a noc router tile + REQUIRE(found_cluster_blocks_that_are_noc_router_compatible.size() == 0); + + // clear the global netlist datastructure so other unit tests that rely on dont use a corrupted netlist + free_clustered_netlist(); + } +} } // namespace \ No newline at end of file From 96539ac32b27181ee2ee5067a4041a3493631bda Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 19 Jul 2022 20:46:53 -0400 Subject: [PATCH 109/128] renamed the 'find_block_with_match_name' function to 'find_block_by_name_fragment'. Also improved commenting for this function. Updated all calls to this function as well. --- vpr/src/base/clustered_netlist.cpp | 39 ++++++++++++------- vpr/src/base/clustered_netlist.h | 10 ++++- vpr/src/base/netlist.h | 6 +-- vpr/src/base/netlist.tpp | 39 ++++++++++++------- .../noc/read_xml_noc_traffic_flows_file.cpp | 2 +- vpr/test/test_clustered_netlist.cpp | 6 +-- 6 files changed, 67 insertions(+), 35 deletions(-) diff --git a/vpr/src/base/clustered_netlist.cpp b/vpr/src/base/clustered_netlist.cpp index 27d40a8034b..c5a4961d5b4 100644 --- a/vpr/src/base/clustered_netlist.cpp +++ b/vpr/src/base/clustered_netlist.cpp @@ -308,18 +308,31 @@ bool ClusteredNetlist::validate_net_sizes_impl(size_t num_nets) const { } /** - * @brief Finds a block where the blocks name contains within it the - * provided input name. The intented use is to find the block id of a - * hard block when provided with the its module name in the HDL design. - * - * For example, suppose a RAM block was instantiated in the design and it - * was named "test_ram". The generated netlist would not have the block - * named as "test_ram", instead it would be something different but the - * name should contain "test_ram" inside it since it represents that - * block. If "test_ram" is provided to find_block() above, then an - * invalid block ID would be returned. The find_block_with_matching_name - * () can instead be used and it should find the ram block that has - * "test_ram" within its name. + * @brief Finds a block where the block's name matches to the provided + * input string pattern. + * The intented use is to find the block id of a + * hard block without knowing its name in the netlist. Instead + * a pattern can be created that we know the block's name will + * match to. Generally, we expect the pattern to be constructed + * using the block's module name in the HDL design, since we can + * expect the netlist name of the block to include the module + * name within it. + * + * For example, suppose a RAM block was named in the netlist as + * "top|alu|test_ram|out". The user instantiated the ram module + * in the HDL design as "test_ram". So instead of going through + * the netlist and finding the ram block's full name, this + * function can be used by just providing the string pattern as + * ".*test_ram.*". We know that the module name should be somewhere + * within the string, so the pattern we provide says that the netlist + * name of the block contains arbritary characters then the module name + * and then some other arbritary characters after. This pattern will + * then be used to match to the block in the netlist. + * + * This function runs in linear time (O(N)) as it goes over all the + * cluster blocks in the netlist. Additionally, if there are multiple + * blocks that match to the provided input pattern, then the + * first block found is returned. * * There is a similiar function in the Netlist Class. This function * additionally requires the logical type of the block as well. Since @@ -333,7 +346,7 @@ bool ClusteredNetlist::validate_net_sizes_impl(size_t num_nets) const { * and this should help improve run time. * */ -ClusterBlockId ClusteredNetlist::find_block_with_matching_name(const std::string& name, const std::vector& cluster_block_candidates) const { +ClusterBlockId ClusteredNetlist::find_block_by_name_fragment(const std::string& name, const std::vector& cluster_block_candidates) const { ClusterBlockId blk_id = ClusterBlockId::INVALID(); std::regex name_to_match(name); diff --git a/vpr/src/base/clustered_netlist.h b/vpr/src/base/clustered_netlist.h index 2465a742af7..4ec6a657545 100644 --- a/vpr/src/base/clustered_netlist.h +++ b/vpr/src/base/clustered_netlist.h @@ -232,10 +232,16 @@ class ClusteredNetlist : public Netlist& cluster_block_candidates) const; + ClusterBlockId find_block_by_name_fragment(const std::string& name, const std::vector& cluster_block_candidates) const; private: //Private Members /* diff --git a/vpr/src/base/netlist.h b/vpr/src/base/netlist.h index eb76d5b94d1..5944b5ad0db 100644 --- a/vpr/src/base/netlist.h +++ b/vpr/src/base/netlist.h @@ -728,11 +728,11 @@ class Netlist { BlockId find_block(const std::string& name) const; /** - * @brief Returns the BlockId of the specified block or BlockId::INVALID() if not found. The name of the block returned contains the provided input name in it. + * @brief Returns the BlockId of the specified block or BlockId::INVALID() if not found. The name of the block ID returned contains the provided input as a substring. * - * @param name The name of the block + * @param name A substring of a block name for which an ID needs to be found. */ - BlockId find_block_with_matching_name(const std::string& name) const; + BlockId find_block_by_name_fragment(const std::string& name) const; /** * @brief Returns the PortId of the specifed port if it exists or PortId::INVALID() if not diff --git a/vpr/src/base/netlist.tpp b/vpr/src/base/netlist.tpp index 29de59e2c68..0bb2412fd89 100644 --- a/vpr/src/base/netlist.tpp +++ b/vpr/src/base/netlist.tpp @@ -459,22 +459,35 @@ BlockId Netlist::find_block(const std::string& na } /** - * @brief Finds a block where the blocks name contains within it the - * provided input name. The intented use is to find the block id of a - * hard block when provided with the its module name in the HDL design. - * - * For example, suppose a RAM block was instantiated in the design and it - * was named "test_ram". The generated netlist would not have the block - * named as "test_ram", instead it would be something different but the - * name should contain "test_ram" inside it since it represents that - * block. If "test_ram" is provided to find_block() above, then an - * invalid block ID would be returned. The find_block_with_matching_name - * () can instead be used and it should find the ram block that has - * "test_ram" within its name. + * @brief Finds a block where the block's name contains the + * provided input name as a substring. + * The intented use is to find the block id of a + * hard block without knowing its name in the netlist. Instead + * the block's module name in the HDL design can be used as it will + * be a substring within its full name in the netlist. + * + * For example, suppose a RAM block was named in the netlist as + * "top|alu|test_ram|out". The user instantiated the ram module + * in the HDL design as "test_ram". So instead of going through + * the netlist and finding the ram block's full name, this + * function can be used by just providing the module name "test_ram" + * and using this substring to match the blocks name in the netlist + * and retrieving its block id. * + * This function runs in linear time (O(N)) as it goes over all the + * cluster blocks in the netlist. Additionally, if there are multiple + * blocks that contain the provided input as a substring, then the + * first block found is returned. + * + * NOTE: This function tries to find blocks by checking for substrings. + * The clustered netlist class defines another version of this + * function that find blocks by checking for a pattern match, + * meaning that the input is a pattern string and the pattern + * is looked for ine each block name. + * */ template -BlockId Netlist::find_block_with_matching_name(const std::string& name) const { +BlockId Netlist::find_block_by_name_fragment(const std::string& name) const { BlockId matching_blk_id = BlockId::INVALID(); const std::string blk_name; diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index 04776eb8cf3..ca55a6b3d45 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -143,7 +143,7 @@ ClusterBlockId get_router_module_cluster_id(std::string router_module_name, cons // find the cluster block whos name matches to the provided router module name provided by the user // Then get the corresponding cluster block id if a valid block was found try { - router_module_id = cluster_ctx.clb_nlist.find_block_with_matching_name(router_module_name, cluster_blocks_compatible_with_noc_router_tiles); + router_module_id = cluster_ctx.clb_nlist.find_block_by_name_fragment(router_module_name, cluster_blocks_compatible_with_noc_router_tiles); } catch (const std::regex_error& error) { // if there was an error with matching the regex string,report it to the user here vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), error.what()); diff --git a/vpr/test/test_clustered_netlist.cpp b/vpr/test/test_clustered_netlist.cpp index 931654f7fad..d05826070ea 100644 --- a/vpr/test/test_clustered_netlist.cpp +++ b/vpr/test/test_clustered_netlist.cpp @@ -71,7 +71,7 @@ TEST_CASE("test_find_block_with_matching_name", "[vpr_clustered_netlist]") { std::string test_router_module_name = "(.*)(noc_router_one)(.*)"; //get the block id - ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, noc_router_logical_type_clusters); + ClusterBlockId test_router_id = test_netlist.find_block_by_name_fragment(test_router_module_name, noc_router_logical_type_clusters); // now check the block id with what we expect to be REQUIRE((size_t)(block_id_from_name.find("router:noc_router_one")->second) == (size_t)test_router_id); @@ -102,7 +102,7 @@ TEST_CASE("test_find_block_with_matching_name", "[vpr_clustered_netlist]") { std::string test_router_module_name = "(.*)(q_a\\[2\\])(.*)"; //get the block id - ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, noc_router_logical_type_clusters); + ClusterBlockId test_router_id = test_netlist.find_block_by_name_fragment(test_router_module_name, noc_router_logical_type_clusters); // now check the block id with what we expect to be REQUIRE((size_t)(block_id_from_name.find("router:new_router|q_a[2]")->second) == (size_t)test_router_id); @@ -139,7 +139,7 @@ TEST_CASE("test_find_block_with_matching_name", "[vpr_clustered_netlist]") { std::string test_router_module_name = "(.*)(noc_router_four\\|flit_out_two\\[0\\]~reg0)$"; //get the block id - ClusterBlockId test_router_id = test_netlist.find_block_with_matching_name(test_router_module_name, noc_router_logical_type_clusters); + ClusterBlockId test_router_id = test_netlist.find_block_by_name_fragment(test_router_module_name, noc_router_logical_type_clusters); // since we passed in the router logical type, we expect the router block to be the returned id From 8b6b86050cbfe6ad7ab9dab25d0cd7b32d726c0e Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 19 Jul 2022 21:11:31 -0400 Subject: [PATCH 110/128] removed a function that checked for duplicate traffic flows. Initially, it was assumed that two traffic flows where the source and estination routers were the same was illegal. But it is was later found that this is not illegal and completely allowed. --- .../noc/read_xml_noc_traffic_flows_file.cpp | 26 ---------- vpr/src/noc/read_xml_noc_traffic_flows_file.h | 18 ------- .../test_read_xml_noc_traffic_flows_file.cpp | 49 ------------------- 3 files changed, 93 deletions(-) diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index ca55a6b3d45..3e18087c909 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -106,9 +106,6 @@ void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_dat verify_traffic_flow_properties(traffic_flow_bandwidth, max_traffic_flow_latency, single_flow_tag, loc_data); - // make sure that the current traffic flow was not added previously - check_for_duplicate_traffic_flow(source_router_id, sink_router_id, single_flow_tag, loc_data, *noc_traffic_flow_storage); - // The current flow information is legal, so store it noc_traffic_flow_storage->create_noc_traffic_flow(source_router_module_name, sink_router_module_name, source_router_id, sink_router_id, traffic_flow_bandwidth, max_traffic_flow_latency); @@ -214,29 +211,6 @@ bool check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& no return result; } -void check_for_duplicate_traffic_flow(ClusterBlockId source_router_id, ClusterBlockId sink_router_id, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const NocTrafficFlows& noc_traffic_flow_storage) { - const std::vector* associated_traffic_flows_to_source_router = noc_traffic_flow_storage.get_traffic_flows_associated_to_source_router(source_router_id); - - // make sure the router is associated to atleast one traffic flow - if (associated_traffic_flows_to_source_router != nullptr) { - /* - * Go through all the traffic flows that exist with the current source router and check to see if any of those traffic flows have a sink router - * that matches current sink router. When this happens then the two traffic flows are duplicates and an error should be thrown. - */ - for (auto traffic_flow_id = associated_traffic_flows_to_source_router->begin(); traffic_flow_id != associated_traffic_flows_to_source_router->end(); traffic_flow_id++) { - ClusterBlockId curr_sink_router_id = noc_traffic_flow_storage.get_single_noc_traffic_flow(*traffic_flow_id).sink_router_cluster_id; - - // compare the current traffic flows sink router with the new traffic flows sink router - if (curr_sink_router_id == sink_router_id) { - // the routers are the same, so this is a duplicate traffic flow. thrown an error - vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "The supplied traffic flow is a duplicate of another traffic flow (contain the same source and sink routers). Duplicate traffic flows are not allowed."); - } - } - } - - return; -} - void get_cluster_blocks_compatible_with_noc_router_tiles(const ClusteringContext& cluster_ctx, t_physical_tile_type_ptr noc_router_tile_type, std::vector& cluster_blocks_compatible_with_noc_router_tiles) { // get the ids of all cluster blocks in the netlist auto cluster_netlist_blocks = cluster_ctx.clb_nlist.blocks(); diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.h b/vpr/src/noc/read_xml_noc_traffic_flows_file.h index 24ba4efd94c..ea5de99cc14 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.h +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.h @@ -175,24 +175,6 @@ t_physical_tile_type_ptr get_physical_type_of_noc_router_tile(const DeviceContex */ bool check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& noc_ctx, t_physical_tile_type_ptr noc_router_tile_type, std::string noc_flows_file); -/** - * @brief Given a traffic flow source and sink router, check to see if there - * already exists another traffic flow with the same source and sink - * routers. If there already exsists a traffic flow with the same routers - * then this is a duplicate and an error is thrown, otherwise no - * duplicate traffic flow exists. - * - * @param source_router_id The cluster block id of the source router in - * the traffic flow to be added. - * @param sink_router_id The cluster block id of the sink router in the - * the traffic flow to be added. - * @param single_flow_tag A xml tag that contains the traffic flow information - * @param loc_data Contains location data about the current line in the xml file - * @param noc_traffic_flow_storage Used to get the previously added traffic - * traffic flow information. - */ -void check_for_duplicate_traffic_flow(ClusterBlockId source_router_id, ClusterBlockId sink_router_id, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const NocTrafficFlows& noc_traffic_flow_storage); - /** * @brief Goes through the blocks within the clustered netlist and indetifies * all blocks that are compatible with a NoC router tile. BY compatible diff --git a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp index dce859aa50d..e29e7be7b56 100644 --- a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp +++ b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp @@ -403,55 +403,6 @@ TEST_CASE("test_check_that_all_router_blocks_have_an_associated_traffic_flow", " free_device(); } } -TEST_CASE("test_check_for_duplicate_traffic_flow", "[vpr_noc_traffic_flows_parser]") { - // filler data for the xml information - // data for the xml parsing - pugi::xml_node test; - pugiutil::loc_data test_location; - - // get the global noc information - NocContext& noc_ctx = g_vpr_ctx.mutable_noc(); - // delete any previously created traffic flow info - noc_ctx.noc_traffic_flows_storage.clear_traffic_flows(); - - // define arbritary values for traffic flow bandwidths and latency - double traffic_flow_bandwidth = 0.0; - double traffic_flow_latency = 0.0; - - SECTION("Test case where there are duplicate traffic flows") { - // create some sample clusterblock ids that can be used to generate traffic flows - ClusterBlockId router_block_zero_id(0); - ClusterBlockId router_block_one_id(1); - - // create sample router block names that can be used to create a traffic flow - std::string router_block_zero = "router_block_zero"; - std::string router_block_one = "router_block_one"; - - // now create a traffic flow - noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_block_zero, router_block_one, router_block_zero_id, router_block_one_id, traffic_flow_bandwidth, traffic_flow_latency); - - // now run the test function with the situation where another traffic flow is being added with the exact same source and sink routers as above - // we expect the function to fail and erro to be thrown - REQUIRE_THROWS_WITH(check_for_duplicate_traffic_flow(router_block_zero_id, router_block_one_id, test, test_location, noc_ctx.noc_traffic_flows_storage), "The supplied traffic flow is a duplicate of another traffic flow (contain the same source and sink routers). Duplicate traffic flows are not allowed."); - } - SECTION("Test case where there are no duplicate traffic flows") { - // create some sample clusterblock ids that can be used to generate traffic flows - ClusterBlockId router_block_zero_id(0); - ClusterBlockId router_block_one_id(1); - ClusterBlockId router_block_two_id(2); - - // create sample router block names that can be used to create a traffic flow - std::string router_block_zero = "router_block_zero"; - std::string router_block_one = "router_block_one"; - - // now create a traffic flow - noc_ctx.noc_traffic_flows_storage.create_noc_traffic_flow(router_block_zero, router_block_one, router_block_zero_id, router_block_one_id, traffic_flow_bandwidth, traffic_flow_latency); - - // now run the test function with the situation where another traffic flow is being added with sink router than what was used above - // we expect the function to pass and no error to be thrown - REQUIRE_NOTHROW(check_for_duplicate_traffic_flow(router_block_zero_id, router_block_two_id, test, test_location, noc_ctx.noc_traffic_flows_storage)); - } -} TEST_CASE("test_get_cluster_blocks_compatible_with_noc_router_tiles", "[vpr_noc_traffic_flows_parser]") { // get the global netlist From 8033563d0d42a1049c4854c9b25762f490369e83 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Wed, 20 Jul 2022 23:03:42 -0400 Subject: [PATCH 111/128] Changed the NocTrafficFlows class to keep track of associated traffic flows for each router in a single datastructure. Previouslythe traffic flow association was done using two seperate datastructures, where one was used to store traffic flows where the router was the starting point and the other was used to store traffic flows where the routers was the destination. Now they are grouped into one. --- vpr/src/noc/noc_traffic_flows.cpp | 72 +++++++---------------------- vpr/src/noc/noc_traffic_flows.h | 55 ++++++++++------------ vpr/test/test_noc_traffic_flows.cpp | 65 ++++++++++++-------------- 3 files changed, 70 insertions(+), 122 deletions(-) diff --git a/vpr/src/noc/noc_traffic_flows.cpp b/vpr/src/noc/noc_traffic_flows.cpp index b66ae268e7c..f0a9bf602a9 100644 --- a/vpr/src/noc/noc_traffic_flows.cpp +++ b/vpr/src/noc/noc_traffic_flows.cpp @@ -13,30 +13,16 @@ const t_noc_traffic_flow& NocTrafficFlows::get_single_noc_traffic_flow(NocTraffi return noc_traffic_flows[traffic_flow_id]; } -const std::vector* NocTrafficFlows::get_traffic_flows_associated_to_source_router(ClusterBlockId source_router_id) const { - const std::vector* associated_traffic_flows_ref = nullptr; - - // get a reference to the traffic flows that have the current router as a source - auto associated_traffic_flows = source_router_associated_traffic_flows.find(source_router_id); +const std::vector* NocTrafficFlows::get_traffic_flows_associated_to_router_block(ClusterBlockId router_block_id){ - // check if there are any traffic flows associated with the current router - if (associated_traffic_flows != source_router_associated_traffic_flows.end()) { - // if we are here then there exists atleast 1 traffic flow that includes the current router as a source - associated_traffic_flows_ref = &(associated_traffic_flows->second); - } - - return associated_traffic_flows_ref; -} - -const std::vector* NocTrafficFlows::get_traffic_flows_associated_to_sink_router(ClusterBlockId source_router_id) const { const std::vector* associated_traffic_flows_ref = nullptr; - // get a reference to the traffic flows that have the current router as a source - auto associated_traffic_flows = sink_router_associated_traffic_flows.find(source_router_id); + // get a reference to the traffic flows that have the current router as a source or sink + auto associated_traffic_flows = traffic_flows_associated_to_router_blocks.find(router_block_id); // check if there are any traffic flows associated with the current router - if (associated_traffic_flows != sink_router_associated_traffic_flows.end()) { - // if we are here then there exists atleast 1 traffic flow that includes the current router as a source + if (associated_traffic_flows != traffic_flows_associated_to_router_blocks.end()) { + // if we are here then there exists atleast 1 traffic flow that includes the current router as a source or sink associated_traffic_flows_ref = &(associated_traffic_flows->second); } @@ -65,8 +51,8 @@ void NocTrafficFlows::create_noc_traffic_flow(std::string source_router_module_n add_router_to_block_set(sink_router_cluster_id); // now add the new traffic flow to flows associated with the current source and sink router - add_traffic_flow_to_associated_routers(curr_traffic_flow_id, source_router_cluster_id, this->source_router_associated_traffic_flows); - add_traffic_flow_to_associated_routers(curr_traffic_flow_id, sink_router_cluster_id, this->sink_router_associated_traffic_flows); + add_traffic_flow_to_associated_routers(curr_traffic_flow_id, source_router_cluster_id); + add_traffic_flow_to_associated_routers(curr_traffic_flow_id, sink_router_cluster_id); return; } @@ -101,8 +87,6 @@ void NocTrafficFlows::reset_traffic_flows_processed_status(void) { void NocTrafficFlows::clear_traffic_flows(void) { // delete any information from internal datastructures noc_traffic_flows.clear(); - source_router_associated_traffic_flows.clear(); - sink_router_associated_traffic_flows.clear(); processed_traffic_flows.clear(); noc_router_blocks.clear(); @@ -124,14 +108,14 @@ bool NocTrafficFlows::check_if_cluster_block_is_a_noc_router(ClusterBlockId bloc // private functions used internally -void NocTrafficFlows::add_traffic_flow_to_associated_routers(NocTrafficFlowId traffic_flow_id, ClusterBlockId associated_router_id, std::unordered_map>& router_associated_traffic_flows) { +void NocTrafficFlows::add_traffic_flow_to_associated_routers(NocTrafficFlowId traffic_flow_id, ClusterBlockId associated_router_id) { // get a reference to the traffic flows associated with the current router - auto router_traffic_flows = router_associated_traffic_flows.find(associated_router_id); + auto router_traffic_flows = traffic_flows_associated_to_router_blocks.find(associated_router_id); // check if a vector asssociated traffic flows exists - if (router_traffic_flows == router_associated_traffic_flows.end()) { + if (router_traffic_flows == traffic_flows_associated_to_router_blocks.end()) { // there exists no associated traffic flows for this router, so we add it with the newly created traffic flow id - router_associated_traffic_flows.insert(std::pair>(associated_router_id, {traffic_flow_id})); + traffic_flows_associated_to_router_blocks.insert(std::pair>(associated_router_id, {traffic_flow_id})); } else { // there already is a vector associated of traffic flows for the current router, so add it router_traffic_flows->second.emplace_back(traffic_flow_id); @@ -181,49 +165,27 @@ void NocTrafficFlows::echo_noc_traffic_flows(char* file_name) { traffic_flow_id++; } - // now print the associated traffic flow information for router cluster blocks that act as source routers in traffic flows + // now print the associated traffic flow information for router cluster blocks + // The associated traffic flows represent flows where the router block is either a source or destination router fprintf(fp, "List of traffic flows where the router block cluster is a source router:\n"); fprintf(fp, "--------------------------------------------------------------\n"); fprintf(fp, "\n"); - // go through each router block cluster and print its associated traffic flows where the cluster is a source router for those traffic flows + // go through each router block cluster and print its associated traffic flows // we only print out the traffic flow ids - for (auto it = source_router_associated_traffic_flows.begin(); it != source_router_associated_traffic_flows.end(); it++) { + for (auto it = traffic_flows_associated_to_router_blocks.begin(); it != traffic_flows_associated_to_router_blocks.end(); it++) { // print the current router cluster id fprintf(fp, "Cluster ID %lu: ", (size_t)it->first); // get the vector of associated traffic flows auto assoc_traffic_flows = &(it->second); - // now go through the traffic flows this router is a source router and add it - for (auto traffic_flow = assoc_traffic_flows->begin(); traffic_flow != assoc_traffic_flows->end(); traffic_flow++) { - fprintf(fp, "%lu ", (size_t)*traffic_flow); - } - - // seperate the next cluster information - fprintf(fp, "\n\n"); - } - - // now print the associated traffic flow information for router cluster blocks that act as source routers in traffic flows - fprintf(fp, "List of traffic flows where the router block cluster is a sink router:\n"); - fprintf(fp, "--------------------------------------------------------------\n"); - fprintf(fp, "\n"); - - // go through each router block cluster and print its associated traffic flows where the cluster is a sink router for those traffic flows - // we only print out the traffic flow ids - for (auto it = sink_router_associated_traffic_flows.begin(); it != sink_router_associated_traffic_flows.end(); it++) { - // print the current router cluster id - fprintf(fp, "Router block cluster ID %lu: ", (size_t)it->first); - - // get the vector of associated traffic flows - auto assoc_traffic_flows = &(it->second); - - // now go through the traffic flows this router is a sink router and add it + // now go through the associated traffic flows of the current router and print their ids for (auto traffic_flow = assoc_traffic_flows->begin(); traffic_flow != assoc_traffic_flows->end(); traffic_flow++) { fprintf(fp, "%lu ", (size_t)*traffic_flow); } - // seperate the next cluster information + // seperate to the next cluster associated traffic flows information fprintf(fp, "\n\n"); } diff --git a/vpr/src/noc/noc_traffic_flows.h b/vpr/src/noc/noc_traffic_flows.h index 20b84c6c0c0..5c4a0dccd92 100644 --- a/vpr/src/noc/noc_traffic_flows.h +++ b/vpr/src/noc/noc_traffic_flows.h @@ -83,17 +83,23 @@ class NocTrafficFlows { /** contains all the traffic flows provided by the user and their information*/ vtr::vector noc_traffic_flows; + /** - * A traffic flow has a source and destination router associated to it. So when either the source or destination router for a given flow is moved, we need to find a new route between them. - * - * Therefore, during placement if two router blocks are swapped, then the only traffic flows we need to re-route are the flows where the two routers are either the source or destination routers of those flows. - * - * The datastructures below store all traffic flows for each router where the router is a source for the traffic flow. Similarily, there is a another datastructure where all traffic flows are stored for each router where the router is a sink for the traffic flow. The routers are indexed by their ClusterBlockId. - * - * This is done so that the traffic that need to be re-routed during placement can be quickly found. + * @brief Each traffic flow is composed of a source and destination + * router. If the source/destination routers are moved, then the traffic + * flow needs tp be re-routed. + * + * This datastructure stores a vector of traffic flows that are associated + * to each router cbluster block. A traffic flow is associated to a router + * cluster block if the router block is either the source or destination + * router within the traffic flow. + * + * This is done so that during placement when a router cluster block is + * moved then the traffic flows that need to be re-routed due to the moved + * block can quickly be found. + * */ - std::unordered_map> source_router_associated_traffic_flows; - std::unordered_map> sink_router_associated_traffic_flows; + std::unordered_map> traffic_flows_associated_to_router_blocks; /** keeps track of which traffic flows have already been processed. * By processed, it tracks whether a traffic flow has been routed or @@ -132,7 +138,7 @@ class NocTrafficFlows { * flows have the router as a source or sink within the flow. * */ - void add_traffic_flow_to_associated_routers(NocTrafficFlowId traffic_flow_id, ClusterBlockId associated_router_id, std::unordered_map>& router_associated_traffic_flows); + void add_traffic_flow_to_associated_routers(NocTrafficFlowId traffic_flow_id, ClusterBlockId associated_router_id); /** * @brief Given a router block in the clustered netlist, store it @@ -162,31 +168,18 @@ class NocTrafficFlows { /** * @brief Get a vector of all traffic flows that have a given router - * block in the clustered netlist as the source (starting point) in the - * flow. + * block in the clustered netlist as the source (starting point) or sink + * (destination point) in the flow. If the router block does not have + * any traffic flows associated to it then NULL is returned. * - * @param source_router_id A unique identifier that represents the + * @param router_block_id A unique identifier that represents the * a router block in the clustered netlist. This router block will - * be the source router in the retrieved traffic flow. + * be the source or sink router in the retrieved traffic flows. * @return const std::vector* A vector of traffic - * flows that have the input router block parameter as the source in the - * flow. - */ - const std::vector* get_traffic_flows_associated_to_source_router(ClusterBlockId source_router_id) const; - - /** - * @brief Get a vector of all traffic flows that have a given router - * block in the clustered netlist as the sink (end point) in the - * flow. - * - * @param sink_router_id A unique identifier that represents the - * a router block in the clustered netlist. This router block will - * be the sink router in the retrieved traffic flow. - * @return const std::vector* A vector of traffic - * flows that have the input router block parameter as the sink in the - * flow. + * flows that have the input router block parameter as the source or sink + * in the flow. */ - const std::vector* get_traffic_flows_associated_to_sink_router(ClusterBlockId sink_router_id) const; + const std::vector* get_traffic_flows_associated_to_router_block(ClusterBlockId router_block_id); /** * @brief Given a traffic flow, determine whether it has been processed diff --git a/vpr/test/test_noc_traffic_flows.cpp b/vpr/test/test_noc_traffic_flows.cpp index d5afa360164..4fdb5b00a80 100644 --- a/vpr/test/test_noc_traffic_flows.cpp +++ b/vpr/test/test_noc_traffic_flows.cpp @@ -32,11 +32,10 @@ TEST_CASE("test_adding_traffic_flows", "[vpr_noc_traffic_flows]") { // total traffic flows will be NUM_OF_ROUTERS * (NUM_OF_ROUTERS - 1) // create the traffic flows std::vector golden_traffic_flow_list; - vtr::vector> golden_list_of_associated_links_source_router; - golden_list_of_associated_links_source_router.resize(NUM_OF_ROUTERS); - vtr::vector> golden_list_of_associated_links_sink_router; - golden_list_of_associated_links_sink_router.resize(NUM_OF_ROUTERS); + vtr::vector> golden_list_of_associated_traffic_flows_to_routers; + + golden_list_of_associated_traffic_flows_to_routers.resize(NUM_OF_ROUTERS); for (int router = 0; router < NUM_OF_ROUTERS; router++) { for (int second_router = 0; second_router < NUM_OF_ROUTERS; second_router++) { @@ -53,9 +52,10 @@ TEST_CASE("test_adding_traffic_flows", "[vpr_noc_traffic_flows]") { curr_flow_id = (NocTrafficFlowId)(golden_traffic_flow_list.size() - 1); - // add the traffic flows to the source and sink routers - golden_list_of_associated_links_source_router[source_router_id].emplace_back(curr_flow_id); - golden_list_of_associated_links_sink_router[sink_router_id].emplace_back(curr_flow_id); + // add the current traffic flow as an associated flow to its source and sink routers + golden_list_of_associated_traffic_flows_to_routers[source_router_id].emplace_back(curr_flow_id); + golden_list_of_associated_traffic_flows_to_routers[sink_router_id].emplace_back(curr_flow_id); + } } @@ -97,33 +97,33 @@ TEST_CASE("test_adding_traffic_flows", "[vpr_noc_traffic_flows]") { REQUIRE(curr_traffic_flow.sink_router_cluster_id == golden_traffic_flow_list[traffic_flow].sink_router_cluster_id); } - int size_of_associated_flows_for_source_routers = golden_list_of_associated_links_source_router.size(); - // make sure that the correct traffic flows are added to each router when it is a source - for (int source_router = 0; source_router < size_of_associated_flows_for_source_routers; source_router++) { - source_router_id = (ClusterBlockId)source_router; - - int size_of_current_source_router_associated_traffic_flows = golden_list_of_associated_links_source_router[source_router_id].size(); + // now check that the associated traffic flows for each router is also stored correctly + for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++){ - const std::vector* associated_traffic_flows_to_source_router = traffic_flow_storage.get_traffic_flows_associated_to_source_router(source_router_id); - - for (int source_router_traffic_flow = 0; source_router_traffic_flow < size_of_current_source_router_associated_traffic_flows; source_router_traffic_flow++) { - REQUIRE((size_t)golden_list_of_associated_links_source_router[source_router_id][source_router_traffic_flow] == (size_t)(*associated_traffic_flows_to_source_router)[source_router_traffic_flow]); - } - } + ClusterBlockId router_id = (ClusterBlockId)router_number; - int size_of_associated_flows_for_sink_routers = golden_list_of_associated_links_sink_router.size(); - // make sure that the correct traffic flows are added to each router when it is a sink - for (int sink_router = 0; sink_router < size_of_associated_flows_for_sink_routers; sink_router++) { - sink_router_id = (ClusterBlockId)sink_router; + int number_of_traffic_flows_associated_with_current_router = golden_list_of_associated_traffic_flows_to_routers[router_id].size(); - int size_of_current_sink_router_associated_traffic_flows = golden_list_of_associated_links_sink_router[sink_router_id].size(); + // get the traffic flows associated to the current router from the test datastructure + const std::vector* associated_traffic_flows_to_router = traffic_flow_storage.get_traffic_flows_associated_to_router_block(router_id); - const std::vector* associated_traffic_flows_to_sink_router = traffic_flow_storage.get_traffic_flows_associated_to_sink_router(sink_router_id); + // make sure that the number of traffic flows associated to each router within the Noctrafficflows datastrcuture matches the golden set + REQUIRE((int)associated_traffic_flows_to_router->size() == number_of_traffic_flows_associated_with_current_router); - for (int sink_router_traffic_flow = 0; sink_router_traffic_flow < size_of_current_sink_router_associated_traffic_flows; sink_router_traffic_flow++) { - REQUIRE((size_t)golden_list_of_associated_links_sink_router[sink_router_id][sink_router_traffic_flow] == (size_t)(*associated_traffic_flows_to_sink_router)[sink_router_traffic_flow]); + // now go through the associated traffic flows and make sure the correct ones were added to the current router + for (int router_traffic_flow = 0; router_traffic_flow < number_of_traffic_flows_associated_with_current_router; router_traffic_flow++) { + REQUIRE((size_t)golden_list_of_associated_traffic_flows_to_routers[router_id][router_traffic_flow] == (size_t)(*associated_traffic_flows_to_router)[router_traffic_flow]); } + } + + /* Performing a quick check that when trying to get the associated + traffic flows for invalid router clusters or router clusters + without any associated traffic flows a null value is returned. + Which implies that no traffic flows are associated to the router + cluster. + */ + REQUIRE(traffic_flow_storage.get_traffic_flows_associated_to_router_block((ClusterBlockId)(NUM_OF_ROUTERS + 1)) == nullptr); } SECTION("Checking to see if invalid blocks that are not routers exist in NocTrafficFlows.") { // create a invalid block id @@ -132,19 +132,12 @@ TEST_CASE("test_adding_traffic_flows", "[vpr_noc_traffic_flows]") { // check that this block doesnt exist in the traffic flow datastructure REQUIRE(traffic_flow_storage.check_if_cluster_block_is_a_noc_router(invalid_block) == false); } - SECTION("Checking that when there are no traffics flows where a given router is a source there exists no traffic flows associated with said source router.") { - // create a invalid block id (mimics the effect where a router has no traffic flows associated with it) - ClusterBlockId invalid_block = (ClusterBlockId)(NUM_OF_ROUTERS + 1); - - // check that this router has no traffic flows associated with it - REQUIRE(traffic_flow_storage.get_traffic_flows_associated_to_source_router(invalid_block) == nullptr); - } - SECTION("Checking that when there are no traffics flows where a given router is a sink there exists no traffic flows associated with said sink router.") { + SECTION("Checking that when a router has no traffic flows associated to it, then the associated traffic flows vector retrieved from the NocTrafficFlows class for this router should be null.") { // create a invalid block id (mimics the effect where a router has no traffic flows associated with it) ClusterBlockId invalid_block = (ClusterBlockId)(NUM_OF_ROUTERS + 1); // check that this router has no traffic flows associated with it - REQUIRE(traffic_flow_storage.get_traffic_flows_associated_to_sink_router(invalid_block) == nullptr); + REQUIRE(traffic_flow_storage.get_traffic_flows_associated_to_router_block(invalid_block) == nullptr); } } } // namespace \ No newline at end of file From 77d24b1b2a7ff2ca01f37a68efabac21df420c91 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Thu, 21 Jul 2022 00:22:18 -0400 Subject: [PATCH 112/128] removed a datastructure inside the NocTrafficFlows class that kept track of which traffic flows had been processed or routed already. This was originally inteded to be used during placement, where ine ach iteration traffic flows are re-routed. THis datastructure can be used to ensure that a traffic flow is no re-routed multiple times.THe decision was made to create a local variable during placement to keep track of this. --- vpr/src/noc/noc_traffic_flows.cpp | 26 -------------- vpr/src/noc/noc_traffic_flows.h | 56 ------------------------------- 2 files changed, 82 deletions(-) diff --git a/vpr/src/noc/noc_traffic_flows.cpp b/vpr/src/noc/noc_traffic_flows.cpp index f0a9bf602a9..57f33d66f27 100644 --- a/vpr/src/noc/noc_traffic_flows.cpp +++ b/vpr/src/noc/noc_traffic_flows.cpp @@ -29,10 +29,6 @@ const std::vector* NocTrafficFlows::get_traffic_flows_associat return associated_traffic_flows_ref; } -bool NocTrafficFlows::get_traffic_flow_processed_status(NocTrafficFlowId traffic_flow_id) { - return processed_traffic_flows[traffic_flow_id]; -} - int NocTrafficFlows::get_number_of_routers_used_in_traffic_flows(void) { return noc_router_blocks.size(); } @@ -57,37 +53,15 @@ void NocTrafficFlows::create_noc_traffic_flow(std::string source_router_module_n return; } -// given a traffic flow and its status, update it -void NocTrafficFlows::set_traffic_flow_status(NocTrafficFlowId traffic_flow_id, bool status) { - // status is initialized to false, change it to true to reflect that the specified flow has been processed - processed_traffic_flows[traffic_flow_id] = status; - - return; -} - // utility functions for the noc traffic flows void NocTrafficFlows::finshed_noc_traffic_flows_setup(void) { - // get the total number of traffic flows and create a vector of the same size to hold the "processed status" of each traffic flow - int num_of_traffic_flows = noc_traffic_flows.size(); - // initialize the status to not processed yet - processed_traffic_flows.resize(num_of_traffic_flows, NOT_PROCESSED); - - return; -} - -void NocTrafficFlows::reset_traffic_flows_processed_status(void) { - for (auto traffic_flow = processed_traffic_flows.begin(); traffic_flow != processed_traffic_flows.end(); traffic_flow++) { - *traffic_flow = NOT_PROCESSED; - } - return; } void NocTrafficFlows::clear_traffic_flows(void) { // delete any information from internal datastructures noc_traffic_flows.clear(); - processed_traffic_flows.clear(); noc_router_blocks.clear(); return; diff --git a/vpr/src/noc/noc_traffic_flows.h b/vpr/src/noc/noc_traffic_flows.h index 5c4a0dccd92..58c69699180 100644 --- a/vpr/src/noc/noc_traffic_flows.h +++ b/vpr/src/noc/noc_traffic_flows.h @@ -39,14 +39,6 @@ #include "echo_files.h" #include "vtr_util.h" -/* - * Whenever a traffic flow is processed (routed a connection between - * 2 routers and updated the relevant information) we need to - * some way to track it, so that we don't process it again. The flags below indicate whether a traffic flow was processed or not. - */ -constexpr bool PROCESSED = true; -constexpr bool NOT_PROCESSED = false; - /** * @brief Describes a traffic flow within the NoC, which is the communication * between two routers. THe NocTrafficFlows contains a number of this structure @@ -101,19 +93,6 @@ class NocTrafficFlows { */ std::unordered_map> traffic_flows_associated_to_router_blocks; - /** keeps track of which traffic flows have already been processed. - * By processed, it tracks whether a traffic flow has been routed or - * not. During placement, two routers can be swapped, if the - * two routers share a traffic flow, then the shared traffic flow - * will be routed twice, where it will routed when processing the - * flows associated to the source router and then again when - * processing the flows associated to the sink router. By using the - * datastructure below, if whether a traffic flow is processed or not - * is tracked, then we can ensure that no traffic flows are routed - * more than once by referring to this datastructure. - */ - vtr::vector processed_traffic_flows; - /** contains the cluster ID of all unique router modules in the design. * and can quickly determine whether a given cluster in the netlist * is a router block or not. whenever placement swaps two clusters, we @@ -181,21 +160,6 @@ class NocTrafficFlows { */ const std::vector* get_traffic_flows_associated_to_router_block(ClusterBlockId router_block_id); - /** - * @brief Given a traffic flow, determine whether it has been processed - * or not. By processed, it checks to see whether the traffic flow has - * been routed. This function should be used before routing a traffic - * flow. - * - * @param traffic_flow_id A unique identifier that represents a traffic - * flow - * @return true Represents the case where the traffic flow has been - * processed - * @return false Represents the case where the traffic flow has not - * been processed - */ - bool get_traffic_flow_processed_status(NocTrafficFlowId traffic_flow_id); - /** * @brief Gets the number of unique router blocks in the * clustered netlist that were used within the user provided @@ -235,18 +199,6 @@ class NocTrafficFlows { */ void create_noc_traffic_flow(std::string source_router_module_name, std::string sink_router_module_name, ClusterBlockId source_router_cluster_id, ClusterBlockId sink_router_cluster_id, double traffic_flow_bandwidth, double traffic_flow_latency); - /** - * @brief Set the status of a given traffic flow. The status indicates - * whether the traffic flow has been routed or not. - * - * @param traffic_flow_id A unique identifier that represents a traffic - * flow. - * @param status THe updated status of the traffic flow. True indicating - * that the traffic flow has been router and False indicating that - * the traffic flow has not been routed. - */ - void set_traffic_flow_status(NocTrafficFlowId traffic_flow_id, bool status); - //utility functions /** @@ -259,14 +211,6 @@ class NocTrafficFlows { */ void finshed_noc_traffic_flows_setup(void); - /** - * @brief Goes through the status of all traffic flows - * and sets them to being not processed. This should be - * used before each iteraition of placement. - * - */ - void reset_traffic_flows_processed_status(void); - /** * @brief Resets the class by clearning internal * satastructures. From a78c86720f75abfbf447a7228209a991f4c7011b Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Thu, 21 Jul 2022 01:16:46 -0400 Subject: [PATCH 113/128] created a new status variable that indicates whether the NocTrafficFlows class has all traffic flows added or not. Added the update of this variable within the 'finished_noc_traffic_flows_setup' function. The purpose of this is to ensure that traffic flows are only added once. --- vpr/src/noc/noc_traffic_flows.cpp | 9 ++++++++- vpr/src/noc/noc_traffic_flows.h | 23 +++++++++++++++++------ 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/vpr/src/noc/noc_traffic_flows.cpp b/vpr/src/noc/noc_traffic_flows.cpp index 57f33d66f27..994fc51ee26 100644 --- a/vpr/src/noc/noc_traffic_flows.cpp +++ b/vpr/src/noc/noc_traffic_flows.cpp @@ -2,9 +2,10 @@ #include "noc_traffic_flows.h" #include "vpr_error.h" -// constructor clears all the traffic flow datastructures +// constructor clears all the traffic flow datastructures and indicates that the class has not been constructed yet NocTrafficFlows::NocTrafficFlows(void) { clear_traffic_flows(); + built_traffic_flows = false; } // getters for the traffic flows @@ -36,6 +37,9 @@ int NocTrafficFlows::get_number_of_routers_used_in_traffic_flows(void) { // setters for the traffic flows void NocTrafficFlows::create_noc_traffic_flow(std::string source_router_module_name, std::string sink_router_module_name, ClusterBlockId source_router_cluster_id, ClusterBlockId sink_router_cluster_id, double traffic_flow_bandwidth, double traffic_flow_latency) { + + VTR_ASSERT_MSG(!built_traffic_flows, "NoC traffic flows have already been added, cannot modify further."); + // create and add the new traffic flow to the vector noc_traffic_flows.emplace_back(source_router_module_name, sink_router_module_name, source_router_cluster_id, sink_router_cluster_id, traffic_flow_bandwidth, traffic_flow_latency); @@ -56,6 +60,9 @@ void NocTrafficFlows::create_noc_traffic_flow(std::string source_router_module_n // utility functions for the noc traffic flows void NocTrafficFlows::finshed_noc_traffic_flows_setup(void) { + + // all the traffic flows have been added, so indicate that the class has been constructed and cannot be modified anymore + built_traffic_flows = true; return; } diff --git a/vpr/src/noc/noc_traffic_flows.h b/vpr/src/noc/noc_traffic_flows.h index 58c69699180..214bb60e3ed 100644 --- a/vpr/src/noc/noc_traffic_flows.h +++ b/vpr/src/noc/noc_traffic_flows.h @@ -38,10 +38,11 @@ #include "vtr_vector.h" #include "echo_files.h" #include "vtr_util.h" +#include "vtr_assert.h" /** * @brief Describes a traffic flow within the NoC, which is the communication - * between two routers. THe NocTrafficFlows contains a number of this structure + * between two routers. The NocTrafficFlows contains a number of this structure * to describe all the communication happening within the NoC. * */ @@ -102,6 +103,17 @@ class NocTrafficFlows { * cluster that was swapped furing palcement is a router block or not.*/ std::unordered_set noc_router_blocks; + /** + * Indicates whether the the NocTrafficFlows class has been fully + * constructed. The expectation is that all the traffic flows will + * be added in one spot and will not be added later on. So this variable + * can be used to check whether all the traffic flows have been added or + * or not. The variable should be used to ensure that this class is not + * modified once all the traffic flows have been added. + * + */ + bool built_traffic_flows; + // private functions /** @@ -202,11 +214,10 @@ class NocTrafficFlows { //utility functions /** - * @brief Determines the total number of traffic flows in - * the design and creates a vector to keep track of the traffic - * flows processed status. This function should be called after - * all the traffic flows have been created. The traffic flows are - * all initialized to being not processed. + * @brief Indicates that the class has been fully constructed, meaning + * that all the traffic flows have been added and cannot be added anymore. + * This function should be called only after adding all the traffic flows + * provided by the user. * */ void finshed_noc_traffic_flows_setup(void); From b32fba045c7522a7fed6187d76de68c1a48da3b3 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 22 Jul 2022 00:10:34 -0400 Subject: [PATCH 114/128] removed a datastructure within the NocTrafficFlows class that kep track of unique router cluster blocks within the netlist. The original intended use was to leverage this datastructure when a cluster is moved during placement to check whether the cluster was a router or not. Later, it was determined that this wasn't needed since another datastrurcture that was used to keep track of traffic flows associated to router cluster blocks could be used to determine whether a cluster has traffic flows or not, and if it did then we know its a router block. --- vpr/src/noc/noc_traffic_flows.cpp | 43 +++++++++-------------------- vpr/src/noc/noc_traffic_flows.h | 36 +++++++++--------------- vpr/test/test_noc_traffic_flows.cpp | 15 ++++------ 3 files changed, 31 insertions(+), 63 deletions(-) diff --git a/vpr/src/noc/noc_traffic_flows.cpp b/vpr/src/noc/noc_traffic_flows.cpp index 994fc51ee26..7adfb3bec14 100644 --- a/vpr/src/noc/noc_traffic_flows.cpp +++ b/vpr/src/noc/noc_traffic_flows.cpp @@ -2,9 +2,8 @@ #include "noc_traffic_flows.h" #include "vpr_error.h" -// constructor clears all the traffic flow datastructures and indicates that the class has not been constructed yet +// constructor indicates that the class has not been constructed yet NocTrafficFlows::NocTrafficFlows(void) { - clear_traffic_flows(); built_traffic_flows = false; } @@ -31,7 +30,7 @@ const std::vector* NocTrafficFlows::get_traffic_flows_associat } int NocTrafficFlows::get_number_of_routers_used_in_traffic_flows(void) { - return noc_router_blocks.size(); + return traffic_flows_associated_to_router_blocks.size(); } // setters for the traffic flows @@ -46,10 +45,6 @@ void NocTrafficFlows::create_noc_traffic_flow(std::string source_router_module_n //since the new traffic flow was added to the back of the vector, its id will be the index of the last element NocTrafficFlowId curr_traffic_flow_id = (NocTrafficFlowId)(noc_traffic_flows.size() - 1); - // add the source and sink routers to the set of unique router blocks in the design - add_router_to_block_set(source_router_cluster_id); - add_router_to_block_set(sink_router_cluster_id); - // now add the new traffic flow to flows associated with the current source and sink router add_traffic_flow_to_associated_routers(curr_traffic_flow_id, source_router_cluster_id); add_traffic_flow_to_associated_routers(curr_traffic_flow_id, sink_router_cluster_id); @@ -69,18 +64,22 @@ void NocTrafficFlows::finshed_noc_traffic_flows_setup(void) { void NocTrafficFlows::clear_traffic_flows(void) { // delete any information from internal datastructures noc_traffic_flows.clear(); - noc_router_blocks.clear(); + traffic_flows_associated_to_router_blocks.clear(); + + // indicate that traffic flows need to be added again after clear + built_traffic_flows = false; return; } -bool NocTrafficFlows::check_if_cluster_block_is_a_noc_router(ClusterBlockId block_id) { - auto router_block = noc_router_blocks.find(block_id); +bool NocTrafficFlows::check_if_cluster_block_has_traffic_flows(ClusterBlockId block_id) { + auto traffic_flows = get_traffic_flows_associated_to_router_block(block_id); bool result = false; - // Check if the given cluster block was found inside the set of all router blocks in the design, then this was a router block so return true. Otherwise return false. - if (router_block != noc_router_blocks.end()) { + // Check to see if any traffic flows were found that are associated to the current cluster block + if (traffic_flows != nullptr) { + // current cluster is a router block that has traffic flows it is a part of. So indicate this to the user. result = true; } @@ -105,12 +104,6 @@ void NocTrafficFlows::add_traffic_flow_to_associated_routers(NocTrafficFlowId tr return; } -void NocTrafficFlows::add_router_to_block_set(ClusterBlockId router_block_id) { - noc_router_blocks.insert(router_block_id); - - return; -} - void NocTrafficFlows::echo_noc_traffic_flows(char* file_name) { FILE* fp; fp = vtr::fopen(file_name, "w"); @@ -146,9 +139,9 @@ void NocTrafficFlows::echo_noc_traffic_flows(char* file_name) { traffic_flow_id++; } - // now print the associated traffic flow information for router cluster blocks + // now print the router cluster ids and their associated traffic flow information for router cluster blocks // The associated traffic flows represent flows where the router block is either a source or destination router - fprintf(fp, "List of traffic flows where the router block cluster is a source router:\n"); + fprintf(fp, "List of all unique router cluster blocks and their corresponding traffic flows where the router block is either a source or destination of the traffic flow:\n"); fprintf(fp, "--------------------------------------------------------------\n"); fprintf(fp, "\n"); @@ -170,16 +163,6 @@ void NocTrafficFlows::echo_noc_traffic_flows(char* file_name) { fprintf(fp, "\n\n"); } - // now print all the unique router block cluster ids in the netlist - fprintf(fp, "List of all router block cluster IDs in the netlist:\n"); - fprintf(fp, "--------------------------------------------------------------\n"); - fprintf(fp, "\n"); - - // print all the unique router block cluster ids - for (auto single_router_block = noc_router_blocks.begin(); single_router_block != noc_router_blocks.end(); single_router_block++) { - fprintf(fp, "Router cluster block ID: %lu\n", (size_t)*single_router_block); - } - vtr::fclose(fp); return; diff --git a/vpr/src/noc/noc_traffic_flows.h b/vpr/src/noc/noc_traffic_flows.h index 214bb60e3ed..2111436077b 100644 --- a/vpr/src/noc/noc_traffic_flows.h +++ b/vpr/src/noc/noc_traffic_flows.h @@ -94,15 +94,6 @@ class NocTrafficFlows { */ std::unordered_map> traffic_flows_associated_to_router_blocks; - /** contains the cluster ID of all unique router modules in the design. - * and can quickly determine whether a given cluster in the netlist - * is a router block or not. whenever placement swaps two clusters, we - * need to check if the clusters a router blocks or not, this is needed - * so that we can deterimine if we need to re-route traffic flows. The - * datastructure below can be used to quickly identify whether a given - * cluster that was swapped furing palcement is a router block or not.*/ - std::unordered_set noc_router_blocks; - /** * Indicates whether the the NocTrafficFlows class has been fully * constructed. The expectation is that all the traffic flows will @@ -131,14 +122,6 @@ class NocTrafficFlows { */ void add_traffic_flow_to_associated_routers(NocTrafficFlowId traffic_flow_id, ClusterBlockId associated_router_id); - /** - * @brief Given a router block in the clustered netlist, store it - * internally. - * - * @param router_block_id A unique identifier that rerpesents a router block in the clustered netlist. This id will be stored. - */ - void add_router_to_block_set(ClusterBlockId router_block_id); - public: NocTrafficFlows(); @@ -231,16 +214,23 @@ class NocTrafficFlows { /** * @brief Given a block from the clustered netlist, determine - * if the block is a router. This function should be used during - * each iteration of placement to check whether two swapped clusters - * are routers or not. + * if the block has traffic flows that it is a part of. There are + * three posssible cases seen by this function. Case 1 is when the + * block is not a router. Case 2 is when the block is a router and + * has not traffic flows it is a part of. And finally case three is + * when the block is a router and has traffic flows it is a part of. + * This function should be used during placement when clusters are + * moved or placed. This function can indicate if the moved cluster + * needs traffic flows to be re-routed. If a cluster is a part of a + * traffic flow, then this means that the cluster is either the + * source or sink router of the traffic flow. * * @param block_id A unique identifier that represents a cluster * block in the clustered netlist - * @return true The block is a router - * @return false THe block is not a router + * @return true The block has traffic flows that it is a part of + * @return false The block has no traffic flows it is a prt of */ - bool check_if_cluster_block_is_a_noc_router(ClusterBlockId block_id); + bool check_if_cluster_block_has_traffic_flows(ClusterBlockId block_id); /** * @brief Writes out the NocTrafficFlows class information to a file. diff --git a/vpr/test/test_noc_traffic_flows.cpp b/vpr/test/test_noc_traffic_flows.cpp index 4fdb5b00a80..507ab375371 100644 --- a/vpr/test/test_noc_traffic_flows.cpp +++ b/vpr/test/test_noc_traffic_flows.cpp @@ -82,7 +82,7 @@ TEST_CASE("test_adding_traffic_flows", "[vpr_noc_traffic_flows]") { // check the set of routers first to see that they were all added properly for (int router = 0; router < size_of_router_block_list; router++) { // every router in the golden list needs to exist in the traffic flow datastructure (this also tests cases where a router was added multiple times, this shouldnt affect it) - REQUIRE(traffic_flow_storage.check_if_cluster_block_is_a_noc_router(golden_router_blocks_list[router]) == true); + REQUIRE(traffic_flow_storage.check_if_cluster_block_has_traffic_flows(golden_router_blocks_list[router]) == true); } int size_of_traffic_flow_list = golden_traffic_flow_list.size(); @@ -115,22 +115,17 @@ TEST_CASE("test_adding_traffic_flows", "[vpr_noc_traffic_flows]") { REQUIRE((size_t)golden_list_of_associated_traffic_flows_to_routers[router_id][router_traffic_flow] == (size_t)(*associated_traffic_flows_to_router)[router_traffic_flow]); } - } + } - /* Performing a quick check that when trying to get the associated - traffic flows for invalid router clusters or router clusters - without any associated traffic flows a null value is returned. - Which implies that no traffic flows are associated to the router - cluster. - */ - REQUIRE(traffic_flow_storage.get_traffic_flows_associated_to_router_block((ClusterBlockId)(NUM_OF_ROUTERS + 1)) == nullptr); + // make sure that the number of unique routers stored inside the NocTrafficFlows class is what we expect it should be + REQUIRE(NUM_OF_ROUTERS == traffic_flow_storage.get_number_of_routers_used_in_traffic_flows()); } SECTION("Checking to see if invalid blocks that are not routers exist in NocTrafficFlows.") { // create a invalid block id ClusterBlockId invalid_block = (ClusterBlockId)(NUM_OF_ROUTERS + 1); // check that this block doesnt exist in the traffic flow datastructure - REQUIRE(traffic_flow_storage.check_if_cluster_block_is_a_noc_router(invalid_block) == false); + REQUIRE(traffic_flow_storage.check_if_cluster_block_has_traffic_flows(invalid_block) == false); } SECTION("Checking that when a router has no traffic flows associated to it, then the associated traffic flows vector retrieved from the NocTrafficFlows class for this router should be null.") { // create a invalid block id (mimics the effect where a router has no traffic flows associated with it) From c9e568c1a4dc05179eab67117a9d6e0b57fa6287 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 22 Jul 2022 13:20:07 -0400 Subject: [PATCH 115/128] updating comments --- vpr/src/noc/noc_traffic_flows.h | 39 ++++++++++++++++----------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/vpr/src/noc/noc_traffic_flows.h b/vpr/src/noc/noc_traffic_flows.h index 2111436077b..602364a6bc5 100644 --- a/vpr/src/noc/noc_traffic_flows.h +++ b/vpr/src/noc/noc_traffic_flows.h @@ -13,18 +13,17 @@ * Each traffic flow is indexed by a unique id that can be used to * retrieve information about them. * - * The class also associates traffic flows to their source routers (start point) - * and sink routers (end point). This is useful if one wants to find traffic - * flows based on just the source or sink router. - * + * The class also associates traffic flows to their logical source routers + * (start point) and logical sink routers (end point). This is useful if one wants to find traffic flows based on just the source or sink logical router. * The routes for the traffic flows are expected to change throughout placement - * as routers will be moved throughout the chip. Therefore this class provides + * as routers will be moved within the chip. Therefore this class provides * a datastructure to keep track of which flows have been updated (re-routed). * - * Finally, this class also stores all router blocks in the design. + * Finally, this class also stores all router blocks (logical routers) in the + * design. * * This class will be primarily used during - * placement to identify which routers inside the NoC(NocStorage) need to + * placement to identify which routers inside the NoC(NocStorage) need to be * routed to each other.This is important since the router modules can be moved * around to different tiles on the FPGA device. * @@ -42,23 +41,23 @@ /** * @brief Describes a traffic flow within the NoC, which is the communication - * between two routers. The NocTrafficFlows contains a number of this structure - * to describe all the communication happening within the NoC. + * between two logical routers. The NocTrafficFlows contains a number of this + * structure to describe all the communication happening within the NoC. * */ struct t_noc_traffic_flow { - /** stores the names of the router blocks communicating within this traffic flow*/ + /** stores the partial names of the router blocks communicating within this traffic flow. Names must uniquely identify router blocks in the netlist.*/ std::string source_router_module_name; std::string sink_router_module_name; - /** stores the block id of the two routers blocks communicating within this traffic flow. This can be used to retrieve the block information from the clustered netlist*/ + /** stores the block id of the two router blocks communicating within this traffic flow. This can be used to retrieve the block information from the clustered netlist*/ ClusterBlockId source_router_cluster_id; ClusterBlockId sink_router_cluster_id; - /** The bandwidth of the information transferred between the two routers. Units in bps. This parameters will be used to update the link usage in the noc model after routing the traffic flow.*/ + /** The bandwidth of the information transferred between the two routers. Units in bytes per second. This parameters will be used to update the link usage in the noc model after routing the traffic flow.*/ double traffic_flow_bandwidth; - /** The maximum allowable time to transmit data between thw two routers. This parameter will be used to evaluate a router traffic flow.*/ + /** The maximum allowable time to transmit data between thw two routers, in seconds. This parameter will be used to evaluate a router traffic flow.*/ double max_traffic_flow_latency; /** Constructor initializes all variables*/ @@ -168,13 +167,13 @@ class NocTrafficFlows { // setters /** - * @brief Given a set of parameters that describe a traffic - * flow, create it an add it to the vector of traffic flows in the - * design. Additionally, the two router blocks involved have their - * ids stored to to keep track of all router blocks that are used - * in traffic flows. Finally, the newly created traffic flow is - * also added to a vector of traffic flows that are associated to both - * the source and sink routers of the flow. + * @brief Given a set of parameters that specify a traffic + * flow, create and add the specified traffic flow it to the vector of + * flows in the design. + * + * Finally, the newly created traffic flow is + * also added to internal datastructures that can be used to quickly + * look up which traffic flows contain a specific router cluster block. * * @param source_router_module_name A string that represents the * name of the source router block in the traffic flow. THis is From 57bfd963df3c46733b1e76653052735489dce4ca Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 22 Jul 2022 13:26:34 -0400 Subject: [PATCH 116/128] cleaned up some code and improved fixed/improved comments for the NocTrafficFlows class within the NoC Context --- vpr/src/base/vpr_api.cpp | 2 +- vpr/src/base/vpr_context.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index 3cfa09f9d28..116685e5d93 100644 --- a/vpr/src/base/vpr_api.cpp +++ b/vpr/src/base/vpr_api.cpp @@ -516,7 +516,7 @@ void vpr_setup_clock_networks(t_vpr_setup& vpr_setup, const t_arch& Arch) { */ void vpr_setup_noc(const t_vpr_setup& vpr_setup, const t_arch& arch) { // check if the user provided the option to model the noc - if (vpr_setup.NocOpts.noc == true) { + if (vpr_setup.NocOpts.noc) { // create the NoC model based on the user description from the arch file setup_noc(arch); // read and store the noc traffic flow information diff --git a/vpr/src/base/vpr_context.h b/vpr/src/base/vpr_context.h index b58b7e22ccb..4343cdbba60 100644 --- a/vpr/src/base/vpr_context.h +++ b/vpr/src/base/vpr_context.h @@ -430,9 +430,9 @@ struct NocContext : public Context { NocStorage noc_model; /** - * @brief Stores all the communication happening betwee routers in the NoC + * @brief Stores all the communication happening between routers in the NoC * - * Contains all of the traffic flows that describe which two routers are communication with each other and also some metrics and constraints on the data transfer between the two routers. + * Contains all of the traffic flows that ddescribe 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. From 6551f65c2525ac359ea0cc0f69e9e12350e3f2df Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Fri, 22 Jul 2022 13:37:57 -0400 Subject: [PATCH 117/128] Added comments to clarify why certain parameters were passed in to functions --- vpr/src/noc/read_xml_noc_traffic_flows_file.h | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.h b/vpr/src/noc/read_xml_noc_traffic_flows_file.h index ea5de99cc14..359b2d82c31 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.h +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.h @@ -59,8 +59,10 @@ void read_xml_noc_traffic_flows_file(const char* noc_flows_file); * is verified and if it is legal then this traffic flow is added * to the NocTrafficFlows class. * - * @param single_flow_tag A xml tag that contains the traffic flow information - * @param loc_data Contains location data about the current line in the xml file + * @param single_flow_tag A xml tag that contains the traffic flow information. + * Passed in for error logging. + * @param loc_data Contains location data about the current line in the xml + * file. Passed in for error logging. * @param cluster_ctx Global variable that contains clustering information. Used * to get information about the router blocks int he design. * @param noc_ctx Global variable that contains NoC information. Used to access @@ -76,14 +78,17 @@ void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_dat /** * @brief Checks to see that the two router module names provided in the * traffic flow description are not empty and they dont have the - * same names. THe two routers cant be the exact same since a router - * cannot communicate with itself. + * same names. The two routers cant be the exact same since a router + * cannot communicate with itself. These names can be partial and not the + * exact name of the router blocks. * * @param source_router_name A string value of the source router module name * @param sink_router_name A string value of the sink router * module name - * @param single_flow_tag A xml tag that contains the traffic flow information - * @param loc_data Contains location data about the current line in the xml file + * @param single_flow_tag A xml tag that contains the traffic flow information. + * Passed in for error logging. + * @param loc_data Contains location data about the current line in the xml + * file. Passed in for error logging. */ void verify_traffic_flow_router_modules(std::string source_router_name, std::string sink_router_name, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data); @@ -96,8 +101,10 @@ void verify_traffic_flow_router_modules(std::string source_router_name, std::str * @param max_traffic_flow_latency The allowable latency for the data * transmission between the two routers in the * traffic flow. - * @param single_flow_tag A xml tag that contains the traffic flow information - * @param loc_data Contains location data about the current line in the xml file + * @param single_flow_tag A xml tag that contains the traffic flow information. + * Passed in for error logging. + * @param loc_data Contains location data about the current line in the xml + * file. Passed in for error logging. */ void verify_traffic_flow_properties(double traffic_flow_bandwidth, double max_traffic_flow_latency, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data); @@ -111,8 +118,10 @@ void verify_traffic_flow_properties(double traffic_flow_bandwidth, double max_tr * @param cluster_ctx Global variable that contains clustering information. * Contains a datastructure to convert a module name to * a cluster block id. - * @param single_flow_tag A xml tag that contains the traffic flow information - * @param loc_data Contains location data about the current line in the xml file + * @param single_flow_tag A xml tag that contains the traffic flow information. + * Passed in for error logging. + * @param loc_data Contains location data about the current line in the xml + * file. Passed in for error logging. * @param cluster_blocks_compatible_with_noc_router_tiles A vector of cluster * blocks in the netlist that are * compatible with a noc router tile. @@ -131,8 +140,10 @@ ClusterBlockId get_router_module_cluster_id(std::string router_module_name, cons * check whether it is of type router. * @param router_module_id The ClusterBlockId of the router block we are trying * to check if its of type router. - * @param single_flow_tag A xml tag that contains the traffic flow information - * @param loc_data Contains location data about the current line in the xml file + * @param single_flow_tag A xml tag that contains the traffic flow information. + * Passed in for error logging. + * @param loc_data Contains location data about the current line in the xml + * file. Passed in for error logging. * @param cluster_ctx Global variable that contains clustering information. * Contains a datastructure to get the logical type of a * router cluster block. From 5137869135b406e6ed2f8cdd413819734d41afdd Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Sat, 23 Jul 2022 13:20:01 -0400 Subject: [PATCH 118/128] Changed example noc traffic flows file to use more realistic constraints and updated README description for the NoC related benchmarks. --- vtr_flow/benchmarks/noc/Readme.txt | 10 ++++++---- .../multiple_noc_routers.flows | 4 ++-- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/vtr_flow/benchmarks/noc/Readme.txt b/vtr_flow/benchmarks/noc/Readme.txt index a9f2aee2d7b..f9117406c87 100644 --- a/vtr_flow/benchmarks/noc/Readme.txt +++ b/vtr_flow/benchmarks/noc/Readme.txt @@ -18,7 +18,7 @@ test_benchmark_circuit: # Test Benchmark Designs The benchmark designs found under the "Test_Designs" folder are relatively -simple designs that are mainly used to verify components NoC flow in the VPR software. +simple designs that are mainly used to verify components NoC CAD flow in the VPR software. Whenever a new or existing feature needs to be tested, the benchmark designs found here should be used. @@ -27,14 +27,16 @@ should be used. The benchmark designs found under the "Synthetic_Designs" folder are small to medium sized designs that are used verify the correctness of the VPR software. These designs -are manually created to guarantee and optimal reference solution. By running these designs -through VPR, we can determine the correctness of the NoC flow based on the reference solution. +are manually created to have understandable structures. For example, a mesh with traffic +flows to nearest neighbours where we know the optimal solution for NoC traffic minimization. +By running these designs through VPR, we can determine the correctness of the NoC CAD flow +based on the reference solution. # Large Benchmark Designs The benchmark designs found under the "Large Designs" folder and medium to large complex designs to determine the performance of the NoC flow within the VPR software. Changes made -to the NoC flow in VPR can be evaluated by running these benchmark designs and comparing +to the NoC CAD flow in VPR can be evaluated by running these benchmark designs and comparing the results with previous versions. # Adding New Benchmark Designs diff --git a/vtr_flow/benchmarks/noc/Test_Designs/test_design_for_noc_traffic_flows_feature/multiple_noc_routers.flows b/vtr_flow/benchmarks/noc/Test_Designs/test_design_for_noc_traffic_flows_feature/multiple_noc_routers.flows index 6b8a7fa385b..494d7519ca8 100755 --- a/vtr_flow/benchmarks/noc/Test_Designs/test_design_for_noc_traffic_flows_feature/multiple_noc_routers.flows +++ b/vtr_flow/benchmarks/noc/Test_Designs/test_design_for_noc_traffic_flows_feature/multiple_noc_routers.flows @@ -1,7 +1,7 @@ - + - + From 5eba6ac2186c54f421783d32718db59720b13a9b Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Sun, 24 Jul 2022 21:14:54 -0400 Subject: [PATCH 119/128] removed header declaration for a function that was previously removed --- vpr/src/base/clustered_netlist.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/vpr/src/base/clustered_netlist.h b/vpr/src/base/clustered_netlist.h index 4ec6a657545..2bc3557dd6b 100644 --- a/vpr/src/base/clustered_netlist.h +++ b/vpr/src/base/clustered_netlist.h @@ -257,9 +257,6 @@ class ClusteredNetlist : public Netlist Date: Mon, 25 Jul 2022 02:04:18 -0400 Subject: [PATCH 120/128] cleaned up code commenting and fixed formatting --- vpr/src/base/clustered_netlist.cpp | 39 ------------- vpr/src/base/clustered_netlist.h | 56 +++++++++++++++++++ vpr/src/base/netlist.h | 36 +++++++++++- vpr/src/base/netlist.tpp | 28 ---------- vpr/src/noc/noc_traffic_flows.cpp | 13 ++--- vpr/src/noc/noc_traffic_flows.h | 3 +- .../noc/read_xml_noc_traffic_flows_file.cpp | 30 ++++++---- vpr/test/test_noc_traffic_flows.cpp | 9 +-- .../test_read_xml_noc_traffic_flows_file.cpp | 17 ++---- 9 files changed, 121 insertions(+), 110 deletions(-) diff --git a/vpr/src/base/clustered_netlist.cpp b/vpr/src/base/clustered_netlist.cpp index c5a4961d5b4..73326961c14 100644 --- a/vpr/src/base/clustered_netlist.cpp +++ b/vpr/src/base/clustered_netlist.cpp @@ -307,45 +307,6 @@ bool ClusteredNetlist::validate_net_sizes_impl(size_t num_nets) const { return true; } -/** - * @brief Finds a block where the block's name matches to the provided - * input string pattern. - * The intented use is to find the block id of a - * hard block without knowing its name in the netlist. Instead - * a pattern can be created that we know the block's name will - * match to. Generally, we expect the pattern to be constructed - * using the block's module name in the HDL design, since we can - * expect the netlist name of the block to include the module - * name within it. - * - * For example, suppose a RAM block was named in the netlist as - * "top|alu|test_ram|out". The user instantiated the ram module - * in the HDL design as "test_ram". So instead of going through - * the netlist and finding the ram block's full name, this - * function can be used by just providing the string pattern as - * ".*test_ram.*". We know that the module name should be somewhere - * within the string, so the pattern we provide says that the netlist - * name of the block contains arbritary characters then the module name - * and then some other arbritary characters after. This pattern will - * then be used to match to the block in the netlist. - * - * This function runs in linear time (O(N)) as it goes over all the - * cluster blocks in the netlist. Additionally, if there are multiple - * blocks that match to the provided input pattern, then the - * first block found is returned. - * - * There is a similiar function in the Netlist Class. This function - * additionally requires the logical type of the block as well. Since - * the inteded use is to find hard blocks, it is quite inefficient to - * to go through all the blocks to find a matching one. Instead, an - * additional datastructure is created that groups clusters by their - * logical type. This function filters the clusters and only searches - * for the matching block within a list of blocks that are the same - * logical type. The idea here is that the filtered list should be - * considereably smaller that a list of every block in the netlist - * and this should help improve run time. - * - */ ClusterBlockId ClusteredNetlist::find_block_by_name_fragment(const std::string& name, const std::vector& cluster_block_candidates) const { ClusterBlockId blk_id = ClusterBlockId::INVALID(); std::regex name_to_match(name); diff --git a/vpr/src/base/clustered_netlist.h b/vpr/src/base/clustered_netlist.h index 2bc3557dd6b..9915f7843cd 100644 --- a/vpr/src/base/clustered_netlist.h +++ b/vpr/src/base/clustered_netlist.h @@ -241,6 +241,62 @@ class ClusteredNetlist : public Netlist& cluster_block_candidates) const; private: //Private Members diff --git a/vpr/src/base/netlist.h b/vpr/src/base/netlist.h index 5944b5ad0db..96dff5d7167 100644 --- a/vpr/src/base/netlist.h +++ b/vpr/src/base/netlist.h @@ -728,9 +728,39 @@ class Netlist { BlockId find_block(const std::string& name) const; /** - * @brief Returns the BlockId of the specified block or BlockId::INVALID() if not found. The name of the block ID returned contains the provided input as a substring. - * - * @param name A substring of a block name for which an ID needs to be found. + * @brief Finds a block where the block's name contains the + * provided input name as a substring. + * The intented use is to find the block id of a + * hard block without knowing its name in the netlist. Instead + * the block's module name in the HDL design can be used as it will + * be a substring within its full name in the netlist. + * + * For example, suppose a RAM block was named in the netlist as + * "top|alu|test_ram|out". The user instantiated the ram module + * in the HDL design as "test_ram". So instead of going through + * the netlist and finding the ram block's full name, this + * function can be used by just providing the module name "test_ram" + * and using this substring to match the blocks name in the netlist + * and retrieving its block id. If no blocks matched to input pattern + * then an invalid block id is returned. + * + * This function runs in linear time (O(N)) as it goes over all the + * cluster blocks in the netlist. Additionally, if there are multiple + * blocks that contain the provided input as a substring, then the + * first block found is returned. + * + * NOTE: This function tries to find blocks by checking for + * substrings. + * The clustered netlist class defines another version of this + * function that find blocks by checking for a pattern match, + * meaning that the input is a pattern string and the pattern + * is looked for ine each block name. + * + * @param name A substring of a block name for which an ID needs to be + * found. + * @return A cluster block id representing a unique cluster block that + * matched to the input string pattern. + * */ BlockId find_block_by_name_fragment(const std::string& name) const; diff --git a/vpr/src/base/netlist.tpp b/vpr/src/base/netlist.tpp index 0bb2412fd89..f5ee6a18556 100644 --- a/vpr/src/base/netlist.tpp +++ b/vpr/src/base/netlist.tpp @@ -458,34 +458,6 @@ BlockId Netlist::find_block(const std::string& na } } -/** - * @brief Finds a block where the block's name contains the - * provided input name as a substring. - * The intented use is to find the block id of a - * hard block without knowing its name in the netlist. Instead - * the block's module name in the HDL design can be used as it will - * be a substring within its full name in the netlist. - * - * For example, suppose a RAM block was named in the netlist as - * "top|alu|test_ram|out". The user instantiated the ram module - * in the HDL design as "test_ram". So instead of going through - * the netlist and finding the ram block's full name, this - * function can be used by just providing the module name "test_ram" - * and using this substring to match the blocks name in the netlist - * and retrieving its block id. - * - * This function runs in linear time (O(N)) as it goes over all the - * cluster blocks in the netlist. Additionally, if there are multiple - * blocks that contain the provided input as a substring, then the - * first block found is returned. - * - * NOTE: This function tries to find blocks by checking for substrings. - * The clustered netlist class defines another version of this - * function that find blocks by checking for a pattern match, - * meaning that the input is a pattern string and the pattern - * is looked for ine each block name. - * - */ template BlockId Netlist::find_block_by_name_fragment(const std::string& name) const { BlockId matching_blk_id = BlockId::INVALID(); diff --git a/vpr/src/noc/noc_traffic_flows.cpp b/vpr/src/noc/noc_traffic_flows.cpp index 7adfb3bec14..b4e7b685eda 100644 --- a/vpr/src/noc/noc_traffic_flows.cpp +++ b/vpr/src/noc/noc_traffic_flows.cpp @@ -2,8 +2,8 @@ #include "noc_traffic_flows.h" #include "vpr_error.h" -// constructor indicates that the class has not been constructed yet -NocTrafficFlows::NocTrafficFlows(void) { +// constructor indicates that the class has not been properly initialized yet as the user supplied traffic flows have not been added. +NocTrafficFlows::NocTrafficFlows() { built_traffic_flows = false; } @@ -13,8 +13,7 @@ const t_noc_traffic_flow& NocTrafficFlows::get_single_noc_traffic_flow(NocTraffi return noc_traffic_flows[traffic_flow_id]; } -const std::vector* NocTrafficFlows::get_traffic_flows_associated_to_router_block(ClusterBlockId router_block_id){ - +const std::vector* NocTrafficFlows::get_traffic_flows_associated_to_router_block(ClusterBlockId router_block_id) { const std::vector* associated_traffic_flows_ref = nullptr; // get a reference to the traffic flows that have the current router as a source or sink @@ -22,7 +21,7 @@ const std::vector* NocTrafficFlows::get_traffic_flows_associat // check if there are any traffic flows associated with the current router if (associated_traffic_flows != traffic_flows_associated_to_router_blocks.end()) { - // if we are here then there exists atleast 1 traffic flow that includes the current router as a source or sink + // if we are here then there exists at least 1 traffic flow that includes the current router as a source or sink associated_traffic_flows_ref = &(associated_traffic_flows->second); } @@ -36,9 +35,8 @@ int NocTrafficFlows::get_number_of_routers_used_in_traffic_flows(void) { // setters for the traffic flows void NocTrafficFlows::create_noc_traffic_flow(std::string source_router_module_name, std::string sink_router_module_name, ClusterBlockId source_router_cluster_id, ClusterBlockId sink_router_cluster_id, double traffic_flow_bandwidth, double traffic_flow_latency) { - VTR_ASSERT_MSG(!built_traffic_flows, "NoC traffic flows have already been added, cannot modify further."); - + // create and add the new traffic flow to the vector noc_traffic_flows.emplace_back(source_router_module_name, sink_router_module_name, source_router_cluster_id, sink_router_cluster_id, traffic_flow_bandwidth, traffic_flow_latency); @@ -55,7 +53,6 @@ void NocTrafficFlows::create_noc_traffic_flow(std::string source_router_module_n // utility functions for the noc traffic flows void NocTrafficFlows::finshed_noc_traffic_flows_setup(void) { - // all the traffic flows have been added, so indicate that the class has been constructed and cannot be modified anymore built_traffic_flows = true; return; diff --git a/vpr/src/noc/noc_traffic_flows.h b/vpr/src/noc/noc_traffic_flows.h index 602364a6bc5..1d15ab9c2f9 100644 --- a/vpr/src/noc/noc_traffic_flows.h +++ b/vpr/src/noc/noc_traffic_flows.h @@ -75,7 +75,6 @@ class NocTrafficFlows { /** contains all the traffic flows provided by the user and their information*/ vtr::vector noc_traffic_flows; - /** * @brief Each traffic flow is composed of a source and destination * router. If the source/destination routers are moved, then the traffic @@ -103,7 +102,7 @@ class NocTrafficFlows { * */ bool built_traffic_flows; - + // private functions /** diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index 3e18087c909..4600b7974fa 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -7,16 +7,13 @@ void read_xml_noc_traffic_flows_file(const char* noc_flows_file) { VPR_FATAL_ERROR(VPR_ERROR_OTHER, "NoC traffic flows file '%s' has an unknown extension. Expecting .flows for NoC traffic flow files.", noc_flows_file); } - // cluster information const ClusteringContext& cluster_ctx = g_vpr_ctx.clustering(); - // noc information + // get the modifiable NoC as we will be adding traffic flows to it here NocContext& noc_ctx = g_vpr_ctx.mutable_noc(); - // device information const DeviceContext& device_ctx = g_vpr_ctx.device(); - // get the physical type of a noc router t_physical_tile_type_ptr noc_router_tile_type = get_physical_type_of_noc_router_tile(device_ctx, noc_ctx); /* Get the cluster blocks that are compatible with a physical NoC router @@ -34,7 +31,11 @@ void read_xml_noc_traffic_flows_file(const char* noc_flows_file) { std::vector cluster_blocks_compatible_with_noc_router_tiles; get_cluster_blocks_compatible_with_noc_router_tiles(cluster_ctx, noc_router_tile_type, cluster_blocks_compatible_with_noc_router_tiles); - /* variabled used when parsing the file */ + /* variabled used when parsing the file. + * Stores xml related information while parsing the file, such as current + * line number, current tag and etc. These variables will be used to + * provide additional information to the user when reporting an error. + */ pugi::xml_document doc; pugiutil::loc_data loc_data; @@ -84,11 +85,12 @@ void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_dat pugiutil::expect_only_attributes(single_flow_tag, expected_single_flow_attributes, loc_data); // store the names of the routers part of this traffic flow + // These names should regex match to a logical router within the clustered netlist std::string source_router_module_name = pugiutil::get_attribute(single_flow_tag, "src", loc_data, pugiutil::REQUIRED).as_string(); std::string sink_router_module_name = pugiutil::get_attribute(single_flow_tag, "dst", loc_data, pugiutil::REQUIRED).as_string(); - //verify whether the router module names are legal + //verify whether the router module names are valid non-empty strings verify_traffic_flow_router_modules(source_router_module_name, sink_router_module_name, single_flow_tag, loc_data); // assign the unique block ids of the two router modules after clustering @@ -137,8 +139,7 @@ void verify_traffic_flow_properties(double traffic_flow_bandwidth, double max_tr ClusterBlockId get_router_module_cluster_id(std::string router_module_name, const ClusteringContext& cluster_ctx, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data, const std::vector& cluster_blocks_compatible_with_noc_router_tiles) { ClusterBlockId router_module_id = ClusterBlockId::INVALID(); - // find the cluster block whos name matches to the provided router module name provided by the user - // Then get the corresponding cluster block id if a valid block was found + // Given a regex pattern, use it to match a name of a cluster router block within the clustered netlist. If a matching cluster block is found, then return its cluster block id. try { router_module_id = cluster_ctx.clb_nlist.find_block_by_name_fragment(router_module_name, cluster_blocks_compatible_with_noc_router_tiles); } catch (const std::regex_error& error) { @@ -160,9 +161,10 @@ void check_traffic_flow_router_module_type(std::string router_module_name, Clust t_logical_block_type_ptr router_module_logical_type = cluster_ctx.clb_nlist.block_type(router_module_id); /* - * Check whether the current router modules logical type is compatible + * Check whether the current router module logical type is compatible * with the physical type of a noc router (can the module be placed on a - * noc router tile on the FPGA device). If not then this module is not a router so throw an error. + * noc router tile on the FPGA device). If not then this module is not a + * router so throw an error. */ if (!is_tile_compatible(noc_router_tile_type, router_module_logical_type)) { vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "The supplied module name '%s' is not a NoC router.", router_module_name.c_str()); @@ -173,6 +175,7 @@ void check_traffic_flow_router_module_type(std::string router_module_name, Clust t_physical_tile_type_ptr get_physical_type_of_noc_router_tile(const DeviceContext& device_ctx, NocContext& noc_ctx) { // get a reference to a single physical noc router + // assuming that all routers have the same physical type, so we are just using the physical type of the first router stored within the NoC auto physical_noc_router = noc_ctx.noc_model.get_noc_routers().begin(); //Using the routers grid position go to the device and identify the physical type of the tile located there. @@ -198,8 +201,11 @@ bool check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& no } } - /* - * Every router block in the design needs to be part of a traffic flow. There can never be a router that isnt part of a traffic flow, other wise the router is doing nothing. So check that the number of unique routers in all traffic flows equals the number of router blocks in the design, otherwise throw an warning to let the user know. If there aren't + /* Every router block in the design needs to be part of a traffic flow. + * There can never be a router that isn't part of a traffic flow, otherwise + * the router is doing nothing. So check that the number of unique routers + * in all traffic flows equals the number of router blocks in the design, + * otherwise throw a warning to let the user know. If there aren't * any traffic flows for any routers then the NoC is not being used. */ if (noc_ctx.noc_traffic_flows_storage.get_number_of_routers_used_in_traffic_flows() != number_of_router_blocks_in_design) { diff --git a/vpr/test/test_noc_traffic_flows.cpp b/vpr/test/test_noc_traffic_flows.cpp index 507ab375371..15f8c758144 100644 --- a/vpr/test/test_noc_traffic_flows.cpp +++ b/vpr/test/test_noc_traffic_flows.cpp @@ -55,7 +55,6 @@ TEST_CASE("test_adding_traffic_flows", "[vpr_noc_traffic_flows]") { // add the current traffic flow as an associated flow to its source and sink routers golden_list_of_associated_traffic_flows_to_routers[source_router_id].emplace_back(curr_flow_id); golden_list_of_associated_traffic_flows_to_routers[sink_router_id].emplace_back(curr_flow_id); - } } @@ -98,8 +97,7 @@ TEST_CASE("test_adding_traffic_flows", "[vpr_noc_traffic_flows]") { } // now check that the associated traffic flows for each router is also stored correctly - for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++){ - + for (int router_number = 0; router_number < NUM_OF_ROUTERS; router_number++) { ClusterBlockId router_id = (ClusterBlockId)router_number; int number_of_traffic_flows_associated_with_current_router = golden_list_of_associated_traffic_flows_to_routers[router_id].size(); @@ -114,11 +112,10 @@ TEST_CASE("test_adding_traffic_flows", "[vpr_noc_traffic_flows]") { for (int router_traffic_flow = 0; router_traffic_flow < number_of_traffic_flows_associated_with_current_router; router_traffic_flow++) { REQUIRE((size_t)golden_list_of_associated_traffic_flows_to_routers[router_id][router_traffic_flow] == (size_t)(*associated_traffic_flows_to_router)[router_traffic_flow]); } - - } + } // make sure that the number of unique routers stored inside the NocTrafficFlows class is what we expect it should be - REQUIRE(NUM_OF_ROUTERS == traffic_flow_storage.get_number_of_routers_used_in_traffic_flows()); + REQUIRE(NUM_OF_ROUTERS == traffic_flow_storage.get_number_of_routers_used_in_traffic_flows()); } SECTION("Checking to see if invalid blocks that are not routers exist in NocTrafficFlows.") { // create a invalid block id diff --git a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp index e29e7be7b56..7109f7a5ccd 100644 --- a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp +++ b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp @@ -404,7 +404,6 @@ TEST_CASE("test_check_that_all_router_blocks_have_an_associated_traffic_flow", " } } TEST_CASE("test_get_cluster_blocks_compatible_with_noc_router_tiles", "[vpr_noc_traffic_flows_parser]") { - // get the global netlist ClusteringContext& cluster_ctx = g_vpr_ctx.mutable_clustering(); ClusteredNetlist* test_netlist = &cluster_ctx.clb_nlist; @@ -449,7 +448,7 @@ TEST_CASE("test_get_cluster_blocks_compatible_with_noc_router_tiles", "[vpr_noc_ // create a physical tile for I/O blocks t_physical_tile_type i_o_block_tile; - // indicate that the io physical tile is not an input/output. Just for this test + // indicate that the io physical tile is not an input/output. Just for this test i_o_block_tile.is_input_type = false; i_o_block_tile.is_output_type = false; @@ -462,11 +461,9 @@ TEST_CASE("test_get_cluster_blocks_compatible_with_noc_router_tiles", "[vpr_noc_ // this is a golden set that the output of this test will be compared to std::vector golden_set_of_router_cluster_blocks_in_netlist; - - SECTION("Test case where all router cluster blocks are correctly identified within the netlist and stored."){ - + SECTION("Test case where all router cluster blocks are correctly identified within the netlist and stored.") { // create some sample router blocks and add them to the clustered netlsit - + // create names for some router blocks char router_one[] = "noc_router_one"; char router_two[] = "noc_router_two"; @@ -489,19 +486,15 @@ TEST_CASE("test_get_cluster_blocks_compatible_with_noc_router_tiles", "[vpr_noc_ REQUIRE(golden_set_of_router_cluster_blocks_in_netlist.size() == found_cluster_blocks_that_are_noc_router_compatible.size()); // now go through the golden set and check that the router blocks in the golden set were correctly found by the test function - for (auto golden_set_router_block_id = golden_set_of_router_cluster_blocks_in_netlist.begin(); golden_set_router_block_id != golden_set_of_router_cluster_blocks_in_netlist.end(); golden_set_router_block_id++){ - + for (auto golden_set_router_block_id = golden_set_of_router_cluster_blocks_in_netlist.begin(); golden_set_router_block_id != golden_set_of_router_cluster_blocks_in_netlist.end(); golden_set_router_block_id++) { // no check that the current router block in the golden set was also found by the test and recognized as being a router logical block REQUIRE(std::find(found_cluster_blocks_that_are_noc_router_compatible.begin(), found_cluster_blocks_that_are_noc_router_compatible.end(), *golden_set_router_block_id) != found_cluster_blocks_that_are_noc_router_compatible.end()); - } // clear the global netlist datastructure so other unit tests that rely on dont use a corrupted netlist free_clustered_netlist(); - } - SECTION("Test case where non router blocks are correctly identified within the netlist and ignored."){ - + SECTION("Test case where non router blocks are correctly identified within the netlist and ignored.") { // add some I/O blocks which are not compatible with a physical noc router tile // create names for some io blocks From d16c5dbb99a9ae04b6735107399c244bb2707237 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Mon, 25 Jul 2022 15:47:54 -0400 Subject: [PATCH 121/128] cleaned up the check_if_cluster_block_has_traffic_flows function within the NocTrafficFlows class to be simpler --- vpr/src/noc/noc_traffic_flows.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/vpr/src/noc/noc_traffic_flows.cpp b/vpr/src/noc/noc_traffic_flows.cpp index b4e7b685eda..3fdc3d1b494 100644 --- a/vpr/src/noc/noc_traffic_flows.cpp +++ b/vpr/src/noc/noc_traffic_flows.cpp @@ -72,15 +72,8 @@ void NocTrafficFlows::clear_traffic_flows(void) { bool NocTrafficFlows::check_if_cluster_block_has_traffic_flows(ClusterBlockId block_id) { auto traffic_flows = get_traffic_flows_associated_to_router_block(block_id); - bool result = false; - - // Check to see if any traffic flows were found that are associated to the current cluster block - if (traffic_flows != nullptr) { - // current cluster is a router block that has traffic flows it is a part of. So indicate this to the user. - result = true; - } - - return result; + // indicate whether a vector of traffic flows were found that are associated to the curre cluster block + return (traffic_flows != nullptr); } // private functions used internally From ad0bebf74514f17993e27e4274fbb42489d2ad92 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 26 Jul 2022 00:46:37 -0400 Subject: [PATCH 122/128] broke down an error that reported when the src and destination router module namesof a traffic flow were invalid into two seperate errors which reported an error when either the src or destination router module names were invalid --- vpr/src/noc/read_xml_noc_traffic_flows_file.cpp | 15 ++++++++++----- vpr/test/test_read_xml_noc_traffic_flows_file.cpp | 10 ++++++++-- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index 4600b7974fa..e80f07ff215 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -115,11 +115,16 @@ void process_single_flow(pugi::xml_node single_flow_tag, const pugiutil::loc_dat } void verify_traffic_flow_router_modules(std::string source_router_name, std::string sink_router_name, pugi::xml_node single_flow_tag, const pugiutil::loc_data& loc_data) { - // check that the router module names were legal - if ((source_router_name == "") || (sink_router_name == "")) { - vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "Invalid names for the source and sink NoC router modules."); - } // check if the source and sink routers have the same name - else if (source_router_name == sink_router_name) { + // check that the source router module name is not empty + if (source_router_name == "") { + vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "Invalid name for the source NoC router module."); + } + // check that the sink router module name is not empty + if (sink_router_name == "") { + vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "Invalid name for the sink NoC router module."); + } + // check if the source and sink routers have the same name + if (source_router_name == sink_router_name) { // Cannot have the source and sink routers have the same name (they need to be different). A flow cant go to a single router. vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "Source and sink NoC routers cannot be the same modules."); } diff --git a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp index 7109f7a5ccd..0c0cf31d439 100644 --- a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp +++ b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp @@ -36,11 +36,17 @@ TEST_CASE("test_verify_traffic_flow_router_modules", "[vpr_noc_traffic_flows_par pugi::xml_node test; pugiutil::loc_data test_location; - SECTION("Test case where atleast one of the input strings for the source and destination router module name is empty") { + SECTION("Test case where input string for the source router module name is empty") { std::string src_router_name = ""; std::string dst_router_name = "test"; - REQUIRE_THROWS_WITH(verify_traffic_flow_router_modules(src_router_name, dst_router_name, test, test_location), "Invalid names for the source and sink NoC router modules."); + REQUIRE_THROWS_WITH(verify_traffic_flow_router_modules(src_router_name, dst_router_name, test, test_location), "Invalid name for the source NoC router module."); + } + SECTION("Test case where input string for the sink router module name is empty") { + std::string src_router_name = "test"; + std::string dst_router_name = ""; + + REQUIRE_THROWS_WITH(verify_traffic_flow_router_modules(src_router_name, dst_router_name, test, test_location), "Invalid name for the sink NoC router module."); } SECTION("Test case where the router module names for both the source and destination routers are the same") { std::string src_router_name = "same_router"; From f11ed2d52f733f5b8d155117416871e4b517da1f Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 26 Jul 2022 00:53:45 -0400 Subject: [PATCH 123/128] added an assertion to check if the NoC has any physical routers, this was done since a function in read_xml_noc_traffic_flows_file.cpp requires a single physical NoC router to determine its physical type. By having this assertion, we can prevent an invalid memory reads --- vpr/src/noc/read_xml_noc_traffic_flows_file.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index e80f07ff215..9ca535f2210 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -183,6 +183,9 @@ t_physical_tile_type_ptr get_physical_type_of_noc_router_tile(const DeviceContex // assuming that all routers have the same physical type, so we are just using the physical type of the first router stored within the NoC auto physical_noc_router = noc_ctx.noc_model.get_noc_routers().begin(); + // Cannot gurantee that there are any physical routers within the NoC, so check if the NoC has any routers, if it doesn't then throw an error + VTR_ASSERT(physical_noc_router != noc_ctx.noc_model.get_noc_routers().end()); + //Using the routers grid position go to the device and identify the physical type of the tile located there. return device_ctx.grid[physical_noc_router->get_router_grid_position_x()][physical_noc_router->get_router_grid_position_y()].type; } From 9cbcf33f9dcb30709f9a27e4b270081649dbdc76 Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 26 Jul 2022 01:16:52 -0400 Subject: [PATCH 124/128] Changed the get_cluster_blocks_compatible_with_noc_router_tiles function to return the vector of founds cluster blocks ids instead of modifying a reference vector that was originally passed in as a parameter --- vpr/src/noc/read_xml_noc_traffic_flows_file.cpp | 10 ++++++---- vpr/src/noc/read_xml_noc_traffic_flows_file.h | 11 ++++------- vpr/test/test_read_xml_noc_traffic_flows_file.cpp | 12 ++++-------- 3 files changed, 14 insertions(+), 19 deletions(-) diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index 9ca535f2210..36795f77712 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -28,8 +28,7 @@ void read_xml_noc_traffic_flows_file(const char* noc_flows_file) { * time consuming, so instead we can compare to only blocks that are * compatible to physical NoC router tiles. */ - std::vector cluster_blocks_compatible_with_noc_router_tiles; - get_cluster_blocks_compatible_with_noc_router_tiles(cluster_ctx, noc_router_tile_type, cluster_blocks_compatible_with_noc_router_tiles); + std::vector cluster_blocks_compatible_with_noc_router_tiles = get_cluster_blocks_compatible_with_noc_router_tiles(cluster_ctx, noc_router_tile_type); /* variabled used when parsing the file. * Stores xml related information while parsing the file, such as current @@ -225,10 +224,13 @@ bool check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& no return result; } -void get_cluster_blocks_compatible_with_noc_router_tiles(const ClusteringContext& cluster_ctx, t_physical_tile_type_ptr noc_router_tile_type, std::vector& cluster_blocks_compatible_with_noc_router_tiles) { +std::vector get_cluster_blocks_compatible_with_noc_router_tiles(const ClusteringContext& cluster_ctx, t_physical_tile_type_ptr noc_router_tile_type) { // get the ids of all cluster blocks in the netlist auto cluster_netlist_blocks = cluster_ctx.clb_nlist.blocks(); + // vector to store all the cluster blocks ids that can be placed within a physical NoC router tile on the FPGA + std::vector cluster_blocks_compatible_with_noc_router_tiles; + for (auto cluster_block_id = cluster_netlist_blocks.begin(); cluster_block_id != cluster_netlist_blocks.end(); cluster_block_id++) { // get the logical type of the block t_logical_block_type_ptr cluster_block_type = cluster_ctx.clb_nlist.block_type(*cluster_block_id); @@ -240,5 +242,5 @@ void get_cluster_blocks_compatible_with_noc_router_tiles(const ClusteringContext } } - return; + return cluster_blocks_compatible_with_noc_router_tiles; } \ No newline at end of file diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.h b/vpr/src/noc/read_xml_noc_traffic_flows_file.h index 359b2d82c31..9e6e4a029e9 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.h +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.h @@ -199,13 +199,10 @@ bool check_that_all_router_blocks_have_an_associated_traffic_flow(NocContext& no * @param noc_router_tile_type The physical type of a Noc router tile in the * FPGA. Used to check if the router block is * compatible with a router tile. - * @param cluster_blocks_compatible_with_noc_router_tiles A vector of cluster - * blocks in the netlist that are - * compatible with a noc router tile. - * The cluster blocks in the netlist - * are added to this vector in this - * function. + * @return std::vector The cluster block ids of the + * clusters within the netlist that + * are compatible with a NoC router tile. */ -void get_cluster_blocks_compatible_with_noc_router_tiles(const ClusteringContext& cluster_ctx, t_physical_tile_type_ptr noc_router_tile_type, std::vector& cluster_blocks_compatible_with_noc_router_tiles); +std::vector get_cluster_blocks_compatible_with_noc_router_tiles(const ClusteringContext& cluster_ctx, t_physical_tile_type_ptr noc_router_tile_type); #endif \ No newline at end of file diff --git a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp index 0c0cf31d439..d8556ead715 100644 --- a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp +++ b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp @@ -483,10 +483,8 @@ TEST_CASE("test_get_cluster_blocks_compatible_with_noc_router_tiles", "[vpr_noc_ golden_set_of_router_cluster_blocks_in_netlist.emplace_back(test_netlist->create_block(router_four, nullptr, router_ref_two)); // stores the found cluster blocks in the netlist that are router blocks which are compatible with a NoC router tile - std::vector found_cluster_blocks_that_are_noc_router_compatible; - - // execute the test function - get_cluster_blocks_compatible_with_noc_router_tiles(cluster_ctx, noc_router_ref, found_cluster_blocks_that_are_noc_router_compatible); + // executing the test function here + std::vector found_cluster_blocks_that_are_noc_router_compatible = get_cluster_blocks_compatible_with_noc_router_tiles(cluster_ctx, noc_router_ref); // check that the correct number of router blocks were found REQUIRE(golden_set_of_router_cluster_blocks_in_netlist.size() == found_cluster_blocks_that_are_noc_router_compatible.size()); @@ -517,11 +515,9 @@ TEST_CASE("test_get_cluster_blocks_compatible_with_noc_router_tiles", "[vpr_noc_ test_netlist->create_block(io_four, nullptr, i_o_ref); // stores the found cluster blocks in the netlist that are router blocks which are compatible with a NoC router tile - std::vector found_cluster_blocks_that_are_noc_router_compatible; - // execute the test function - get_cluster_blocks_compatible_with_noc_router_tiles(cluster_ctx, noc_router_ref, found_cluster_blocks_that_are_noc_router_compatible); - + std::vector found_cluster_blocks_that_are_noc_router_compatible = get_cluster_blocks_compatible_with_noc_router_tiles(cluster_ctx, noc_router_ref); + // since there were no router blocks in this netlist, check that the test found function 0 blocks that were compatible with a noc router tile REQUIRE(found_cluster_blocks_that_are_noc_router_compatible.size() == 0); From 9f6ca9f7a45ee8a6ce71e0307b233952423a6a1a Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 26 Jul 2022 01:33:06 -0400 Subject: [PATCH 125/128] changed the string parameter name within the find_block_by_name_fragment function in the both the clustered netlist and netlist calsses to help indicate how the string parameter will be used when trying to find a block within the netlist. --- vpr/src/base/clustered_netlist.cpp | 4 ++-- vpr/src/base/clustered_netlist.h | 6 +++--- vpr/src/base/netlist.h | 6 +++--- vpr/src/base/netlist.tpp | 4 ++-- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/vpr/src/base/clustered_netlist.cpp b/vpr/src/base/clustered_netlist.cpp index 73326961c14..2055d0bc6db 100644 --- a/vpr/src/base/clustered_netlist.cpp +++ b/vpr/src/base/clustered_netlist.cpp @@ -307,9 +307,9 @@ bool ClusteredNetlist::validate_net_sizes_impl(size_t num_nets) const { return true; } -ClusterBlockId ClusteredNetlist::find_block_by_name_fragment(const std::string& name, const std::vector& cluster_block_candidates) const { +ClusterBlockId ClusteredNetlist::find_block_by_name_fragment(const std::string& name_pattern, const std::vector& cluster_block_candidates) const { ClusterBlockId blk_id = ClusterBlockId::INVALID(); - std::regex name_to_match(name); + std::regex name_to_match(name_pattern); for (auto compatible_block_id = cluster_block_candidates.begin(); compatible_block_id != cluster_block_candidates.end(); compatible_block_id++) { if (std::regex_match(Netlist::block_name(*compatible_block_id), name_to_match)) { diff --git a/vpr/src/base/clustered_netlist.h b/vpr/src/base/clustered_netlist.h index 9915f7843cd..f1e913a650d 100644 --- a/vpr/src/base/clustered_netlist.h +++ b/vpr/src/base/clustered_netlist.h @@ -286,8 +286,8 @@ class ClusteredNetlist : public Netlist& cluster_block_candidates) const; + ClusterBlockId find_block_by_name_fragment(const std::string& name_pattern, const std::vector& cluster_block_candidates) const; private: //Private Members /* diff --git a/vpr/src/base/netlist.h b/vpr/src/base/netlist.h index 96dff5d7167..400245afcee 100644 --- a/vpr/src/base/netlist.h +++ b/vpr/src/base/netlist.h @@ -756,13 +756,13 @@ class Netlist { * meaning that the input is a pattern string and the pattern * is looked for ine each block name. * - * @param name A substring of a block name for which an ID needs to be - * found. + * @param name_substring A substring of a block name for which an ID needs + * to be found. * @return A cluster block id representing a unique cluster block that * matched to the input string pattern. * */ - BlockId find_block_by_name_fragment(const std::string& name) const; + BlockId find_block_by_name_fragment(const std::string& name_substring) const; /** * @brief Returns the PortId of the specifed port if it exists or PortId::INVALID() if not diff --git a/vpr/src/base/netlist.tpp b/vpr/src/base/netlist.tpp index f5ee6a18556..2773e2471c6 100644 --- a/vpr/src/base/netlist.tpp +++ b/vpr/src/base/netlist.tpp @@ -459,7 +459,7 @@ BlockId Netlist::find_block(const std::string& na } template -BlockId Netlist::find_block_by_name_fragment(const std::string& name) const { +BlockId Netlist::find_block_by_name_fragment(const std::string& name_substring) const { BlockId matching_blk_id = BlockId::INVALID(); const std::string blk_name; @@ -468,7 +468,7 @@ BlockId Netlist::find_block_by_name_fragment(cons // get the corresponding block name blk_name = &strings_[block_names_[*blk_id]]; // check whether the current block name contains the input string within it - if (blk_name.find(name) != std::string::npos) { + if (blk_name.find(name_substring) != std::string::npos) { matching_blk_id = blk_id; break; } From 7776f03acb907763d0ebf24ef017866e82e203cd Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 26 Jul 2022 01:39:24 -0400 Subject: [PATCH 126/128] improved commenting that describes the purpose of the --noc command line option in vpr --- vpr/src/base/vpr_types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index 401a8dd3873..2f08b0fdc9d 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -1271,7 +1271,7 @@ struct t_analysis_opts { // used to store NoC specific options, when supplied as an input by the user struct t_noc_opts { - bool noc; /// Date: Tue, 26 Jul 2022 01:45:10 -0400 Subject: [PATCH 127/128] formatting changes --- vpr/src/noc/read_xml_noc_traffic_flows_file.cpp | 4 ++-- vpr/test/test_read_xml_noc_traffic_flows_file.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp index 36795f77712..32b75f6ff58 100644 --- a/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -117,11 +117,11 @@ void verify_traffic_flow_router_modules(std::string source_router_name, std::str // check that the source router module name is not empty if (source_router_name == "") { vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "Invalid name for the source NoC router module."); - } + } // check that the sink router module name is not empty if (sink_router_name == "") { vpr_throw(VPR_ERROR_OTHER, loc_data.filename_c_str(), loc_data.line(single_flow_tag), "Invalid name for the sink NoC router module."); - } + } // check if the source and sink routers have the same name if (source_router_name == sink_router_name) { // Cannot have the source and sink routers have the same name (they need to be different). A flow cant go to a single router. diff --git a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp index d8556ead715..938ca0f7242 100644 --- a/vpr/test/test_read_xml_noc_traffic_flows_file.cpp +++ b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp @@ -517,7 +517,7 @@ TEST_CASE("test_get_cluster_blocks_compatible_with_noc_router_tiles", "[vpr_noc_ // stores the found cluster blocks in the netlist that are router blocks which are compatible with a NoC router tile // execute the test function std::vector found_cluster_blocks_that_are_noc_router_compatible = get_cluster_blocks_compatible_with_noc_router_tiles(cluster_ctx, noc_router_ref); - + // since there were no router blocks in this netlist, check that the test found function 0 blocks that were compatible with a noc router tile REQUIRE(found_cluster_blocks_that_are_noc_router_compatible.size() == 0); From b1f1477db2f8f528a2ac0a152af8f396577ae61c Mon Sep 17 00:00:00 2001 From: Srivatsan Srinivasan Date: Tue, 26 Jul 2022 13:51:19 -0400 Subject: [PATCH 128/128] Changed one of the section names in the NocTrafficFlows ojects echo file to be more succint and also updated the echo file format --- vpr/src/noc/noc_traffic_flows.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vpr/src/noc/noc_traffic_flows.cpp b/vpr/src/noc/noc_traffic_flows.cpp index 3fdc3d1b494..724b7d2cecb 100644 --- a/vpr/src/noc/noc_traffic_flows.cpp +++ b/vpr/src/noc/noc_traffic_flows.cpp @@ -99,14 +99,14 @@ void NocTrafficFlows::echo_noc_traffic_flows(char* file_name) { fp = vtr::fopen(file_name, "w"); // file header - fprintf(fp, "--------------------------------------------------------------\n"); + fprintf(fp, "----------------------------------------------------------------------------\n"); fprintf(fp, "NoC Traffic Flows\n"); - fprintf(fp, "--------------------------------------------------------------\n"); + fprintf(fp, "----------------------------------------------------------------------------\n"); fprintf(fp, "\n"); // print all the routers and their properties fprintf(fp, "List of NoC Traffic Flows:\n"); - fprintf(fp, "--------------------------------------------------------------\n"); + fprintf(fp, "----------------------------------------------------------------------------\n"); fprintf(fp, "\n"); int traffic_flow_id = 0; @@ -131,8 +131,8 @@ void NocTrafficFlows::echo_noc_traffic_flows(char* file_name) { // now print the router cluster ids and their associated traffic flow information for router cluster blocks // The associated traffic flows represent flows where the router block is either a source or destination router - fprintf(fp, "List of all unique router cluster blocks and their corresponding traffic flows where the router block is either a source or destination of the traffic flow:\n"); - fprintf(fp, "--------------------------------------------------------------\n"); + fprintf(fp, "List of all unique router cluster blocks and their associated traffic flows:\n"); + fprintf(fp, "----------------------------------------------------------------------------\n"); fprintf(fp, "\n"); // go through each router block cluster and print its associated traffic flows