refactored local encoder support for Verilog MUX generation

This commit is contained in:
tangxifan 2019-09-27 23:10:43 -06:00
parent 4da5035627
commit 433fc73460
11 changed files with 173 additions and 46 deletions

View File

@ -54,8 +54,8 @@
* Get the model id of a SRAM model that is used to configure
* a circuit model
*******************************************************************/
std::vector<CircuitModelId> get_circuit_sram_models(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model) {
std::vector<CircuitModelId> find_circuit_sram_models(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model) {
/* SRAM model id is stored in the sram ports of a circuit model */
std::vector<CircuitPortId> sram_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_SRAM);
std::vector<CircuitModelId> sram_models;
@ -73,3 +73,21 @@ std::vector<CircuitModelId> get_circuit_sram_models(const CircuitLibrary& circui
return sram_models;
}
/********************************************************************
* Find regular (not mode select) sram ports of a circuit model
*******************************************************************/
std::vector<CircuitPortId> find_circuit_regular_sram_ports(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model) {
std::vector<CircuitPortId> sram_ports = circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_SRAM, true);
std::vector<CircuitPortId> regular_sram_ports;
for (const auto& port : sram_ports) {
if (true == circuit_lib.port_is_mode_select(port)) {
continue;
}
regular_sram_ports.push_back(port);
}
return regular_sram_ports;
}

View File

@ -10,7 +10,10 @@
#include <vector>
#include "circuit_library.h"
std::vector<CircuitModelId> get_circuit_sram_models(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model);
std::vector<CircuitModelId> find_circuit_sram_models(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model);
std::vector<CircuitPortId> find_circuit_regular_sram_ports(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model);
#endif

View File

@ -136,10 +136,14 @@ void BasicPort::revert() {
/* rotate: increase both lsb and msb by an offset */
bool BasicPort::rotate(const size_t& offset) {
/* If current port is invalid or offset is 0,
* we do nothing
*/
if ((0 == offset) || (0 == get_width())) {
/* If offset is 0, we do nothing */
if (0 == offset) {
return true;
}
/* If current width is 0, we set a width using the offset! */
if (0 == get_width()) {
set_width(offset);
return true;
}
/* check if leads to overflow:

View File

@ -27,12 +27,14 @@
* We plus 1, which is all-zero condition for outputs
***************************************************************************************/
size_t find_mux_local_decoder_addr_size(const size_t& data_size) {
/* Make sure we have a encoder which is at least 2 ! */
/* if data size is 1, it is an corner case for the decoder (addr = 1) */
if (1 == data_size) {
return 1;
}
VTR_ASSERT (2 <= data_size);
return ceil(log(data_size) / log(2));
}
/***************************************************************************************
* Try to find if the decoder already exists in the library,
* If there is no such decoder, add it to the library

View File

@ -6,6 +6,8 @@
#include "decoder_library.h"
bool need_mux_local_decoder(const size_t& data_size);
size_t find_mux_local_decoder_addr_size(const size_t& data_size);
DecoderId add_mux_local_decoder_to_library(DecoderLibrary& decoder_lib,

View File

@ -332,6 +332,33 @@ std::string generate_configuration_chain_tail_name() {
return std::string("ccff_tail");
}
/*********************************************************************
* Generate the addr port (input) for a local decoder of a multiplexer
* TODO: This could be replaced as a constexpr string
*********************************************************************/
std::string generate_mux_local_decoder_addr_port_name() {
return std::string("addr");
}
/*********************************************************************
* Generate the data port (output) for a local decoder of a multiplexer
* TODO: This could be replaced as a constexpr string
*********************************************************************/
std::string generate_mux_local_decoder_data_port_name() {
return std::string("data");
}
/*********************************************************************
* Generate the inverted data port (output) for a local decoder of a multiplexer
* TODO: This could be replaced as a constexpr string
*********************************************************************/
std::string generate_mux_local_decoder_data_inv_port_name() {
return std::string("data_inv");
}
/*********************************************************************
* Generate the port name for a regular sram port which appears in the
* port list of a module

View File

@ -76,6 +76,12 @@ std::string generate_configuration_chain_head_name();
std::string generate_configuration_chain_tail_name();
std::string generate_mux_local_decoder_addr_port_name();
std::string generate_mux_local_decoder_data_port_name();
std::string generate_mux_local_decoder_data_inv_port_name();
std::string generate_sram_port_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const e_sram_orgz& sram_orgz_type,

View File

@ -59,17 +59,17 @@ void print_verilog_mux_local_decoder_module(std::fstream& fp,
VTR_ASSERT(ModuleId::INVALID() != module_id);
/* Add module ports */
/* Add each input port */
BasicPort addr_port("addr", addr_size);
BasicPort addr_port(generate_mux_local_decoder_addr_port_name(), addr_size);
module_manager.add_port(module_id, addr_port, ModuleManager::MODULE_INPUT_PORT);
/* Add each output port */
BasicPort data_port("data", data_size);
BasicPort data_port(generate_mux_local_decoder_data_port_name(), data_size);
module_manager.add_port(module_id, data_port, ModuleManager::MODULE_OUTPUT_PORT);
/* Data port is registered. It should be outputted as
* output reg [lsb:msb] data
*/
module_manager.set_port_is_register(module_id, data_port.get_name(), true);
/* Add data_in port */
BasicPort data_inv_port("data_inv", data_size);
BasicPort data_inv_port(generate_mux_local_decoder_data_inv_port_name(), data_size);
VTR_ASSERT(true == decoder_lib.use_data_inv_port(decoder));
module_manager.add_port(module_id, data_inv_port, ModuleManager::MODULE_OUTPUT_PORT);
@ -81,6 +81,20 @@ void print_verilog_mux_local_decoder_module(std::fstream& fp,
/* Print the truth table of this decoder */
/* Internal logics */
/* Early exit: Corner case for data size = 1 the logic is very simple:
* data = addr;
* data_inv = ~data_inv
*/
if (1 == data_size) {
print_verilog_wire_connection(fp, addr_port, data_port, false);
print_verilog_wire_connection(fp, data_inv_port, data_port, true);
print_verilog_comment(fp, std::string("----- END Verilog codes for Decoder convert " + std::to_string(addr_size) + "-bit addr to " + std::to_string(data_size) + "-bit data -----"));
/* Put an end to the Verilog module */
print_verilog_module_end(fp, module_name);
return;
}
/* We use a magic number -1 as the addr=1 should be mapped to ...1
* Otherwise addr will map addr=1 to ..10
* Note that there should be a range for the shift operators
@ -194,7 +208,7 @@ void print_verilog_submodule_mux_local_decoders(ModuleManager& module_manager,
* Note that only when there are >=2 memories, a decoder is needed
*/
size_t decoder_data_size = branch_mux_graph.num_memory_bits();
if (2 > decoder_data_size) {
if (0 == decoder_data_size) {
continue;
}
/* Try to find if the decoder already exists in the library,

View File

@ -442,7 +442,7 @@ void print_verilog_mux_memory_module(ModuleManager& module_manager,
std::string(verilog_mem_posfix));
/* Get the sram ports from the mux */
std::vector<CircuitModelId> sram_models = get_circuit_sram_models(circuit_lib, mux_model);
std::vector<CircuitModelId> sram_models = find_circuit_sram_models(circuit_lib, mux_model);
VTR_ASSERT( 1 == sram_models.size() );
/* Find the number of SRAMs in the module, this is also the port width */

View File

@ -17,6 +17,8 @@
#include "physical_types.h"
#include "vpr_types.h"
#include "mux_utils.h"
#include "circuit_library_utils.h"
#include "decoder_library_utils.h"
/* FPGA-X2P context header files */
#include "spice_types.h"
@ -853,6 +855,10 @@ void generate_verilog_cmos_mux_module_mux2_multiplexing_structure(ModuleManager&
/* Generate the port info of each mem node */
BasicPort instance_mem_port(circuit_lib.port_lib_name(mux_regular_sram_ports[0]), size_t(mem), size_t(mem));
std::string module_mem_port_name = circuit_lib.port_lib_name(std_cell_input_ports[2]);
/* If use local decoders, we should use another name for the mem port */
if (true == circuit_lib.mux_use_local_encoder(circuit_model)) {
instance_mem_port.set_name(generate_mux_local_decoder_data_port_name());
}
port2port_name_map[module_mem_port_name] = instance_mem_port;
}
@ -910,19 +916,8 @@ void generate_verilog_cmos_mux_module_tgate_multiplexing_structure(ModuleManager
/* Find the actual mux size */
size_t mux_size = find_mux_num_datapath_inputs(circuit_lib, circuit_model, mux_graph.num_inputs());
/* TODO: these are duplicated codes, find a way to simplify it!!!
* Get the regular (non-mode-select) sram ports from the mux
*/
std::vector<CircuitPortId> mux_regular_sram_ports;
for (const auto& port : circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_SRAM, true)) {
/* 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;
}
mux_regular_sram_ports.push_back(port);
}
/* 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);
VTR_ASSERT(1 == mux_regular_sram_ports.size());
/* Build the location map of intermediate buffers */
@ -1035,6 +1030,10 @@ void generate_verilog_cmos_mux_module_tgate_multiplexing_structure(ModuleManager
for (const auto& mem : mems) {
/* Generate the port info of each mem node */
BasicPort branch_node_mem_port(circuit_lib.port_lib_name(mux_regular_sram_ports[0]), size_t(mem), size_t(mem));
/* If use local decoders, we should use another name for the mem port */
if (true == circuit_lib.mux_use_local_encoder(circuit_model)) {
branch_node_mem_port.set_name(generate_mux_local_decoder_data_port_name());
}
branch_node_mem_ports.push_back(branch_node_mem_port);
}
@ -1065,6 +1064,10 @@ void generate_verilog_cmos_mux_module_tgate_multiplexing_structure(ModuleManager
for (const auto& mem : mems) {
/* Generate the port info of each mem node */
BasicPort branch_node_mem_inv_port(circuit_lib.port_lib_name(mux_regular_sram_ports[0]) + "_inv", size_t(mem), size_t(mem));
/* If use local decoders, we should use another name for the mem port */
if (true == circuit_lib.mux_use_local_encoder(circuit_model)) {
branch_node_mem_inv_port.set_name(generate_mux_local_decoder_data_inv_port_name());
}
branch_node_mem_inv_ports.push_back(branch_node_mem_inv_port);
}
@ -1315,8 +1318,11 @@ void generate_verilog_cmos_mux_module(ModuleManager& module_manager,
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);
/* Get the sram ports from the mux
* Multiplexing structure does not mode_sram_ports, they are handled in LUT modules
* Here we just bypass it.
*/
std::vector<CircuitPortId> mux_sram_ports = find_circuit_regular_sram_ports(circuit_lib, circuit_model);
/* Make sure we have a valid file handler*/
check_file_handler(fp);
@ -1329,6 +1335,18 @@ void generate_verilog_cmos_mux_module(ModuleManager& module_manager,
/* Find out the number of memory bits */
size_t num_mems = mux_graph.num_memory_bits();
/* The size of of memory ports depend on
* if a local encoder is used for the mux or not
* Multiplexer local encoders are applied to memory bits at each stage
*/
if (true == circuit_lib.mux_use_local_encoder(circuit_model)) {
num_mems = 0;
for (const auto& lvl : mux_graph.levels()) {
size_t data_size = mux_graph.num_memory_bits_at_level(lvl);
num_mems += find_mux_local_decoder_addr_size(data_size);
}
}
/* 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());
@ -1381,18 +1399,8 @@ void generate_verilog_cmos_mux_module(ModuleManager& module_manager,
module_manager.add_port(module_id, output_port, ModuleManager::MODULE_OUTPUT_PORT);
}
/* TODO: the size of of memory ports depend on
* if a local encoder is used for the mux or not
*/
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);
@ -1400,11 +1408,56 @@ void generate_verilog_cmos_mux_module(ModuleManager& module_manager,
/* Update counter */
sram_port_cnt++;
}
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 */
/* Add local decoder instance here */
if (true == circuit_lib.mux_use_local_encoder(circuit_model)) {
BasicPort decoder_data_port(generate_mux_local_decoder_data_port_name(), mux_graph.num_memory_bits());
BasicPort decoder_data_inv_port(generate_mux_local_decoder_data_inv_port_name(), mux_graph.num_memory_bits());
/* Print local wires to bridge the port of module and memory inputs
* of each MUX branch instance
*/
fp << generate_verilog_port(VERILOG_PORT_WIRE, decoder_data_port) << ";" << std::endl;
fp << generate_verilog_port(VERILOG_PORT_WIRE, decoder_data_inv_port) << ";" << std::endl;
/* Local port to record the LSB and MSB of each level, here, we deposite (0, 0) */
BasicPort lvl_addr_port(circuit_lib.port_lib_name(mux_sram_ports[0]), 0);
BasicPort lvl_data_port(decoder_data_port.get_name(), 0);
BasicPort lvl_data_inv_port(decoder_data_inv_port.get_name(), 0);
for (const auto& lvl : mux_graph.levels()) {
size_t addr_size = find_mux_local_decoder_addr_size(mux_graph.num_memory_bits_at_level(lvl));
size_t data_size = mux_graph.num_memory_bits_at_level(lvl);
/* Update the LSB and MSB of addr and data port for the current level */
lvl_addr_port.rotate(addr_size);
lvl_data_port.rotate(data_size);
lvl_data_inv_port.rotate(data_size);
/* Print the instance of local decoder */
std::string decoder_module_name = generate_mux_local_decoder_subckt_name(addr_size, data_size);
ModuleId decoder_module = module_manager.find_module(decoder_module_name);
VTR_ASSERT(ModuleId::INVALID() != decoder_module);
/* Create a port-to-port map */
std::map<std::string, BasicPort> decoder_port2port_name_map;
decoder_port2port_name_map[generate_mux_local_decoder_addr_port_name()] = lvl_addr_port;
decoder_port2port_name_map[generate_mux_local_decoder_data_port_name()] = lvl_data_port;
decoder_port2port_name_map[generate_mux_local_decoder_data_inv_port_name()] = lvl_data_inv_port;
/* Print an instance of the MUX Module */
print_verilog_comment(fp, std::string("----- BEGIN Instanciation of a local decoder -----"));
print_verilog_module_instance(fp, module_manager, module_id, decoder_module, decoder_port2port_name_map, circuit_lib.dump_explicit_port_map(circuit_model));
print_verilog_comment(fp, std::string("----- END Instanciation of a local decoder -----"));
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(module_id, decoder_module);
}
}
/* Print the internal logic in Verilog codes */
/* Print the Multiplexing structure in Verilog codes
* Separated generation strategy on using standard cell MUX2 or TGATE,
* 1. MUX2 has a fixed port map: input_port[0] and input_port[1] is the data_path input
@ -1430,8 +1483,6 @@ void generate_verilog_cmos_mux_module(ModuleManager& module_manager,
generate_verilog_cmos_mux_module_input_buffers(module_manager, circuit_lib, fp, module_id, circuit_model, mux_graph);
generate_verilog_cmos_mux_module_output_buffers(module_manager, circuit_lib, fp, module_id, circuit_model, mux_graph);
/* TODO: add local decoder instance here */
/* Put an end to the Verilog module */
print_verilog_module_end(fp, module_name);
}

View File

@ -872,7 +872,7 @@ void print_verilog_cmos_mux_config_bus(std::fstream& fp,
fp << generate_verilog_port(VERILOG_PORT_WIRE, inverted_sram_output_bus) << ";" << std::endl;
/* Get the SRAM model of the mux_model */
std::vector<CircuitModelId> sram_models = get_circuit_sram_models(circuit_lib, mux_model);
std::vector<CircuitModelId> sram_models = find_circuit_sram_models(circuit_lib, mux_model);
/* TODO: maybe later multiplexers may have mode select ports... This should be relaxed */
VTR_ASSERT( 1 == sram_models.size() );
std::vector<CircuitPortId> blb_ports = circuit_lib.model_ports_by_type(sram_models[0], SPICE_MODEL_PORT_BLB);
@ -998,7 +998,7 @@ void print_verilog_rram_mux_config_bus(std::fstream& fp,
fp << generate_verilog_port(VERILOG_PORT_WIRE, inverted_sram_output_bus) << ";" << std::endl;
/* Get the SRAM model of the mux_model */
std::vector<CircuitModelId> sram_models = get_circuit_sram_models(circuit_lib, mux_model);
std::vector<CircuitModelId> sram_models = find_circuit_sram_models(circuit_lib, mux_model);
/* TODO: maybe later multiplexers may have mode select ports... This should be relaxed */
VTR_ASSERT( 1 == sram_models.size() );
@ -1078,7 +1078,7 @@ void print_verilog_formal_verification_mux_sram_ports_wiring(std::fstream& fp,
BasicPort mux_sram_output(generate_mux_sram_port_name(circuit_lib, mux_model, mux_size, mux_instance_id, SPICE_MODEL_PORT_INPUT),
num_conf_bits);
/* Get the SRAM model of the mux_model */
std::vector<CircuitModelId> sram_models = get_circuit_sram_models(circuit_lib, mux_model);
std::vector<CircuitModelId> sram_models = find_circuit_sram_models(circuit_lib, mux_model);
/* TODO: maybe later multiplexers may have mode select ports... This should be relaxed */
VTR_ASSERT( 1 == sram_models.size() );
BasicPort formal_verification_port(generate_formal_verification_sram_port_name(circuit_lib, sram_models[0]),