diff --git a/libs/libarchfpga/src/read_xml_arch_file.cpp b/libs/libarchfpga/src/read_xml_arch_file.cpp index 73b6584c6ce..95481f264e4 100644 --- a/libs/libarchfpga/src/read_xml_arch_file.cpp +++ b/libs/libarchfpga/src/read_xml_arch_file.cpp @@ -4672,7 +4672,7 @@ static void processTopology(pugi::xml_node topology_tag, const pugiutil::loc_dat /** * Stores router information that includes the number of connections a router has within a given topology and also the number of times a router was declared in the arch file using the tag. * In the datastructure below, the router id is the key and the stored data is a pair, where the first element describes the number of router declarations and the second element describes the number of router connections. - * This is used only for erro checking. + * This is used only for error checking. */ std::map> routers_in_arch_info; 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..b6e5e5163b7 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,10 @@ 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.c_str()); + VTR_LOG("\n"); + + // add future options here (routing algorithm etc...) +} \ No newline at end of file diff --git a/vpr/src/base/clustered_netlist.cpp b/vpr/src/base/clustered_netlist.cpp index 146e104d340..2055d0bc6db 100644 --- a/vpr/src/base/clustered_netlist.cpp +++ b/vpr/src/base/clustered_netlist.cpp @@ -306,3 +306,17 @@ bool ClusteredNetlist::validate_net_sizes_impl(size_t num_nets) const { } return true; } + +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_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)) { + 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 144c30dc095..f1e913a650d 100644 --- a/vpr/src/base/clustered_netlist.h +++ b/vpr/src/base/clustered_netlist.h @@ -228,6 +228,77 @@ class ClusteredNetlist : public Netlist& cluster_block_candidates) const; + private: //Private Members /* * Netlist compression/optimization 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/base/netlist.h b/vpr/src/base/netlist.h index 21dff5cf5ef..400245afcee 100644 --- a/vpr/src/base/netlist.h +++ b/vpr/src/base/netlist.h @@ -727,6 +727,43 @@ class Netlist { */ BlockId find_block(const std::string& name) const; + /** + * @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_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_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 2fd483ee7a3..2773e2471c6 100644 --- a/vpr/src/base/netlist.tpp +++ b/vpr/src/base/netlist.tpp @@ -458,6 +458,24 @@ BlockId Netlist::find_block(const std::string& na } } +template +BlockId Netlist::find_block_by_name_fragment(const std::string& name_substring) 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_substring) != 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)); diff --git a/vpr/src/base/read_options.cpp b/vpr/src/base/read_options.cpp index 21ad69e96c2..50917547e96 100644 --- a/vpr/src/base/read_options.cpp +++ b/vpr/src/base/read_options.cpp @@ -2622,6 +2622,13 @@ 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_flows_file, "--noc_flows_file") + .help( + "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); + return parser; } @@ -2803,7 +2810,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) { @@ -2826,5 +2833,19 @@ 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"); + } + 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/setup_noc.cpp b/vpr/src/base/setup_noc.cpp index 3657df22927..3bc36722184 100644 --- a/vpr/src/base/setup_noc.cpp +++ b/vpr/src/base/setup_noc.cpp @@ -1,4 +1,3 @@ - #include #include diff --git a/vpr/src/base/setup_noc.h b/vpr/src/base/setup_noc.h index 565fe46653f..2f96268f787 100644 --- a/vpr/src/base/setup_noc.h +++ b/vpr/src/base/setup_noc.h @@ -1,13 +1,6 @@ #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. - * - */ - /** * @file * @brief This is the setup_noc header file. The main purpose of diff --git a/vpr/src/base/vpr_api.cpp b/vpr/src/base/vpr_api.cpp index a06a155e038..116685e5d93 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" @@ -515,9 +516,11 @@ 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 + read_xml_noc_traffic_flows_file(vpr_setup.NocOpts.noc_flows_file.c_str()); #ifndef NO_GRAPHICS // setup the graphics diff --git a/vpr/src/base/vpr_context.h b/vpr/src/base/vpr_context.h index ca4ed41bdee..4343cdbba60 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 @@ -427,6 +428,16 @@ struct NocContext : public Context { * The NoC model is created once from the architecture file description. */ NocStorage noc_model; + + /** + * @brief Stores all the communication happening between routers in the NoC + * + * 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. + */ + NocTrafficFlows noc_traffic_flows_storage; }; /** diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index 1f0db609fa4..2f08b0fdc9d 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -1271,7 +1271,8 @@ struct t_analysis_opts { // used to store NoC specific options, when supplied as an input by the user struct t_noc_opts { - bool noc; /// NocRouterId; typedef vtr::StrongId NocLinkId; +// 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 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 diff --git a/vpr/src/noc/noc_traffic_flows.cpp b/vpr/src/noc/noc_traffic_flows.cpp new file mode 100644 index 00000000000..724b7d2cecb --- /dev/null +++ b/vpr/src/noc/noc_traffic_flows.cpp @@ -0,0 +1,159 @@ + +#include "noc_traffic_flows.h" +#include "vpr_error.h" + +// 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; +} + +// getters for the traffic flows + +const t_noc_traffic_flow& NocTrafficFlows::get_single_noc_traffic_flow(NocTrafficFlowId traffic_flow_id) const { + 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* associated_traffic_flows_ref = nullptr; + + // 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 != traffic_flows_associated_to_router_blocks.end()) { + // 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); + } + + return associated_traffic_flows_ref; +} + +int NocTrafficFlows::get_number_of_routers_used_in_traffic_flows(void) { + return traffic_flows_associated_to_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) { + 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); + + //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); + + // 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); + + return; +} + +// 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; +} + +void NocTrafficFlows::clear_traffic_flows(void) { + // delete any information from internal datastructures + noc_traffic_flows.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_has_traffic_flows(ClusterBlockId block_id) { + auto traffic_flows = get_traffic_flows_associated_to_router_block(block_id); + + // 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 + +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 = traffic_flows_associated_to_router_blocks.find(associated_router_id); + + // check if a vector asssociated traffic flows exists + 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 + 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); + } + + 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 = 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()); + 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"); + + // update the id for the next traffic flow + traffic_flow_id++; + } + + // 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 associated traffic flows:\n"); + fprintf(fp, "----------------------------------------------------------------------------\n"); + fprintf(fp, "\n"); + + // go through each router block cluster and print its associated traffic flows + // we only print out the traffic flow ids + 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 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 to the next cluster associated traffic flows information + fprintf(fp, "\n\n"); + } + + vtr::fclose(fp); + + 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 new file mode 100644 index 00000000000..1d15ab9c2f9 --- /dev/null +++ b/vpr/src/noc/noc_traffic_flows.h @@ -0,0 +1,243 @@ +#ifndef NOC_TRAFFIC_FLOWS_H +#define NOC_TRAFFIC_FLOWS_H + +/** + * @file + * @brief This file defines the NocTrafficFlows class, which contains all + * communication betwee routers in the NoC. + * + * Overview + * ======== + * 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 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 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 (logical routers) in the + * design. + * + * This class 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. + * + */ +#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" +#include "vtr_assert.h" + +/** + * @brief Describes a traffic flow within the NoC, which is the communication + * 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 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 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 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, in seconds. This parameter will be used to evaluate a router 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) {} +}; + +class NocTrafficFlows { + private: + /** 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 + * 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> traffic_flows_associated_to_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 + + /** + * @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); + + 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) 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 router_block_id A unique identifier that represents the + * a router block in the clustered netlist. This router block will + * 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 or sink + * in the flow. + */ + const std::vector* get_traffic_flows_associated_to_router_block(ClusterBlockId router_block_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 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 + * 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); + + //utility functions + + /** + * @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); + + /** + * @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 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 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_has_traffic_flows(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 new file mode 100644 index 00000000000..32b75f6ff58 --- /dev/null +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.cpp @@ -0,0 +1,246 @@ + +#include "read_xml_noc_traffic_flows_file.h" + +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) { + 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); + } + + const ClusteringContext& cluster_ctx = g_vpr_ctx.clustering(); + + // get the modifiable NoC as we will be adding traffic flows to it here + NocContext& noc_ctx = g_vpr_ctx.mutable_noc(); + + const DeviceContext& device_ctx = g_vpr_ctx.device(); + + 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); + + /* 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; + + // 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); + + // 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()) { + // current tag is a valid "flow" so process it + 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 + + 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 + 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(); + + // 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; +} + +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; + + // 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 + // 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 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 + 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); + 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); + + 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, 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) { + // 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."); + } + + 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) { + // check that the bandwidth and max latency are positive values + 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, const std::vector& cluster_blocks_compatible_with_noc_router_tiles) { + ClusterBlockId router_module_id = ClusterBlockId::INVALID(); + + // 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) { + // 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 + 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) { + // 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 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. + */ + 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; +} + +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(); + + // 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; +} + +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(); + + 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 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) { + 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; +} + +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); + + // 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 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 new file mode 100644 index 00000000000..9e6e4a029e9 --- /dev/null +++ b/vpr/src/noc/read_xml_noc_traffic_flows_file.h @@ -0,0 +1,208 @@ +#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" +#include "globals.h" + +#include "vtr_assert.h" +#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" + +#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(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. + * 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 + * 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, const std::vector& cluster_blocks_compatible_with_noc_router_tiles); + +/** + * @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. 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. + * 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); + +/** + * @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. + * 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); + +/** + * @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. + * 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. + * @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, const std::vector& cluster_blocks_compatible_with_noc_router_tiles); + +/** + * @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. + * 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. + * @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 + * 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 + * 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. + * @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. + */ +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 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. + * @return std::vector The cluster block ids of the + * clusters within the netlist that + * are compatible with a NoC router tile. + */ +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/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 diff --git a/vpr/test/test_clustered_netlist.cpp b/vpr/test/test_clustered_netlist.cpp new file mode 100644 index 00000000000..d05826070ea --- /dev/null +++ b/vpr/test/test_clustered_netlist.cpp @@ -0,0 +1,150 @@ +#include "catch2/catch_test_macros.hpp" +#include "catch2/matchers/catch_matchers_all.hpp" + +#include "clustered_netlist.h" + +#include +#include +#include + +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"; + + // datastructure to store all the cluster block IDs of the noc router logical block type clusters + std::vector 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)); + 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)); + + // 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_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); + } + 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)); + + // 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_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); + } + 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)); + + // 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_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 + + // 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); + } +} +} // 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 new file mode 100644 index 00000000000..15f8c758144 --- /dev/null +++ b/vpr/test/test_noc_traffic_flows.cpp @@ -0,0 +1,135 @@ +#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_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++) { + // 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 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); + } + } + + // 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_has_traffic_flows(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); + } + + // 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++) { + 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(); + + // 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); + + // 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); + + // 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]); + } + } + + // 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_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) + 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_router_block(invalid_block) == nullptr); + } +} +} // 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 new file mode 100644 index 00000000000..938ca0f7242 --- /dev/null +++ b/vpr/test/test_read_xml_noc_traffic_flows_file.cpp @@ -0,0 +1,528 @@ +#include "catch2/catch_test_macros.hpp" +#include "catch2/matchers/catch_matchers_all.hpp" + +#include "read_xml_noc_traffic_flows_file.h" + +#include + +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(); +} + +/* + * 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 + pugi::xml_node test; + pugiutil::loc_data test_location; + + 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 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"; + 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 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_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; + + // 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; + + // 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); + + /* 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; + + // 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, 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)); + + // 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"; + 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, 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)); + + // 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"; + + 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_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); + + // 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 + 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, 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)); + + // 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"; + + 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_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(); + } +} +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; + + // 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; + + 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, 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, 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]") { + // 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; + + //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, 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"; + + 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); + + // 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 + 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); + + // 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_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 + // 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()); + + // 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 + // 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); + + // 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 diff --git a/vtr_flow/benchmarks/noc/Readme.txt b/vtr_flow/benchmarks/noc/Readme.txt new file mode 100644 index 00000000000..f9117406c87 --- /dev/null +++ b/vtr_flow/benchmarks/noc/Readme.txt @@ -0,0 +1,46 @@ +################################################### +# 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 CAD 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 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 CAD 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..494d7519ca8 --- /dev/null +++ b/vtr_flow/benchmarks/noc/Test_Designs/test_design_for_noc_traffic_flows_feature/multiple_noc_routers.flows @@ -0,0 +1,7 @@ + + + + + + +