start developing mux Verilog module generation

This commit is contained in:
tangxifan 2019-09-03 16:59:03 -06:00
parent a8c803f08f
commit 4d183a3fe4
4 changed files with 187 additions and 5 deletions

View File

@ -178,6 +178,15 @@ bool CircuitLibrary::is_lut_intermediate_buffered(const CircuitModelId& model_id
return buffer_existence_[model_id][LUT_INTER_BUFFER];
}
/* Return a flag showing if a LUT circuit model uses fracturable structure */
bool CircuitLibrary::is_lut_fracturable(const CircuitModelId& model_id) const {
/* validate the model_id */
VTR_ASSERT(valid_model_id(model_id));
/* validate the circuit model type is LUT */
VTR_ASSERT(SPICE_MODEL_LUT == model_type(model_id));
return lut_is_fracturable_[model_id];
}
/* Find the id of pass-gate circuit model
* Two cases to be considered:
* 1. this is a pass-gate circuit model, just find the data and return

View File

@ -225,6 +225,7 @@ class CircuitLibrary {
bool is_output_buffered(const CircuitModelId& model_id) const;
/* LUT-related information */
bool is_lut_intermediate_buffered(const CircuitModelId& model_id) const;
bool is_lut_fracturable(const CircuitModelId& model_id) const;
/* Pass-gate-logic information */
CircuitModelId pass_gate_logic_model(const CircuitModelId& model_id) const;
enum e_spice_model_pass_gate_logic_type pass_gate_logic_type(const CircuitModelId& model_id) const;

View File

@ -9,15 +9,28 @@
/************************************************
* Generate the module name for a multiplexer in Verilog format
* Different circuit model requires different names:
* 1. LUTs are named as <model_name>_mux
* 2. MUXes are named as <model_name>_size<num_inputs>
***********************************************/
std::string generate_verilog_mux_subckt_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model,
const size_t& mux_size,
const std::string& postfix) {
std::string module_name = circuit_lib.model_name(circuit_model);
module_name += "_size";
module_name += std::to_string(mux_size);
module_name += postfix;
/* Check the model type and give different names */
if (SPICE_MODEL_MUX == circuit_lib.model_type(circuit_model)) {
module_name += "_size";
module_name += std::to_string(mux_size);
} else {
VTR_ASSERT(SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model));
module_name += "_mux";
}
/* Add postfix if it is not empty */
if (!postfix.empty()) {
module_name += postfix;
}
return module_name;
}

View File

