Merge pull request #149 from lnis-uofu/dev
Netlist/Module size Reduction for Routing Multiplexers
This commit is contained in:
commit
2eaff52c13
|
@ -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;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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<MuxMemId, ModuleNetId>& mux_module_mem_nets,
|
||||
const vtr::vector<MuxMemId, ModuleNetId>& 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<CircuitPortId> 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<MuxMemId> 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<MuxMemId> 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* and the full multiplexer
|
||||
**********************************************/
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
/* 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<std::string, bool>& 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<std::string, bool> 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<MuxGraph> 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<MuxGraph> 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 */
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* and the full multiplexer
|
||||
**********************************************/
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
/* 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<std::string, bool>& 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<CircuitPortId> mux_blb_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_BLB, true);
|
||||
std::vector<CircuitPortId> 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<std::string, bool> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue