From 167778cf57bf0f486dd6578ca82fbe3e75baee26 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 27 Sep 2019 16:05:47 -0600 Subject: [PATCH] refactoring MUX Verilog instanciation in Switch block --- vpr7_x2p/vpr/SRC/device/mux_graph.cpp | 60 ++++++++++++++- vpr7_x2p/vpr/SRC/device/mux_graph.h | 11 +++ vpr7_x2p/vpr/SRC/device/mux_utils.cpp | 11 ++- .../SRC/fpga_x2p/verilog/verilog_routing.c | 76 ++++++++++++++----- 4 files changed, 133 insertions(+), 25 deletions(-) diff --git a/vpr7_x2p/vpr/SRC/device/mux_graph.cpp b/vpr7_x2p/vpr/SRC/device/mux_graph.cpp index 91105ddbf..608ffa4b5 100644 --- a/vpr7_x2p/vpr/SRC/device/mux_graph.cpp +++ b/vpr7_x2p/vpr/SRC/device/mux_graph.cpp @@ -65,6 +65,14 @@ MuxGraph::mem_range MuxGraph::memories() const { return vtr::make_range(mem_ids_.begin(), mem_ids_.end()); } +std::vector MuxGraph::levels() const { + std::vector graph_levels; + for (size_t lvl = 0; lvl < num_levels(); ++lvl) { + graph_levels.push_back(lvl); + } + return graph_levels; +} + /************************************************** * Public Accessors: Data query *************************************************/ @@ -158,6 +166,14 @@ size_t MuxGraph::num_memory_bits() const { return mem_ids_.size(); } +/* Find the number of SRAMs at a level in the MUX graph */ +size_t MuxGraph::num_memory_bits_at_level(const size_t& level) const { + /* need to check if the graph is valid or not */ + VTR_ASSERT_SAFE(valid_level(level)); + VTR_ASSERT_SAFE(valid_mux_graph()); + return mem_lookup_[level].size(); +} + /* Find the number of nodes at a given level in the MUX graph */ size_t MuxGraph::num_nodes_at_level(const size_t& level) const { /* validate the level numbers */ @@ -310,6 +326,7 @@ MuxGraph MuxGraph::subgraph(const MuxNodeId& root_node) const { } /* Not found, we add a memory bit and record in the mem-to-mem map */ MuxMemId mem_subgraph = mux_graph.add_mem(); + mux_graph.set_mem_level(mem_subgraph, 0); mem2mem_map[mem_origin] = mem_subgraph; /* configure the edge */ mux_graph.edge_mem_ids_[edge2edge_map[edge_origin]] = mem_subgraph; @@ -317,6 +334,7 @@ MuxGraph MuxGraph::subgraph(const MuxNodeId& root_node) const { /* Since the graph is finalized, it is time to build the fast look-up */ mux_graph.build_node_lookup(); + mux_graph.build_mem_lookup(); return mux_graph; } @@ -519,11 +537,20 @@ MuxMemId MuxGraph::add_mem() { MuxMemId mem = MuxMemId(mem_ids_.size()); /* Push to the node list */ mem_ids_.push_back(mem); + mem_levels_.push_back(size_t(-1)); /* Resize the other node-related vectors */ return mem; } +/* Configure the level of a memory */ +void MuxGraph::set_mem_level(const MuxMemId& mem, const size_t& level) { + /* Make sure we have valid edge and mem */ + VTR_ASSERT( valid_mem_id(mem) ); + + mem_levels_[mem] = level; +} + /* Link an edge to a memory bit */ void MuxGraph::set_edge_mem_id(const MuxEdgeId& edge, const MuxMemId& mem) { /* Make sure we have valid edge and mem */ @@ -593,8 +620,11 @@ void MuxGraph::build_multilevel_mux_graph(const size_t& mux_size, num_mems_per_level = 1; } /* Number of memory bits is definite, add them */ - for (size_t i = 0; i < num_mems_per_level * num_levels; ++i) { - add_mem(); + for (size_t ilvl = 0; ilvl < num_levels; ++ilvl) { + for (size_t imem = 0; imem < num_mems_per_level; ++imem) { + MuxMemId mem = add_mem(); + mem_levels_[mem] = ilvl; + } } /* Create a fast node lookup locally. @@ -747,6 +777,7 @@ void MuxGraph::build_onelevel_mux_graph(const size_t& mux_size, /* Create a memory bit*/ MuxMemId mem = add_mem(); + mem_levels_[mem] = 0; /* Link the edge to a memory bit */ set_edge_mem_id(edge, mem); } @@ -863,6 +894,7 @@ void MuxGraph::build_mux_graph(const CircuitLibrary& circuit_lib, /* Since the graph is finalized, it is time to build the fast look-up */ build_node_lookup(); + build_mem_lookup(); /* For fracturable LUTs, we need to add more outputs to the MUX graph */ if ( (SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model)) @@ -895,10 +927,34 @@ void MuxGraph::build_node_lookup() { } } +/* Build fast mem lookup */ +void MuxGraph::build_mem_lookup() { + /* Invalidate the mem lookup if necessary */ + invalidate_mem_lookup(); + + /* Find the maximum number of levels */ + size_t num_levels = 0; + for (auto mem : memories()) { + num_levels = std::max((int)mem_levels_[mem], (int)num_levels); + } + + /* Resize mem_lookup */ + mem_lookup_.resize(num_levels + 1); + for (auto mem : memories()) { + /* Categorize mem nodes into mem_lookup */ + mem_lookup_[mem_levels_[mem]].push_back(mem); + } +} + /* Invalidate (empty) the node fast lookup*/ void MuxGraph::invalidate_node_lookup() { node_lookup_.clear(); } + +/* Invalidate (empty) the mem fast lookup*/ +void MuxGraph::invalidate_mem_lookup() { + mem_lookup_.clear(); +} /************************************************** * Private validators diff --git a/vpr7_x2p/vpr/SRC/device/mux_graph.h b/vpr7_x2p/vpr/SRC/device/mux_graph.h index 856c7e0b1..ddb80e6f4 100644 --- a/vpr7_x2p/vpr/SRC/device/mux_graph.h +++ b/vpr7_x2p/vpr/SRC/device/mux_graph.h @@ -62,6 +62,7 @@ class MuxGraph { std::vector non_input_nodes() const; edge_range edges() const; mem_range memories() const; + std::vector levels() const; public: /* Public accessors: Data query */ /* Find the number of inputs in the MUX graph */ size_t num_inputs() const; @@ -76,6 +77,8 @@ class MuxGraph { size_t num_node_levels() const; /* Find the number of SRAMs in the MUX graph */ size_t num_memory_bits() const; + /* Find the number of SRAMs at a level in the MUX graph */ + size_t num_memory_bits_at_level(const size_t& level) const; /* Find the number of nodes at a given level in the MUX graph */ size_t num_nodes_at_level(const size_t& level) const; /* Find the level of a node */ @@ -112,6 +115,8 @@ class MuxGraph { MuxEdgeId add_edge(const MuxNodeId& from_node, const MuxNodeId& to_node); /* Add a memory bit to the MuxGraph */ MuxMemId add_mem(); + /* Configure the level of a memory */ + void set_mem_level(const MuxMemId& mem, const size_t& level); /* Link an edge to a mem */ void set_edge_mem_id(const MuxEdgeId& edge, const MuxMemId& mem); private: /* Private mutators : graph builders */ @@ -130,6 +135,8 @@ class MuxGraph { const CircuitModelId& circuit_model); /* Build fast node lookup */ void build_node_lookup(); + /* Build fast mem lookup */ + void build_mem_lookup(); private: /* Private validators */ /* valid ids */ bool valid_node_id(const MuxNodeId& node) const; @@ -141,6 +148,7 @@ class MuxGraph { /* validate/invalidate node lookup */ bool valid_node_lookup() const; void invalidate_node_lookup(); + void invalidate_mem_lookup(); /* validate graph */ bool valid_mux_graph() const; private: /* Internal data */ @@ -161,10 +169,13 @@ class MuxGraph { vtr::vector edge_inv_mem_; /* if the edge is controlled by an inverted output of a memory bit */ vtr::vector mem_ids_; /* ids of configuration memories */ + vtr::vector mem_levels_; /* ids of configuration memories */ /* fast look-up */ typedef std::vector>> NodeLookup; mutable NodeLookup node_lookup_; /* [num_levels][num_types][num_nodes_per_level] */ + typedef std::vector> MemLookup; + mutable MemLookup mem_lookup_; /* [num_levels][num_mems_per_level] */ }; #endif diff --git a/vpr7_x2p/vpr/SRC/device/mux_utils.cpp b/vpr7_x2p/vpr/SRC/device/mux_utils.cpp index 6a6d169a9..53e71f1f8 100644 --- a/vpr7_x2p/vpr/SRC/device/mux_utils.cpp +++ b/vpr7_x2p/vpr/SRC/device/mux_utils.cpp @@ -283,6 +283,7 @@ size_t find_cmos_mux_num_config_bits(const CircuitLibrary& circuit_lib, const MuxGraph& mux_graph, const e_sram_orgz& sram_orgz_type) { size_t num_config_bits = 0; + switch (sram_orgz_type) { case SPICE_SRAM_MEMORY_BANK: case SPICE_SRAM_SCAN_CHAIN: @@ -296,10 +297,16 @@ size_t find_cmos_mux_num_config_bits(const CircuitLibrary& circuit_lib, exit(1); } - if (true == circuit_lib.mux_use_local_encoder(mux_model)) { - num_config_bits = find_mux_local_decoder_addr_size(mux_graph.num_memory_bits()); + if (false == circuit_lib.mux_use_local_encoder(mux_model)) { + return num_config_bits; } + num_config_bits = 0; + /* Multiplexer local encoders are applied to memory bits at each stage */ + for (const auto& lvl : mux_graph.levels()) { + num_config_bits += find_mux_local_decoder_addr_size(mux_graph.num_memory_bits_at_level(lvl)); + } + return num_config_bits; } diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c index 5e0d99f9c..19a006e41 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -2328,7 +2329,7 @@ void print_verilog_unique_switch_box_mux(ModuleManager& module_manager, t_rr_node* cur_rr_node, const std::vector& drive_rr_nodes, const size_t& switch_index, - const bool& is_explicit_mapping) { + const bool& use_explicit_mapping) { /* Check the file handler*/ check_file_handler(fp); @@ -2341,11 +2342,9 @@ void print_verilog_unique_switch_box_mux(ModuleManager& module_manager, /* Find the input size of the implementation of a routing multiplexer */ size_t datapath_mux_size = drive_rr_nodes.size(); - size_t impl_mux_size = find_mux_implementation_num_inputs(circuit_lib, mux_model, datapath_mux_size); - VTR_ASSERT(true == valid_mux_implementation_num_inputs(impl_mux_size)); /* Get the multiplexing graph from the Mux Library */ - MuxId mux_id = mux_lib.mux_graph(mux_model, impl_mux_size); + MuxId mux_id = mux_lib.mux_graph(mux_model, datapath_mux_size); const MuxGraph& mux_graph = mux_lib.mux_graph(mux_id); /* Find the module name of the multiplexer and try to find it in the module manager */ @@ -2365,19 +2364,12 @@ void print_verilog_unique_switch_box_mux(ModuleManager& module_manager, inbus_port.set_name(generate_mux_input_bus_port_name(circuit_lib, mux_model, datapath_mux_size, mux_instance_id)); inbus_port.set_width(datapath_mux_size); - /* Create the path of the input of multiplexer in the hierarchy - * TODO: this MUST be deprecated later because module manager is created to handle these problems!!! - */ - std::string mux_input_hie_path = std::string(rr_sb.gen_sb_verilog_instance_name()) + std::string("/") - + mux_module_name + std::string("_") - + std::to_string(mux_instance_id) + std::string("_/in"); - cur_rr_node->name_mux = my_strdup(mux_input_hie_path.c_str()); - /* Generate input ports that are wired to the input bus of the routing multiplexer */ std::vector mux_input_ports = generate_switch_block_input_ports(rr_sb, drive_rr_nodes); /* Connect input ports to bus */ - print_verilog_comment(fp, std::string("----- A local bus wire for multiplexer inputs -----")); + print_verilog_comment(fp, std::string("----- BEGIN A local bus wire for multiplexer inputs -----")); fp << generate_verilog_local_wire(inbus_port, mux_input_ports) << std::endl; + print_verilog_comment(fp, std::string("----- END A local bus wire for multiplexer inputs -----")); fp << std::endl; /* Find the number of reserved configuration bits for the routing multiplexer */ @@ -2387,32 +2379,66 @@ void print_verilog_unique_switch_box_mux(ModuleManager& module_manager, size_t mux_num_config_bits = find_mux_num_config_bits(circuit_lib, mux_model, mux_graph, cur_sram_orgz_info->type); /* Print the configuration bus for the routing multiplexers */ - print_verilog_comment(fp, std::string("----- Local wires to group configuration ports -----")); + print_verilog_comment(fp, std::string("----- BEGIN Local wires to group configuration ports -----")); print_verilog_mux_config_bus(fp, circuit_lib, mux_model, cur_sram_orgz_info->type, datapath_mux_size, mux_instance_id, mux_num_reserved_config_bits, mux_num_config_bits); + print_verilog_comment(fp, std::string("----- END Local wires to group configuration ports -----")); fp << std::endl; /* Dump ports visible only during formal verification */ - print_verilog_comment(fp, std::string("----- Local wires used in only formal verification purpose -----")); + print_verilog_comment(fp, std::string("----- BEGIN Local wires used in only formal verification purpose -----")); print_verilog_preprocessing_flag(fp, std::string(verilog_formal_verification_preproc_flag)); /* Print the SRAM configuration ports for formal verification */ + /* TODO: align with the port width of formal verification port of SB module */ print_verilog_formal_verification_mux_sram_ports_wiring(fp, circuit_lib, mux_model, datapath_mux_size, mux_instance_id, mux_num_config_bits); print_verilog_endif(fp); + print_verilog_comment(fp, std::string("----- END Local wires used in only formal verification purpose -----")); fp << std::endl; - /* TODO: Instanciate the MUX Module */ - /* TODO: create port-to-port map */ + /* Instanciate the MUX Module */ + /* Create port-to-port map */ + std::map mux_port2port_name_map; + /* Link input bus port to Switch Block inputs */ + std::vector mux_model_input_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_INPUT, true); + VTR_ASSERT(1 == mux_model_input_ports.size()); + /* Use the port name convention in the circuit library */ + mux_port2port_name_map[circuit_lib.port_lib_name(mux_model_input_ports[0])] = inbus_port; + /* Link output port to Switch Block outputs */ + std::vector mux_model_output_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_OUTPUT, true); + VTR_ASSERT(1 == mux_model_output_ports.size()); + /* Use the port name convention in the circuit library */ + mux_port2port_name_map[circuit_lib.port_lib_name(mux_model_output_ports[0])] = generate_verilog_unique_switch_box_chan_port(rr_sb, chan_side, cur_rr_node, OUT_PORT); + /* Link SRAM port to different configuraton port for the routing multiplexer * Different design technology requires different configuration bus! - dump_verilog_mux_config_bus_ports(fp, verilog_model, cur_sram_orgz_info, - mux_size, cur_num_sram, num_mux_reserved_conf_bits, - num_mux_conf_bits, is_explicit_mapping); */ - /* TODO: Print an instance of the MUX Module */ + std::vector mux_model_sram_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_SRAM, true); + VTR_ASSERT( 1 == mux_model_sram_ports.size() ); + /* For the regular SRAM port, module port use the same name */ + std::string mux_module_sram_port_name = circuit_lib.port_lib_name(mux_model_sram_ports[0]); + BasicPort mux_config_port(generate_mux_sram_port_name(circuit_lib, mux_model, datapath_mux_size, mux_instance_id, SPICE_MODEL_PORT_INPUT), + mux_num_config_bits); + mux_port2port_name_map[mux_module_sram_port_name] = mux_config_port; + + /* For the inverted SRAM port */ + std::string mux_module_sram_inv_port_name = circuit_lib.port_lib_name(mux_model_sram_ports[0]) + std::string("_inv"); + BasicPort mux_config_inv_port(generate_mux_sram_port_name(circuit_lib, mux_model, datapath_mux_size, mux_instance_id, SPICE_MODEL_PORT_OUTPUT), + mux_num_config_bits); + mux_port2port_name_map[mux_module_sram_inv_port_name] = mux_config_inv_port; + + /* Print an instance of the MUX Module */ + print_verilog_comment(fp, std::string("----- BEGIN Instanciation of a routing multiplexer -----")); + print_verilog_module_instance(fp, module_manager, sb_module, mux_module, mux_port2port_name_map, use_explicit_mapping); + print_verilog_comment(fp, std::string("----- END Instanciation of a routing multiplexer -----")); + fp << std::endl; + /* IMPORTANT: this update MUST be called after the instance outputting!!!! + * update the module manager with the relationship between the parent and child modules + */ + module_manager.add_child_module(sb_module, mux_module); /* TODO: Instanciate memory modules */ switch (circuit_lib.design_tech_type(mux_model)) { @@ -2443,6 +2469,14 @@ void print_verilog_unique_switch_box_mux(ModuleManager& module_manager, "(File:%s,[LINE%d])Invalid design technology for circuit model (%s)!\n", __FILE__, __LINE__, circuit_lib.model_name(mux_model).c_str()); } + + /* Create the path of the input of multiplexer in the hierarchy + * TODO: this MUST be deprecated later because module manager is created to handle these problems!!! + */ + std::string mux_input_hie_path = std::string(rr_sb.gen_sb_verilog_instance_name()) + std::string("/") + + mux_module_name + std::string("_") + + std::to_string(mux_instance_id) + std::string("_/in"); + cur_rr_node->name_mux = my_strdup(mux_input_hie_path.c_str()); }