@ -692,6 +692,160 @@ void generate_verilog_mux_branch_module(ModuleManager& module_manager,
}
}
/*********************************************************************
* Generate Verilog codes modeling a CMOS multiplexer with the given size
* The Verilog module will consist of three parts:
* 1. instances of the branch circuits of multiplexers which are generated before
* This builds up the multiplexing structure
* 2. Input buffers/inverters
* 3. Output buffers/inverters
*********************************************************************/
static
void generate_verilog_cmos_mux_module(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
std::fstream& fp,
const CircuitModelId& circuit_model,
const std::string& module_name,
const MuxGraph& mux_graph) {
/* Get the global ports required by MUX (and any submodules) */
std::vector<CircuitPortId> mux_global_ports = circuit_lib.model_global_ports_by_type(circuit_model, SPICE_MODEL_PORT_INPUT, true);
/* Get the input ports from the mux */
std::vector<CircuitPortId> mux_input_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_INPUT, true);
/* Get the output ports from the mux */
std::vector<CircuitPortId> mux_output_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_OUTPUT, true);
/* Get the sram ports from the mux */
std::vector<CircuitPortId> mux_sram_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_SRAM, true);
/* Make sure we have a valid file handler*/
check_file_handler(fp);
/* Generate the Verilog netlist according to the mux_graph */
/* TODO: Find out the number of data-path inputs */
size_t num_inputs = mux_graph.num_inputs();
/* Find out the number of outputs */
size_t num_outputs = mux_graph.num_outputs();
/* Find out the number of memory bits */
size_t num_mems = mux_graph.num_memory_bits();
/* Check codes to ensure the port of Verilog netlists will match */
/* MUX graph must have only 1 output */
VTR_ASSERT(1 == mux_input_ports.size());
VTR_ASSERT(1 == mux_input_ports.size());
VTR_ASSERT(1 == num_outputs);
/* A quick check on the model ports */
if ((SPICE_MODEL_MUX == circuit_lib.model_type(circuit_model))
|| ((SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model))
&& (false == circuit_lib.is_lut_fracturable(circuit_model))) ) {
VTR_ASSERT(1 == mux_output_ports.size());
VTR_ASSERT(1 == circuit_lib.port_size(mux_output_ports[0]));
} else {
VTR_ASSERT_SAFE( (SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model))
&& (true == circuit_lib.is_lut_fracturable(circuit_model)) );
for (const auto& port : mux_output_ports) {
VTR_ASSERT(0 < circuit_lib.port_size(port));
}
}
/* Create a Verilog Module based on the circuit model, and add to module manager */
ModuleId module_id = module_manager.add_module(module_name);
VTR_ASSERT(ModuleId::INVALID() != module_id);
/* Add module ports */
/* Add each global port */
for (const auto& port : mux_global_ports) {
/* Configure each global port */
BasicPort global_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
module_manager.add_port(module_id, global_port, ModuleManager::MODULE_GLOBAL_PORT);
}
/* Add each input port
* Treat MUX and LUT differently
* 1. MUXes: we do not have a specific input sizes, it is inferred by architecture
* 2. LUTes: we do have a specific input sizes
*/
for (const auto& port : mux_input_ports) {
BasicPort input_port(circuit_lib.port_lib_name(port), num_inputs);
if (SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model)) {
input_port.set_width(circuit_lib.port_size(port));
}
module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT);
}
/* Add each output port
* Treat MUX and LUT differently
* 1. MUXes: we do not have a specific output sizes, it is inferred by architecture
* 2. LUTes: we do have a specific input sizes
*/
for (const auto& port : mux_output_ports) {
BasicPort output_port(circuit_lib.port_lib_name(port), num_outputs);
if (SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model)) {
output_port.set_width(circuit_lib.port_size(port));
}
module_manager.add_port(module_id, output_port, ModuleManager::MODULE_OUTPUT_PORT);
}
/* Add each memory port */
size_t sram_port_cnt = 0;
for (const auto& port : mux_sram_ports) {
/* Multiplexing structure does not mode_sram_ports, they are handled in LUT modules
* Here we just bypass it.
*/
if (true == circuit_lib.port_is_mode_select(port)) {
continue;
}
BasicPort mem_port(circuit_lib.port_lib_name(port), num_mems);
module_manager.add_port(module_id, mem_port, ModuleManager::MODULE_INPUT_PORT);
BasicPort mem_inv_port(std::string(circuit_lib.port_lib_name(port) + "_inv"), num_mems);
module_manager.add_port(module_id, mem_inv_port, ModuleManager::MODULE_INPUT_PORT);
/* Update counter */
sram_port_cnt++;
}
/* Double check: We should have only 1 sram port outputted here! */
VTR_ASSERT(1 == sram_port_cnt);
/* dump module definition + ports */
print_verilog_module_declaration(fp, module_manager, module_id);
/* TODO: Print the internal logic in Verilog codes */
/* TODO: Print the Multiplexing structure in Verilog codes */
/* TODO: Print the input buffers in Verilog codes */
/* TODO: Print the output buffers in Verilog codes */
/* Put an end to the Verilog module */
print_verilog_module_end(fp, module_name);
}
/***********************************************
* Generate Verilog codes modeling a multiplexer
* with the given graph-level description
**********************************************/
static
void generate_verilog_mux_module(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
std::fstream& fp,
const CircuitModelId& circuit_model,
const MuxGraph& mux_graph) {
std::string module_name = generate_verilog_mux_subckt_name(circuit_lib, circuit_model, mux_graph.num_inputs(), std::string(""));
/* Multiplexers built with different technology is in different organization */
switch (circuit_lib.design_tech_type(circuit_model)) {
case SPICE_MODEL_DESIGN_CMOS:
/* SRAM-based Multiplexer Verilog module generation */
generate_verilog_cmos_mux_module(module_manager, circuit_lib, fp, circuit_model, module_name, mux_graph);
break;
case SPICE_MODEL_DESIGN_RRAM:
/* TODO: RRAM-based Multiplexer Verilog module generation */
/*
generate_verilog_rram_mux_branch_module(module_manager, circuit_lib, fp, circuit_model, module_name, mux_graph,
circuit_lib.dump_structural_verilog(circuit_model));
*/
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(FILE:%s,LINE[%d]) Invalid design technology of multiplexer (name: %s)\n",
__FILE__, __LINE__, circuit_lib.model_name(circuit_model).c_str());
exit(1);
}
}
/***********************************************
* Generate Verilog modules for all the unique
* multiplexers in the FPGA device
@ -733,10 +887,15 @@ void print_verilog_submodule_muxes(ModuleManager& module_manager,
generate_verilog_mux_branch_module(module_manager, circuit_lib, fp, mux_circuit_model,
mux_graph.num_inputs(), branch_mux_graph);
}
/* TODO: create MUX modules */
}
/* Dump MUX graph one by one */
/* Generate unique Verilog modules for 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 MUX circuits */
generate_verilog_mux_module(module_manager, circuit_lib, fp, mux_circuit_model, mux_graph);
}
/* Close the file steam */
fp.close();