diff --git a/openfpga/src/base/openfpga_naming.cpp b/openfpga/src/base/openfpga_naming.cpp index f6f64d39a..d2e41f549 100644 --- a/openfpga/src/base/openfpga_naming.cpp +++ b/openfpga/src/base/openfpga_naming.cpp @@ -112,8 +112,8 @@ std::string generate_mux_subckt_name(const CircuitLibrary& circuit_lib, ***********************************************/ std::string generate_mux_branch_subckt_name(const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model, - const size_t& mux_size, const size_t& branch_mux_size, + const size_t& branch_mem_size, const std::string& postfix) { /* If the tgate circuit model of this MUX is a MUX2 standard cell, * the mux_subckt name will be the name of the standard cell @@ -123,9 +123,23 @@ std::string generate_mux_branch_subckt_name(const CircuitLibrary& circuit_lib, VTR_ASSERT (CIRCUIT_MODEL_GATE_MUX2 == circuit_lib.gate_type(subckt_model)); return circuit_lib.model_name(subckt_model); } - std::string branch_postfix = postfix + "_size" + std::to_string(branch_mux_size); - return generate_mux_subckt_name(circuit_lib, circuit_model, mux_size, branch_postfix); + /* Include memory size as a second unique signature for the branch module + * This is due to some branch modules have the same input sizes but different memory sizes + */ + std::string branch_postfix = postfix + + "_input" + std::to_string(branch_mux_size) + + "_mem" + std::to_string(branch_mem_size); + + std::string module_name = circuit_lib.model_name(circuit_model); + if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(circuit_model)) { + module_name += "_mux"; + } else { + VTR_ASSERT(CIRCUIT_MODEL_MUX == circuit_lib.model_type(circuit_model)); + } + module_name += branch_postfix; + + return module_name; } /************************************************ diff --git a/openfpga/src/base/openfpga_naming.h b/openfpga/src/base/openfpga_naming.h index a43fe8bb0..a3cfac08c 100644 --- a/openfpga/src/base/openfpga_naming.h +++ b/openfpga/src/base/openfpga_naming.h @@ -43,8 +43,8 @@ std::string generate_mux_subckt_name(const CircuitLibrary& circuit_lib, std::string generate_mux_branch_subckt_name(const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model, - const size_t& mux_size, const size_t& branch_mux_size, + const size_t& branch_mem_size, const std::string& posfix); std::string generate_mux_local_decoder_subckt_name(const size_t& addr_size, diff --git a/openfpga/src/fabric/build_mux_modules.cpp b/openfpga/src/fabric/build_mux_modules.cpp index b768ac74c..fcf0db026 100644 --- a/openfpga/src/fabric/build_mux_modules.cpp +++ b/openfpga/src/fabric/build_mux_modules.cpp @@ -333,9 +333,13 @@ static void build_mux_branch_module(ModuleManager& module_manager, const CircuitLibrary& circuit_lib, const CircuitModelId& mux_model, - const size_t& mux_size, const MuxGraph& mux_graph) { - std::string module_name = generate_mux_branch_subckt_name(circuit_lib, mux_model, mux_size, mux_graph.num_inputs(), MUX_BASIS_MODULE_POSTFIX); + std::string module_name = generate_mux_branch_subckt_name(circuit_lib, mux_model, mux_graph.num_inputs(), mux_graph.num_memory_bits(), MUX_BASIS_MODULE_POSTFIX); + + /* Skip the module building if it is already there */ + if (module_manager.valid_module_id(module_manager.find_module(module_name))) { + return; + } /* Multiplexers built with different technology is in different organization */ switch (circuit_lib.design_tech_type(mux_model)) { @@ -547,8 +551,6 @@ void build_cmos_mux_module_tgate_multiplexing_structure(ModuleManager& module_ma const vtr::vector& mux_module_mem_nets, const vtr::vector& mux_module_mem_inv_nets, const MuxGraph& mux_graph) { - /* Find the actual mux size */ - size_t mux_size = find_mux_num_datapath_inputs(circuit_lib, circuit_model, mux_graph.num_inputs()); /* Get the regular (non-mode-select) sram ports from the mux */ std::vector mux_regular_sram_ports = find_circuit_regular_sram_ports(circuit_lib, circuit_model); @@ -572,9 +574,19 @@ void build_cmos_mux_module_tgate_multiplexing_structure(ModuleManager& module_ma */ size_t branch_size = mux_graph.node_in_edges(node).size(); - /* Instanciate the branch module which is a tgate-based module - */ - std::string branch_module_name= generate_mux_branch_subckt_name(circuit_lib, circuit_model, mux_size, branch_size, MUX_BASIS_MODULE_POSTFIX); + /* Get the mems in the branch circuits */ + std::vector mems; + for (const auto& edge : mux_graph.node_in_edges(node)) { + /* Get the mem control the edge */ + MuxMemId mem = mux_graph.find_edge_mem(edge); + /* Add the mem if it is not in the list */ + if (mems.end() == std::find(mems.begin(), mems.end(), mem)) { + mems.push_back(mem); + } + } + + /* Instanciate the branch module which is a tgate-based module */ + std::string branch_module_name= generate_mux_branch_subckt_name(circuit_lib, circuit_model, branch_size, mems.size(), MUX_BASIS_MODULE_POSTFIX); /* Get the moduleId for the submodule */ ModuleId branch_module_id = module_manager.find_module(branch_module_name); /* We must have one */ @@ -612,17 +624,6 @@ void build_cmos_mux_module_tgate_multiplexing_structure(ModuleManager& module_ma module_nets_by_level[output_node_level][output_node_index_at_level] = branch_net; /* Wire the branch module memory ports to the nets of MUX memory ports */ - /* Get the mems in the branch circuits */ - std::vector mems; - for (const auto& edge : mux_graph.node_in_edges(node)) { - /* Get the mem control the edge */ - MuxMemId mem = mux_graph.find_edge_mem(edge); - /* Add the mem if it is not in the list */ - if (mems.end() == std::find(mems.begin(), mems.end(), mem)) { - mems.push_back(mem); - } - } - /* Get mem/mem_inv ports of branch module */ ModulePortId branch_module_mem_port_id = module_manager.find_module_port(branch_module_id, std::string("mem")); BasicPort branch_module_mem_port = module_manager.module_port(branch_module_id, branch_module_mem_port_id); @@ -1404,7 +1405,6 @@ void build_mux_modules(ModuleManager& module_manager, /* Create branch circuits, which are N:1 one-level or 2:1 tree-like MUXes */ for (auto branch_mux_graph : branch_mux_graphs) { build_mux_branch_module(module_manager, circuit_lib, mux_circuit_model, - find_mux_num_datapath_inputs(circuit_lib, mux_circuit_model, mux_graph.num_inputs()), branch_mux_graph); } } diff --git a/openfpga/src/fpga_spice/spice_constants.h b/openfpga/src/fpga_spice/spice_constants.h index 3e045b40c..47b153cf0 100644 --- a/openfpga/src/fpga_spice/spice_constants.h +++ b/openfpga/src/fpga_spice/spice_constants.h @@ -10,6 +10,7 @@ constexpr char* TRANSISTOR_WRAPPER_POSTFIX = "_wrapper"; constexpr char* TRANSISTORS_SPICE_FILE_NAME = "transistor.sp"; constexpr char* SUPPLY_WRAPPER_SPICE_FILE_NAME = "supply_wrapper.sp"; +constexpr char* MUX_PRIMITIVES_SPICE_FILE_NAME = "mux_primitives.sp"; constexpr char* MUXES_SPICE_FILE_NAME = "muxes.sp"; constexpr char* LUTS_SPICE_FILE_NAME = "luts.sp"; constexpr char* MEMORIES_SPICE_FILE_NAME = "memories.sp"; diff --git a/openfpga/src/fpga_spice/spice_mux.cpp b/openfpga/src/fpga_spice/spice_mux.cpp index b1436d57e..147387848 100644 --- a/openfpga/src/fpga_spice/spice_mux.cpp +++ b/openfpga/src/fpga_spice/spice_mux.cpp @@ -6,6 +6,7 @@ * and the full multiplexer **********************************************/ #include +#include #include /* Headers from vtrutil library */ @@ -49,9 +50,16 @@ void generate_spice_mux_branch_subckt(const ModuleManager& module_manager, const CircuitLibrary& circuit_lib, std::fstream& fp, const CircuitModelId& mux_model, - const size_t& mux_size, - const MuxGraph& mux_graph) { - std::string module_name = generate_mux_branch_subckt_name(circuit_lib, mux_model, mux_size, mux_graph.num_inputs(), SPICE_MUX_BASIS_POSTFIX); + const MuxGraph& mux_graph, + std::map& branch_mux_module_is_outputted) { + std::string module_name = generate_mux_branch_subckt_name(circuit_lib, mux_model, mux_graph.num_inputs(), mux_graph.num_memory_bits(), SPICE_MUX_BASIS_POSTFIX); + + /* Skip outputting if the module has already been outputted */ + auto result = branch_mux_module_is_outputted.find(module_name); + if ((result != branch_mux_module_is_outputted.end()) + && (true == result->second)) { + return; + } /* Multiplexers built with different technology is in different organization */ switch (circuit_lib.design_tech_type(mux_model)) { @@ -84,6 +92,9 @@ void generate_spice_mux_branch_subckt(const ModuleManager& module_manager, circuit_lib.model_name(mux_model).c_str()); exit(1); } + + /* Record that this branch module has been outputted */ + branch_mux_module_is_outputted[module_name] = true; } /*********************************************** @@ -127,14 +138,73 @@ void generate_spice_mux_subckt(const ModuleManager& module_manager, } /*********************************************** - * Generate SPICE subcircuits for all the unique + * Generate primitive SPICE subcircuits for all the unique * multiplexers in the FPGA device **********************************************/ -int print_spice_submodule_muxes(NetlistManager& netlist_manager, - const ModuleManager& module_manager, - const MuxLibrary& mux_lib, - const CircuitLibrary& circuit_lib, - const std::string& submodule_dir) { +static +int print_spice_submodule_mux_primitives(NetlistManager& netlist_manager, + const ModuleManager& module_manager, + const MuxLibrary& mux_lib, + const CircuitLibrary& circuit_lib, + const std::string& submodule_dir) { + int status = CMD_EXEC_SUCCESS; + + std::string spice_fname(submodule_dir + std::string(MUX_PRIMITIVES_SPICE_FILE_NAME)); + + /* Create the file stream */ + std::fstream fp; + fp.open(spice_fname, std::fstream::out | std::fstream::trunc); + + check_file_stream(spice_fname.c_str(), fp); + + /* Print out debugging information for if the file is not opened/created properly */ + VTR_LOG("Writing SPICE netlist for Multiplexer primitives '%s' ...", + spice_fname.c_str()); + + print_spice_file_header(fp, "Multiplexer primitives"); + + /* Record if the branch module has been outputted + * since different sizes of routing multiplexers may share the same branch module + */ + std::map branch_mux_module_is_outputted; + + /* Generate basis sub-circuit for unique branches shared by the multiplexers */ + for (auto mux : mux_lib.muxes()) { + const MuxGraph& mux_graph = mux_lib.mux_graph(mux); + CircuitModelId mux_circuit_model = mux_lib.mux_circuit_model(mux); + /* Create a mux graph for the branch circuit */ + std::vector branch_mux_graphs = mux_graph.build_mux_branch_graphs(); + /* Create branch circuits, which are N:1 one-level or 2:1 tree-like MUXes */ + for (auto branch_mux_graph : branch_mux_graphs) { + generate_spice_mux_branch_subckt(module_manager, circuit_lib, fp, mux_circuit_model, + branch_mux_graph, + branch_mux_module_is_outputted); + } + } + + /* Close the file stream */ + fp.close(); + + /* Add fname to the netlist name list */ + NetlistId nlist_id = netlist_manager.add_netlist(spice_fname); + VTR_ASSERT(NetlistId::INVALID() != nlist_id); + netlist_manager.set_netlist_type(nlist_id, NetlistManager::SUBMODULE_NETLIST); + + VTR_LOG("Done\n"); + + return status; +} + +/*********************************************** + * Generate top-level SPICE subcircuits for all the unique + * multiplexers in the FPGA device + **********************************************/ +static +int print_spice_submodule_mux_top_subckt(NetlistManager& netlist_manager, + const ModuleManager& module_manager, + const MuxLibrary& mux_lib, + const CircuitLibrary& circuit_lib, + const std::string& submodule_dir) { int status = CMD_EXEC_SUCCESS; std::string spice_fname(submodule_dir + std::string(MUXES_SPICE_FILE_NAME)); @@ -151,20 +221,6 @@ int print_spice_submodule_muxes(NetlistManager& netlist_manager, print_spice_file_header(fp, "Multiplexers"); - /* Generate basis sub-circuit for unique branches shared by the multiplexers */ - for (auto mux : mux_lib.muxes()) { - const MuxGraph& mux_graph = mux_lib.mux_graph(mux); - CircuitModelId mux_circuit_model = mux_lib.mux_circuit_model(mux); - /* Create a mux graph for the branch circuit */ - std::vector branch_mux_graphs = mux_graph.build_mux_branch_graphs(); - /* Create branch circuits, which are N:1 one-level or 2:1 tree-like MUXes */ - for (auto branch_mux_graph : branch_mux_graphs) { - generate_spice_mux_branch_subckt(module_manager, circuit_lib, fp, mux_circuit_model, - find_mux_num_datapath_inputs(circuit_lib, mux_circuit_model, mux_graph.num_inputs()), - branch_mux_graph); - } - } - /* Generate unique Verilog modules for the multiplexers */ for (auto mux : mux_lib.muxes()) { const MuxGraph& mux_graph = mux_lib.mux_graph(mux); @@ -186,4 +242,38 @@ int print_spice_submodule_muxes(NetlistManager& netlist_manager, return status; } +/*********************************************** + * Generate SPICE modules for all the unique + * multiplexers in the FPGA device + * Output to two SPICE netlists: + * - A SPICE netlist contains all the primitive + * cells for build the routing multiplexers + * - A SPICE netlist contains all the top-level + * module for routing multiplexers + **********************************************/ +int print_spice_submodule_muxes(NetlistManager& netlist_manager, + const ModuleManager& module_manager, + const MuxLibrary& mux_lib, + const CircuitLibrary& circuit_lib, + const std::string& submodule_dir) { + int status = CMD_EXEC_SUCCESS; + + status = print_spice_submodule_mux_primitives(netlist_manager, module_manager, + mux_lib, circuit_lib, submodule_dir); + + if (CMD_EXEC_FATAL_ERROR == status) { + return status; + } + + status = print_spice_submodule_mux_top_subckt(netlist_manager, module_manager, + mux_lib, circuit_lib, submodule_dir); + + if (CMD_EXEC_FATAL_ERROR == status) { + return status; + } + + + return status; +} + } /* end namespace openfpga */ diff --git a/openfpga/src/fpga_verilog/verilog_mux.cpp b/openfpga/src/fpga_verilog/verilog_mux.cpp index 7fbd8aff9..a0fd896e2 100644 --- a/openfpga/src/fpga_verilog/verilog_mux.cpp +++ b/openfpga/src/fpga_verilog/verilog_mux.cpp @@ -6,6 +6,7 @@ * and the full multiplexer **********************************************/ #include +#include #include /* Headers from vtrutil library */ @@ -580,10 +581,17 @@ void generate_verilog_mux_branch_module(ModuleManager& module_manager, const CircuitLibrary& circuit_lib, std::fstream& fp, const CircuitModelId& mux_model, - const size_t& mux_size, const MuxGraph& mux_graph, - const bool& use_explicit_port_map) { - std::string module_name = generate_mux_branch_subckt_name(circuit_lib, mux_model, mux_size, mux_graph.num_inputs(), VERILOG_MUX_BASIS_POSTFIX); + const bool& use_explicit_port_map, + std::map& branch_mux_module_is_outputted) { + std::string module_name = generate_mux_branch_subckt_name(circuit_lib, mux_model, mux_graph.num_inputs(), mux_graph.num_memory_bits(), VERILOG_MUX_BASIS_POSTFIX); + + /* Skip outputting if the module has already been outputted */ + auto result = branch_mux_module_is_outputted.find(module_name); + if ((result != branch_mux_module_is_outputted.end()) + && (true == result->second)) { + return; + } /* Multiplexers built with different technology is in different organization */ switch (circuit_lib.design_tech_type(mux_model)) { @@ -618,6 +626,9 @@ void generate_verilog_mux_branch_module(ModuleManager& module_manager, circuit_lib.model_name(mux_model).c_str()); exit(1); } + + /* Record that this branch module has been outputted */ + branch_mux_module_is_outputted[module_name] = true; } /******************************************************************** @@ -809,9 +820,6 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu /* Make sure we have a valid file handler*/ VTR_ASSERT(true == valid_file_stream(fp)); - /* Find the actual mux size */ - size_t mux_size = find_mux_num_datapath_inputs(circuit_lib, circuit_model, mux_graph.num_inputs()); - /* Get the BL and WL ports from the mux */ std::vector mux_blb_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_BLB, true); std::vector mux_wl_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_WL, true); @@ -876,7 +884,7 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu /* Instanciate the branch module which is a tgate-based module */ - std::string branch_module_name= generate_mux_branch_subckt_name(circuit_lib, circuit_model, mux_size, branch_size, VERILOG_MUX_BASIS_POSTFIX); + std::string branch_module_name= generate_mux_branch_subckt_name(circuit_lib, circuit_model, branch_size, mems.size(), VERILOG_MUX_BASIS_POSTFIX); /* Get the moduleId for the submodule */ ModuleId branch_module_id = module_manager.find_module(branch_module_name); /* We must have one */ @@ -1244,6 +1252,11 @@ void print_verilog_submodule_mux_primitives(ModuleManager& module_manager, print_verilog_file_header(fp, "Multiplexer primitives"); + /* Record if the branch module has been outputted + * since different sizes of routing multiplexers may share the same branch module + */ + std::map branch_mux_module_is_outputted; + /* Generate basis sub-circuit for unique branches shared by the multiplexers */ for (auto mux : mux_lib.muxes()) { const MuxGraph& mux_graph = mux_lib.mux_graph(mux); @@ -1253,8 +1266,8 @@ void print_verilog_submodule_mux_primitives(ModuleManager& module_manager, /* Create branch circuits, which are N:1 one-level or 2:1 tree-like MUXes */ for (auto branch_mux_graph : branch_mux_graphs) { generate_verilog_mux_branch_module(module_manager, circuit_lib, fp, mux_circuit_model, - find_mux_num_datapath_inputs(circuit_lib, mux_circuit_model, mux_graph.num_inputs()), - branch_mux_graph, use_explicit_port_map); + branch_mux_graph, use_explicit_port_map, + branch_mux_module_is_outputted); } }