refactored LUT Verilog generation
This commit is contained in:
parent
6a5b50facf
commit
0399319212
|
@ -376,6 +376,24 @@ size_t check_circuit_library_ports(const CircuitLibrary& circuit_lib) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Check the tri-state map of ports, the length should match the port size! */
|
||||||
|
for (const auto& port : circuit_lib.ports()) {
|
||||||
|
if (circuit_lib.port_tri_state_map(port).empty()) {
|
||||||
|
continue; /* No tri-state map is found, go to the next */
|
||||||
|
}
|
||||||
|
if (circuit_lib.port_tri_state_map(port).length() == circuit_lib.port_size(port)) {
|
||||||
|
continue; /* Sizes match, go to the next */
|
||||||
|
}
|
||||||
|
/* We have a problem here, sizes do not match, leave a message and raise the error flag */
|
||||||
|
vpr_printf(TIO_MESSAGE_ERROR,
|
||||||
|
"Tri-state map (=%s) of circuit port (type=%s) of model (name=%s) does not match the port size (=%lu)!\n",
|
||||||
|
circuit_lib.port_tri_state_map(port).c_str(),
|
||||||
|
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(circuit_lib.port_type(port))],
|
||||||
|
circuit_lib.model_name(port).c_str(),
|
||||||
|
circuit_lib.port_size(port));
|
||||||
|
num_err++;
|
||||||
|
}
|
||||||
|
|
||||||
return num_err;
|
return num_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -192,6 +192,32 @@ bool CircuitLibrary::is_lut_fracturable(const CircuitModelId& model_id) const {
|
||||||
return lut_is_fracturable_[model_id];
|
return lut_is_fracturable_[model_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return the circuit model of input buffers
|
||||||
|
* that are inserted between multiplexing structure and LUT inputs
|
||||||
|
*/
|
||||||
|
CircuitModelId CircuitLibrary::lut_input_inverter_model(const CircuitModelId& model_id) const {
|
||||||
|
/* validate the model_id */
|
||||||
|
VTR_ASSERT(valid_model_id(model_id));
|
||||||
|
/* validate the circuit model type is BUF */
|
||||||
|
VTR_ASSERT(SPICE_MODEL_LUT == model_type(model_id));
|
||||||
|
/* We MUST have an input inverter */
|
||||||
|
VTR_ASSERT(true == buffer_existence_[model_id][LUT_INPUT_INVERTER]);
|
||||||
|
return buffer_model_ids_[model_id][LUT_INPUT_INVERTER];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the circuit model of input buffers
|
||||||
|
* that are inserted between multiplexing structure and LUT inputs
|
||||||
|
*/
|
||||||
|
CircuitModelId CircuitLibrary::lut_input_buffer_model(const CircuitModelId& model_id) const {
|
||||||
|
/* validate the model_id */
|
||||||
|
VTR_ASSERT(valid_model_id(model_id));
|
||||||
|
/* validate the circuit model type is BUF */
|
||||||
|
VTR_ASSERT(SPICE_MODEL_LUT == model_type(model_id));
|
||||||
|
/* We MUST have an input buffer */
|
||||||
|
VTR_ASSERT(true == buffer_existence_[model_id][LUT_INPUT_BUFFER]);
|
||||||
|
return buffer_model_ids_[model_id][LUT_INPUT_BUFFER];
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the circuit model of intermediate buffers
|
/* Return the circuit model of intermediate buffers
|
||||||
* that are inserted inside LUT multiplexing structures
|
* that are inserted inside LUT multiplexing structures
|
||||||
*/
|
*/
|
||||||
|
@ -200,7 +226,7 @@ CircuitModelId CircuitLibrary::lut_intermediate_buffer_model(const CircuitModelI
|
||||||
VTR_ASSERT(valid_model_id(model_id));
|
VTR_ASSERT(valid_model_id(model_id));
|
||||||
/* validate the circuit model type is BUF */
|
/* validate the circuit model type is BUF */
|
||||||
VTR_ASSERT(SPICE_MODEL_LUT == model_type(model_id));
|
VTR_ASSERT(SPICE_MODEL_LUT == model_type(model_id));
|
||||||
/* if we have an intermediate buffer, we return something, otherwise return an empty map */
|
/* if we have an intermediate buffer, we return something, otherwise return an invalid id */
|
||||||
if (true == is_lut_intermediate_buffered(model_id)) {
|
if (true == is_lut_intermediate_buffered(model_id)) {
|
||||||
return buffer_model_ids_[model_id][LUT_INTER_BUFFER];
|
return buffer_model_ids_[model_id][LUT_INTER_BUFFER];
|
||||||
} else {
|
} else {
|
||||||
|
@ -749,6 +775,20 @@ std::vector<size_t> CircuitLibrary::port_lut_output_masks(const CircuitPortId& c
|
||||||
return port_lut_output_masks_[circuit_port_id];
|
return port_lut_output_masks_[circuit_port_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return tri-state map of a port */
|
||||||
|
std::string CircuitLibrary::port_tri_state_map(const CircuitPortId& circuit_port_id) const {
|
||||||
|
/* validate the circuit_port_id */
|
||||||
|
VTR_ASSERT(valid_circuit_port_id(circuit_port_id));
|
||||||
|
return port_tri_state_maps_[circuit_port_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return circuit model id which is used to tri-state a port */
|
||||||
|
CircuitModelId CircuitLibrary::port_tri_state_model(const CircuitPortId& circuit_port_id) const {
|
||||||
|
/* validate the circuit_port_id */
|
||||||
|
VTR_ASSERT(valid_circuit_port_id(circuit_port_id));
|
||||||
|
return port_tri_state_model_ids_[circuit_port_id];
|
||||||
|
}
|
||||||
|
|
||||||
/* Return the id of parent circuit model for a circuit port */
|
/* Return the id of parent circuit model for a circuit port */
|
||||||
CircuitModelId CircuitLibrary::port_parent_model(const CircuitPortId& circuit_port_id) const {
|
CircuitModelId CircuitLibrary::port_parent_model(const CircuitPortId& circuit_port_id) const {
|
||||||
/* validate the circuit_port_id */
|
/* validate the circuit_port_id */
|
||||||
|
|
|
@ -226,6 +226,8 @@ class CircuitLibrary {
|
||||||
/* LUT-related information */
|
/* LUT-related information */
|
||||||
bool is_lut_intermediate_buffered(const CircuitModelId& model_id) const;
|
bool is_lut_intermediate_buffered(const CircuitModelId& model_id) const;
|
||||||
bool is_lut_fracturable(const CircuitModelId& model_id) const;
|
bool is_lut_fracturable(const CircuitModelId& model_id) const;
|
||||||
|
CircuitModelId lut_input_buffer_model(const CircuitModelId& model_id) const;
|
||||||
|
CircuitModelId lut_input_inverter_model(const CircuitModelId& model_id) const;
|
||||||
CircuitModelId lut_intermediate_buffer_model(const CircuitModelId& model_id) const;
|
CircuitModelId lut_intermediate_buffer_model(const CircuitModelId& model_id) const;
|
||||||
std::string lut_intermediate_buffer_location_map(const CircuitModelId& model_id) const;
|
std::string lut_intermediate_buffer_location_map(const CircuitModelId& model_id) const;
|
||||||
/* Pass-gate-logic information */
|
/* Pass-gate-logic information */
|
||||||
|
@ -277,6 +279,8 @@ class CircuitLibrary {
|
||||||
bool port_is_prog(const CircuitPortId& circuit_port_id) const;
|
bool port_is_prog(const CircuitPortId& circuit_port_id) const;
|
||||||
size_t port_lut_frac_level(const CircuitPortId& circuit_port_id) const;
|
size_t port_lut_frac_level(const CircuitPortId& circuit_port_id) const;
|
||||||
std::vector<size_t> port_lut_output_masks(const CircuitPortId& circuit_port_id) const;
|
std::vector<size_t> port_lut_output_masks(const CircuitPortId& circuit_port_id) const;
|
||||||
|
std::string port_tri_state_map(const CircuitPortId& circuit_port_id) const;
|
||||||
|
CircuitModelId port_tri_state_model(const CircuitPortId& circuit_port_id) const;
|
||||||
CircuitModelId port_parent_model(const CircuitPortId& circuit_port_id) const;
|
CircuitModelId port_parent_model(const CircuitPortId& circuit_port_id) const;
|
||||||
std::string model_name(const CircuitPortId& port_id) const;
|
std::string model_name(const CircuitPortId& port_id) const;
|
||||||
public: /* Public Accessors: Timing graph */
|
public: /* Public Accessors: Timing graph */
|
||||||
|
|
|
@ -0,0 +1,384 @@
|
||||||
|
/********************************************************************
|
||||||
|
* This file includes functions to generate Verilog submodules for LUTs
|
||||||
|
********************************************************************/
|
||||||
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
#include "util.h"
|
||||||
|
#include "vtr_assert.h"
|
||||||
|
|
||||||
|
/* Device-level header files */
|
||||||
|
#include "mux_graph.h"
|
||||||
|
#include "module_manager.h"
|
||||||
|
#include "physical_types.h"
|
||||||
|
#include "vpr_types.h"
|
||||||
|
#include "mux_utils.h"
|
||||||
|
|
||||||
|
/* FPGA-X2P context header files */
|
||||||
|
#include "spice_types.h"
|
||||||
|
#include "fpga_x2p_naming.h"
|
||||||
|
#include "fpga_x2p_utils.h"
|
||||||
|
|
||||||
|
/* FPGA-Verilog context header files */
|
||||||
|
#include "verilog_global.h"
|
||||||
|
#include "verilog_writer_utils.h"
|
||||||
|
#include "verilog_submodule_utils.h"
|
||||||
|
#include "verilog_lut.h"
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Print a Verilog module for a LUT circuit model
|
||||||
|
* This function supports both single-output and fracturable LUTs
|
||||||
|
* The Verilog module will be organized in structural Verilog codes.
|
||||||
|
* It will instanciate:
|
||||||
|
* 1. Multiplexer used inside LUT
|
||||||
|
* 2. Input buffers
|
||||||
|
* 3. Input inverters
|
||||||
|
* 4. Output buffers.
|
||||||
|
* 6. AND/OR gates to tri-state LUT inputs
|
||||||
|
********************************************************************/
|
||||||
|
static
|
||||||
|
void print_verilog_submodule_lut(ModuleManager& module_manager,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
std::fstream& fp,
|
||||||
|
const CircuitModelId& circuit_model) {
|
||||||
|
/* Ensure a valid file handler*/
|
||||||
|
check_file_handler(fp);
|
||||||
|
|
||||||
|
/* Get the global ports required by MUX (and any submodules) */
|
||||||
|
std::vector<CircuitPortId> lut_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> lut_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> lut_output_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_OUTPUT, true);
|
||||||
|
|
||||||
|
/* Classify SRAM ports into two categories: regular (not for mode select) and mode-select */
|
||||||
|
std::vector<CircuitPortId> lut_regular_sram_ports;
|
||||||
|
std::vector<CircuitPortId> lut_mode_select_sram_ports;
|
||||||
|
|
||||||
|
{ /* Create a code block to keep some variables in local */
|
||||||
|
/* Get the sram ports from the mux */
|
||||||
|
std::vector<CircuitPortId> lut_sram_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_SRAM, true);
|
||||||
|
for (const auto& port : lut_sram_ports) {
|
||||||
|
/* Bypass mode_select ports */
|
||||||
|
if (true == circuit_lib.port_is_mode_select(port)) {
|
||||||
|
lut_mode_select_sram_ports.push_back(port);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
VTR_ASSERT_SAFE (false == circuit_lib.port_is_mode_select(port));
|
||||||
|
lut_regular_sram_ports.push_back(port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make sure that the number of ports and sizes of ports are what we want */
|
||||||
|
if (false == circuit_lib.is_lut_fracturable(circuit_model)) {
|
||||||
|
/* Single-output LUTs:
|
||||||
|
* We should have only 1 input port, 1 output port and 1 SRAM port
|
||||||
|
*/
|
||||||
|
VTR_ASSERT (1 == lut_input_ports.size());
|
||||||
|
VTR_ASSERT (1 == lut_output_ports.size());
|
||||||
|
VTR_ASSERT (1 == lut_regular_sram_ports.size());
|
||||||
|
VTR_ASSERT (0 == lut_mode_select_sram_ports.size());
|
||||||
|
} else {
|
||||||
|
VTR_ASSERT (true == circuit_lib.is_lut_fracturable(circuit_model));
|
||||||
|
/* Fracturable LUT:
|
||||||
|
* We should have only 1 input port, a few output ports (fracturable outputs)
|
||||||
|
* and two SRAM ports
|
||||||
|
*/
|
||||||
|
VTR_ASSERT (1 == lut_input_ports.size());
|
||||||
|
VTR_ASSERT (1 <= lut_output_ports.size());
|
||||||
|
VTR_ASSERT (1 == lut_regular_sram_ports.size());
|
||||||
|
VTR_ASSERT (1 == lut_mode_select_sram_ports.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a Verilog Module based on the circuit model, and add to module manager */
|
||||||
|
ModuleId module_id = module_manager.add_module(circuit_lib.model_name(circuit_model));
|
||||||
|
VTR_ASSERT(ModuleId::INVALID() != module_id);
|
||||||
|
/* Add module ports */
|
||||||
|
/* Add each global port */
|
||||||
|
for (const auto& port : lut_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 */
|
||||||
|
for (const auto& port : lut_input_ports) {
|
||||||
|
BasicPort input_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
|
||||||
|
module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT);
|
||||||
|
}
|
||||||
|
/* Add each output port */
|
||||||
|
for (const auto& port : lut_output_ports) {
|
||||||
|
BasicPort output_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
|
||||||
|
module_manager.add_port(module_id, output_port, ModuleManager::MODULE_OUTPUT_PORT);
|
||||||
|
}
|
||||||
|
/* Add each regular (not mode select) SRAM port */
|
||||||
|
for (const auto& port : lut_regular_sram_ports) {
|
||||||
|
BasicPort mem_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
|
||||||
|
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"), circuit_lib.port_size(port));
|
||||||
|
module_manager.add_port(module_id, mem_inv_port, ModuleManager::MODULE_INPUT_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add each mode-select SRAM port */
|
||||||
|
for (const auto& port : lut_mode_select_sram_ports) {
|
||||||
|
BasicPort mem_port(circuit_lib.port_lib_name(port), circuit_lib.port_size(port));
|
||||||
|
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"), circuit_lib.port_size(port));
|
||||||
|
module_manager.add_port(module_id, mem_inv_port, ModuleManager::MODULE_INPUT_PORT);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* dump module definition + ports */
|
||||||
|
print_verilog_module_declaration(fp, module_manager, module_id);
|
||||||
|
|
||||||
|
/* Print local wires for mode selector */
|
||||||
|
/* Local wires for the output of mode selector */
|
||||||
|
BasicPort mode_select_output_port(std::string(circuit_lib.port_lib_name(lut_input_ports[0]) + "_mode"), circuit_lib.port_size(lut_input_ports[0]));
|
||||||
|
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, mode_select_output_port) << ";" << std::endl;
|
||||||
|
/* Local wires for the output of input inverters */
|
||||||
|
BasicPort inverted_input_port(std::string(circuit_lib.port_lib_name(lut_input_ports[0]) + "_b"), circuit_lib.port_size(lut_input_ports[0]));
|
||||||
|
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, inverted_input_port) << ";" << std::endl;
|
||||||
|
/* Local wires for the output of input buffers */
|
||||||
|
BasicPort buffered_input_port(std::string(circuit_lib.port_lib_name(lut_input_ports[0]) + "_buf"), circuit_lib.port_size(lut_input_ports[0]));
|
||||||
|
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, buffered_input_port) << ";" << std::endl;
|
||||||
|
|
||||||
|
/* Instanciate mode selecting circuit: AND/OR gate
|
||||||
|
* By following the tri-state map of LUT input port
|
||||||
|
* The wiring of input ports will be organized as follows
|
||||||
|
*
|
||||||
|
* LUT input
|
||||||
|
* |
|
||||||
|
* v
|
||||||
|
* +----------+
|
||||||
|
* | mode |
|
||||||
|
* | selector |
|
||||||
|
* +----------+
|
||||||
|
* | mode_select_output_port
|
||||||
|
* +-----------------+------------+
|
||||||
|
* | |
|
||||||
|
* +----------+ +---------+
|
||||||
|
* | Inverter | | Buffer |
|
||||||
|
* +----------+ +---------+
|
||||||
|
* | inverter_input_port | buffered_input_port
|
||||||
|
* v v
|
||||||
|
* +--------------------------------------+
|
||||||
|
* | LUT Multiplexing Structure |
|
||||||
|
* +--------------------------------------+
|
||||||
|
*/
|
||||||
|
print_verilog_comment(fp, std::string("---- BEGIN Instanciation of model-select gates -----"));
|
||||||
|
/* Get the tri-state port map for the input ports*/
|
||||||
|
std::string tri_state_map = circuit_lib.port_tri_state_map(lut_input_ports[0]);
|
||||||
|
size_t mode_select_port_lsb = 0;
|
||||||
|
for (const auto& pin : circuit_lib.pins(lut_input_ports[0])) {
|
||||||
|
BasicPort cur_mode_select_output_port(mode_select_output_port.get_name(), pin, pin);
|
||||||
|
BasicPort cur_input_port(circuit_lib.port_lib_name(lut_input_ports[0]), pin, pin);
|
||||||
|
/* For an empty tri-state map or a '-' sign in tri-state map, we can short-wire mode select_output_ports */
|
||||||
|
if (tri_state_map.empty() || ('-' == tri_state_map[pin]) ) {
|
||||||
|
print_verilog_wire_connection(fp, cur_mode_select_output_port, cur_input_port, false);
|
||||||
|
continue; /* Finish here */
|
||||||
|
}
|
||||||
|
/* Reach here, it means that we need a circuit for mode selection */
|
||||||
|
BasicPort cur_lut_mode_select_sram_port(circuit_lib.port_lib_name(lut_mode_select_sram_ports[0]), mode_select_port_lsb, mode_select_port_lsb);
|
||||||
|
enum e_spice_model_gate_type required_gate_type;
|
||||||
|
if ('0' == tri_state_map[pin]) {
|
||||||
|
/* We need a 2-input AND gate, in order to tri-state the input
|
||||||
|
* Detailed circuit is as follow:
|
||||||
|
* +---------+
|
||||||
|
* SRAM --->| 2-input |----> mode_select_output_port
|
||||||
|
* LUT input--->| AND |
|
||||||
|
* +---------+
|
||||||
|
* When SRAM is set to logic 0, the LUT input is tri-stated
|
||||||
|
* When SRAM is set to logic 1, the LUT input is effective to the downstream circuits
|
||||||
|
*/
|
||||||
|
required_gate_type = SPICE_MODEL_GATE_AND;
|
||||||
|
} else {
|
||||||
|
VTR_ASSERT ('1' == tri_state_map[pin]);
|
||||||
|
/* We need a 2-input OR gate, in order to tri-state the input
|
||||||
|
* Detailed circuit is as follow:
|
||||||
|
* +---------+
|
||||||
|
* SRAM --->| 2-input |----> mode_select_output_port
|
||||||
|
* LUT input--->| OR |
|
||||||
|
* +---------+
|
||||||
|
* When SRAM is set to logic 1, the LUT input is tri-stated
|
||||||
|
* When SRAM is set to logic 0, the LUT input is effective to the downstream circuits
|
||||||
|
*/
|
||||||
|
required_gate_type = SPICE_MODEL_GATE_OR;
|
||||||
|
}
|
||||||
|
/* Get the circuit model of the gate */
|
||||||
|
CircuitModelId gate_model = circuit_lib.port_tri_state_model(lut_input_ports[0]);
|
||||||
|
/* Check this is the gate we want ! */
|
||||||
|
VTR_ASSERT (required_gate_type == circuit_lib.gate_type(gate_model));
|
||||||
|
|
||||||
|
/* Prepare for the gate instanciation */
|
||||||
|
/* Get the input ports from the gate */
|
||||||
|
std::vector<CircuitPortId> gate_input_ports = circuit_lib.model_ports_by_type(gate_model, SPICE_MODEL_PORT_INPUT, true);
|
||||||
|
/* Get the output ports from the gate */
|
||||||
|
std::vector<CircuitPortId> gate_output_ports = circuit_lib.model_ports_by_type(gate_model, SPICE_MODEL_PORT_OUTPUT, true);
|
||||||
|
/* Check the port sizes and width:
|
||||||
|
* we should have only 2 input ports, each of which has a size of 1
|
||||||
|
* we should have only 1 output port, each of which has a size of 1
|
||||||
|
*/
|
||||||
|
VTR_ASSERT (2 == gate_input_ports.size());
|
||||||
|
for (const auto& port : gate_input_ports) {
|
||||||
|
VTR_ASSERT (1 == circuit_lib.port_size(port));
|
||||||
|
}
|
||||||
|
VTR_ASSERT (1 == gate_output_ports.size());
|
||||||
|
for (const auto& port : gate_output_ports) {
|
||||||
|
VTR_ASSERT (1 == circuit_lib.port_size(port));
|
||||||
|
}
|
||||||
|
/* Find the module id of gate_model in the module manager */
|
||||||
|
ModuleId gate_module_id = module_manager.find_module(circuit_lib.model_name(gate_model));
|
||||||
|
/* We must have a valid id */
|
||||||
|
VTR_ASSERT (ModuleId::INVALID() != gate_module_id);
|
||||||
|
/* Create a port-to-port map:
|
||||||
|
* Input[0] of the gate is wired to a SRAM mode-select port
|
||||||
|
* Input[1] of the gate is wired to the input port of LUT
|
||||||
|
* Output[0] of the gate is wired to the mode_select_output_port
|
||||||
|
*/
|
||||||
|
std::map<std::string, BasicPort> port2port_name_map;
|
||||||
|
port2port_name_map[circuit_lib.port_lib_name(gate_input_ports[0])] = cur_lut_mode_select_sram_port;
|
||||||
|
port2port_name_map[circuit_lib.port_lib_name(gate_input_ports[1])] = cur_input_port;
|
||||||
|
port2port_name_map[circuit_lib.port_lib_name(gate_output_ports[0])] = cur_mode_select_output_port;
|
||||||
|
|
||||||
|
/* Instanciate the gate */
|
||||||
|
print_verilog_module_instance(fp, module_manager, module_id, gate_module_id, port2port_name_map, circuit_lib.dump_explicit_port_map(circuit_model));
|
||||||
|
/* 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(module_id, gate_module_id);
|
||||||
|
/* update the lsb of mode select port size */
|
||||||
|
mode_select_port_lsb++;
|
||||||
|
}
|
||||||
|
print_verilog_comment(fp, std::string("---- END Instanciation of model-select gates -----"));
|
||||||
|
/* Sanitity check */
|
||||||
|
if ( true == circuit_lib.is_lut_fracturable(circuit_model) ) {
|
||||||
|
if (mode_select_port_lsb != circuit_lib.port_size(lut_mode_select_sram_ports[0])) {
|
||||||
|
vpr_printf(TIO_MESSAGE_ERROR,
|
||||||
|
"(FILE:%s,LINE[%d]) Circuit model LUT (name=%s) has a unmatched tri-state map (%s) implied by mode_port size(%d)!\n",
|
||||||
|
__FILE__, __LINE__,
|
||||||
|
circuit_lib.model_name(circuit_model).c_str(),
|
||||||
|
tri_state_map.c_str(),
|
||||||
|
circuit_lib.port_size(lut_mode_select_sram_ports[0]));
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add a blank-line splitter */
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
/* Add inverters to mode_select output ports */
|
||||||
|
print_verilog_comment(fp, std::string("---- BEGIN Instanciation of an input inverters modules -----"));
|
||||||
|
/* Find the circuit model of the input inverter */
|
||||||
|
CircuitModelId input_inverter_model = circuit_lib.lut_input_inverter_model(circuit_model);
|
||||||
|
VTR_ASSERT( CircuitModelId::INVALID() != input_inverter_model );
|
||||||
|
/* Now we need to add inverters by instanciating the modules */
|
||||||
|
for (const auto& pin : circuit_lib.pins(lut_input_ports[0])) {
|
||||||
|
/* Input of inverter is the output of mode select circuits */
|
||||||
|
BasicPort inverter_instance_input_port(mode_select_output_port.get_name(), pin, pin);
|
||||||
|
/* Output of inverter is the inverted input port */
|
||||||
|
BasicPort inverter_instance_output_port(inverted_input_port.get_name(), pin, pin);
|
||||||
|
|
||||||
|
print_verilog_buffer_instance(fp, module_manager, circuit_lib, module_id, input_inverter_model, inverter_instance_input_port, inverter_instance_output_port);
|
||||||
|
}
|
||||||
|
print_verilog_comment(fp, std::string("---- END Instanciation of an input inverters modules -----"));
|
||||||
|
|
||||||
|
/* Add buffers to mode_select output ports */
|
||||||
|
print_verilog_comment(fp, std::string("---- BEGIN Instanciation of an input buffer modules -----"));
|
||||||
|
/* Find the circuit model of the input inverter */
|
||||||
|
CircuitModelId input_buffer_model = circuit_lib.lut_input_buffer_model(circuit_model);
|
||||||
|
VTR_ASSERT( CircuitModelId::INVALID() != input_buffer_model );
|
||||||
|
/* Now we need to add inverters by instanciating the modules */
|
||||||
|
for (const auto& pin : circuit_lib.pins(lut_input_ports[0])) {
|
||||||
|
/* Input of inverter is the output of mode select circuits */
|
||||||
|
BasicPort buffer_instance_input_port(mode_select_output_port.get_name(), pin, pin);
|
||||||
|
/* Output of inverter is the inverted input port */
|
||||||
|
BasicPort buffer_instance_output_port(buffered_input_port.get_name(), pin, pin);
|
||||||
|
|
||||||
|
print_verilog_buffer_instance(fp, module_manager, circuit_lib, module_id, input_buffer_model, buffer_instance_input_port, buffer_instance_output_port);
|
||||||
|
}
|
||||||
|
print_verilog_comment(fp, std::string("---- END Instanciation of an input buffer modules -----"));
|
||||||
|
|
||||||
|
/* Instanciate the multiplexing structure for the LUT */
|
||||||
|
print_verilog_comment(fp, std::string("---- BEGIN Instanciation of LUT multiplexer module -----"));
|
||||||
|
/* Find the name of LUT MUX: no need to provide a mux size, just give an invalid number (=-1) */
|
||||||
|
std::string lut_mux_module_name = generate_verilog_mux_subckt_name(circuit_lib, circuit_model, size_t(-1), std::string(""));
|
||||||
|
/* Find the module id of LUT MUX in the module manager */
|
||||||
|
ModuleId lut_mux_module_id = module_manager.find_module(lut_mux_module_name);
|
||||||
|
/* We must have a valid id */
|
||||||
|
VTR_ASSERT (ModuleId::INVALID() != lut_mux_module_id);
|
||||||
|
/* Create a port-to-port map:
|
||||||
|
* Input of the LUT MUX is wired to a regular SRAM port of LUT
|
||||||
|
* Outputs of the LUT MUX is wired to the output ports of LUT by name
|
||||||
|
* SRAM of the LUT MUX is wired to the buffered input port of LUT
|
||||||
|
* SRAM_inv of the LUT MUX is wired to the inverted input port of LUT
|
||||||
|
*/
|
||||||
|
std::map<std::string, BasicPort> port2port_name_map;
|
||||||
|
port2port_name_map[circuit_lib.port_lib_name(lut_input_ports[0])] = BasicPort(circuit_lib.port_lib_name(lut_regular_sram_ports[0]), circuit_lib.port_size(lut_regular_sram_ports[0]));
|
||||||
|
/* Skip the output ports, if we do not need a new name for the port of instance */
|
||||||
|
port2port_name_map[circuit_lib.port_lib_name(lut_regular_sram_ports[0])] = buffered_input_port;
|
||||||
|
/* TODO: be more flexible in naming !!! */
|
||||||
|
port2port_name_map[std::string(circuit_lib.port_lib_name(lut_regular_sram_ports[0]) + "_inv")] = inverted_input_port;
|
||||||
|
|
||||||
|
/* Instanciate the gate */
|
||||||
|
print_verilog_module_instance(fp, module_manager, module_id, lut_mux_module_id, port2port_name_map, circuit_lib.dump_explicit_port_map(circuit_model));
|
||||||
|
/* 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(module_id, lut_mux_module_id);
|
||||||
|
|
||||||
|
/* Print timing info */
|
||||||
|
print_verilog_submodule_timing(fp, circuit_lib, circuit_model);
|
||||||
|
|
||||||
|
/* Print signal initialization */
|
||||||
|
print_verilog_submodule_signal_init(fp, circuit_lib, circuit_model);
|
||||||
|
|
||||||
|
/* Put an end to the Verilog module */
|
||||||
|
print_verilog_module_end(fp, circuit_lib.model_name(circuit_model));
|
||||||
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Print Verilog modules for the Look-Up Tables (LUTs)
|
||||||
|
* in the circuit library
|
||||||
|
********************************************************************/
|
||||||
|
void print_verilog_submodule_luts(ModuleManager& module_manager,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const std::string& verilog_dir,
|
||||||
|
const std::string& submodule_dir) {
|
||||||
|
/* TODO: remove .bak when this part is completed and tested */
|
||||||
|
std::string verilog_fname = submodule_dir + luts_verilog_file_name + ".bak";
|
||||||
|
|
||||||
|
std::fstream fp;
|
||||||
|
|
||||||
|
/* Create the file stream */
|
||||||
|
fp.open(verilog_fname, std::fstream::out | std::fstream::trunc);
|
||||||
|
/* Check if the file stream if valid or not */
|
||||||
|
check_file_handler(fp);
|
||||||
|
|
||||||
|
/* Create file */
|
||||||
|
vpr_printf(TIO_MESSAGE_INFO,
|
||||||
|
"Generating Verilog netlist for LUTs (%s)...\n",
|
||||||
|
__FILE__, __LINE__, verilog_fname.c_str());
|
||||||
|
|
||||||
|
print_verilog_file_header(fp, "Look-Up Tables");
|
||||||
|
|
||||||
|
print_verilog_include_defines_preproc_file(fp, verilog_dir);
|
||||||
|
|
||||||
|
/* Search for each LUT circuit model */
|
||||||
|
for (const auto& circuit_model : circuit_lib.models()) {
|
||||||
|
/* Bypass user-defined and non-LUT modules */
|
||||||
|
if ( (!circuit_lib.model_verilog_netlist(circuit_model).empty())
|
||||||
|
|| (SPICE_MODEL_LUT != circuit_lib.model_type(circuit_model)) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
print_verilog_submodule_lut(module_manager, circuit_lib, fp, circuit_model);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close the file handler */
|
||||||
|
fp.close();
|
||||||
|
|
||||||
|
/* Add fname to the linked list */
|
||||||
|
/* Add it when the Verilog generation is refactored
|
||||||
|
submodule_verilog_subckt_file_path_head = add_one_subckt_file_name_to_llist(submodule_verilog_subckt_file_path_head, verilog_fname.c_str());
|
||||||
|
*/
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
/***********************************************
|
||||||
|
* Header file for verilog_lut.cpp
|
||||||
|
**********************************************/
|
||||||
|
|
||||||
|
#ifndef VERILOG_LUT_H
|
||||||
|
#define VERILOG_LUT_H
|
||||||
|
|
||||||
|
/* Include other header files which are dependency on the function declared below */
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include "circuit_library.h"
|
||||||
|
#include "module_manager.h"
|
||||||
|
|
||||||
|
void print_verilog_submodule_luts(ModuleManager& module_manager,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const std::string& verilog_dir,
|
||||||
|
const std::string& submodule_dir);
|
||||||
|
|
||||||
|
#endif
|
|
@ -43,6 +43,7 @@
|
||||||
#include "verilog_mux.h"
|
#include "verilog_mux.h"
|
||||||
#include "verilog_essential_gates.h"
|
#include "verilog_essential_gates.h"
|
||||||
#include "verilog_decoders.h"
|
#include "verilog_decoders.h"
|
||||||
|
#include "verilog_lut.h"
|
||||||
|
|
||||||
/***** Subroutines *****/
|
/***** Subroutines *****/
|
||||||
|
|
||||||
|
@ -3344,6 +3345,7 @@ void dump_verilog_submodules(ModuleManager& module_manager,
|
||||||
fpga_verilog_opts.include_timing,
|
fpga_verilog_opts.include_timing,
|
||||||
fpga_verilog_opts.include_signal_init,
|
fpga_verilog_opts.include_signal_init,
|
||||||
fpga_verilog_opts.dump_explicit_verilog);
|
fpga_verilog_opts.dump_explicit_verilog);
|
||||||
|
print_verilog_submodule_luts(module_manager, Arch.spice->circuit_lib, std::string(verilog_dir), std::string(submodule_dir));
|
||||||
|
|
||||||
/* 3. Hardwires */
|
/* 3. Hardwires */
|
||||||
vpr_printf(TIO_MESSAGE_INFO, "Generating modules of hardwires...\n");
|
vpr_printf(TIO_MESSAGE_INFO, "Generating modules of hardwires...\n");
|
||||||
|
|
Loading…
Reference in New Issue