Merge remote-tracking branch 'origin/dev' into heterogeneous

This commit is contained in:
AurelienUoU 2019-09-30 10:02:11 -06:00
commit fdc3c5e4a9
21 changed files with 924 additions and 388 deletions

View File

@ -1875,7 +1875,7 @@ void CircuitLibrary::build_submodels() {
/* Build a unique list */
for (const auto& cand : candidates) {
/* Make sure the model id is unique in the list */
if (true == is_unique_submodel(model,cand)) {
if (true == is_unique_submodel(model, cand)) {
sub_models_[model].push_back(cand);
}
}

View File

@ -453,8 +453,8 @@ class CircuitLibrary {
void link_buffer_model(const CircuitModelId& model_id);
void link_pass_gate_logic_model(const CircuitModelId& model_id);
bool is_unique_submodel(const CircuitModelId& model_id, const CircuitModelId& submodel_id);
void build_submodels();
void build_model_timing_graph(const CircuitModelId& model_id);
void build_submodels();
public: /* Public Mutators: builders */
void build_model_links();
void build_timing_graphs();

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

@ -9,6 +9,7 @@
#include "sides.h"
#include "fpga_x2p_utils.h"
#include "circuit_library_utils.h"
#include "fpga_x2p_naming.h"
/************************************************
@ -18,8 +19,8 @@
* Case 1 : If there is NO intermediate buffer followed by,
* the node name will be mux_l<node_level>_in
***********************************************/
std::string generate_verilog_mux_node_name(const size_t& node_level,
const bool& add_buffer_postfix) {
std::string generate_mux_node_name(const size_t& node_level,
const bool& add_buffer_postfix) {
/* Generate the basic node_name */
std::string node_name = "mux_l" + std::to_string(node_level) + "_in";
@ -38,10 +39,10 @@ std::string generate_verilog_mux_node_name(const size_t& node_level,
* 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 generate_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);
/* Check the model type and give different names */
if (SPICE_MODEL_MUX == circuit_lib.model_type(circuit_model)) {
@ -64,11 +65,11 @@ std::string generate_verilog_mux_subckt_name(const CircuitLibrary& circuit_lib,
* Generate the module name of a branch for a
* multiplexer in Verilog format
***********************************************/
std::string generate_verilog_mux_branch_subckt_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model,
const size_t& mux_size,
const size_t& branch_mux_size,
const std::string& postfix) {
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 std::string& postfix) {
/* If the tgate spice model of this MUX is a MUX2 standard cell,
* the mux_subckt name will be the name of the standard cell
*/
@ -79,7 +80,7 @@ std::string generate_verilog_mux_branch_subckt_name(const CircuitLibrary& circui
}
std::string branch_postfix = postfix + "_size" + std::to_string(branch_mux_size);
return generate_verilog_mux_subckt_name(circuit_lib, circuit_model, mux_size, branch_postfix);
return generate_mux_subckt_name(circuit_lib, circuit_model, mux_size, branch_postfix);
}
/************************************************
@ -315,6 +316,70 @@ std::string generate_formal_verification_sram_port_name(const CircuitLibrary& ci
return port_name;
}
/*********************************************************************
* Generate the head port name of a configuration chain
* TODO: This could be replaced as a constexpr string
*********************************************************************/
std::string generate_configuration_chain_head_name() {
return std::string("ccff_head");
}
/*********************************************************************
* Generate the tail port name of a configuration chain
* TODO: This could be replaced as a constexpr string
*********************************************************************/
std::string generate_configuration_chain_tail_name() {
return std::string("ccff_tail");
}
/*********************************************************************
* Generate the memory output port name of a configuration chain
* TODO: This could be replaced as a constexpr string
*********************************************************************/
std::string generate_configuration_chain_data_out_name() {
return std::string("mem_out");
}
/*********************************************************************
* Generate the inverted memory output port name of a configuration chain
* TODO: This could be replaced as a constexpr string
*********************************************************************/
std::string generate_configuration_chain_inverted_data_out_name() {
return std::string("mem_outb");
}
/*********************************************************************
* 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 of a local configuration bus
* TODO: This could be replaced as a constexpr string
*********************************************************************/
std::string generate_local_config_bus_port_name() {
return std::string("config_bus");
}
/*********************************************************************
* Generate the port name for a regular sram port which appears in the
* port list of a module
@ -473,7 +538,7 @@ std::string generate_mux_input_bus_port_name(const CircuitLibrary& circuit_lib,
const size_t& mux_size,
const size_t& mux_instance_id) {
std::string postfix = std::string("_") + std::to_string(mux_instance_id) + std::string("_inbus");
return generate_verilog_mux_subckt_name(circuit_lib, mux_model, mux_size, postfix);
return generate_mux_subckt_name(circuit_lib, mux_model, mux_size, postfix);
}
/*********************************************************************
@ -492,7 +557,29 @@ std::string generate_mux_config_bus_port_name(const CircuitLibrary& circuit_lib,
postfix += std::string("_b");
}
return generate_verilog_mux_subckt_name(circuit_lib, mux_model, mux_size, postfix);
return generate_mux_subckt_name(circuit_lib, mux_model, mux_size, postfix);
}
/*********************************************************************
* Generate the port name for a SRAM port of a circuit
* This name is used for local wires that connecting SRAM ports
* of a circuit model inside a Verilog/SPICE module
* Note that the SRAM ports share the same naming
* convention regardless of their configuration style
*********************************************************************/
std::string generate_local_sram_port_name(const std::string& port_prefix,
const size_t& instance_id,
const e_spice_model_port_type& port_type) {
std::string port_name = port_prefix + std::string("_") + std::to_string(instance_id) + std::string("_");
if (SPICE_MODEL_PORT_INPUT == port_type) {
port_name += std::string("out");
} else {
VTR_ASSERT( SPICE_MODEL_PORT_OUTPUT == port_type );
port_name += std::string("outb");
}
return port_name;
}
/*********************************************************************
@ -501,21 +588,12 @@ std::string generate_mux_config_bus_port_name(const CircuitLibrary& circuit_lib,
* of routing multiplexers inside a Verilog/SPICE module
* Note that the SRAM ports of routing multiplexers share the same naming
* convention regardless of their configuration style
*********************************************************************/
**********************************************************************/
std::string generate_mux_sram_port_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const size_t& mux_size,
const size_t& mux_instance_id,
const e_spice_model_port_type& port_type) {
std::string postfix = std::string("_") + std::to_string(mux_instance_id) + std::string("_");
if (SPICE_MODEL_PORT_INPUT == port_type) {
postfix += std::string("out");
} else {
VTR_ASSERT( SPICE_MODEL_PORT_OUTPUT == port_type );
postfix += std::string("outb");
}
return generate_verilog_mux_subckt_name(circuit_lib, mux_model, mux_size, postfix);
std::string prefix = generate_mux_subckt_name(circuit_lib, mux_model, mux_size, std::string());
return generate_local_sram_port_name(prefix, mux_instance_id, port_type);
}

View File

@ -13,19 +13,19 @@
#include "circuit_library.h"
#include "vpr_types.h"
std::string generate_verilog_mux_node_name(const size_t& node_level,
const bool& add_buffer_postfix);
std::string generate_mux_node_name(const size_t& node_level,
const bool& add_buffer_postfix);
std::string generate_verilog_mux_subckt_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model,
const size_t& mux_size,
const std::string& posfix) ;
std::string generate_mux_subckt_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model,
const size_t& mux_size,
const std::string& posfix) ;
std::string generate_verilog_mux_branch_subckt_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model,
const size_t& mux_size,
const size_t& branch_mux_size,
const std::string& posfix);
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 std::string& posfix);
std::string generate_mux_local_decoder_subckt_name(const size_t& addr_size,
const size_t& data_size);
@ -72,6 +72,22 @@ std::string generate_reserved_sram_port_name(const e_spice_model_port_type& port
std::string generate_formal_verification_sram_port_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model);
std::string generate_configuration_chain_head_name();
std::string generate_configuration_chain_tail_name();
std::string generate_configuration_chain_data_out_name();
std::string generate_configuration_chain_inverted_data_out_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_local_config_bus_port_name();
std::string generate_sram_port_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const e_sram_orgz& sram_orgz_type,
@ -93,6 +109,10 @@ std::string generate_mux_config_bus_port_name(const CircuitLibrary& circuit_lib,
const size_t& bus_id,
const bool& inverted);
std::string generate_local_sram_port_name(const std::string& port_prefix,
const size_t& instance_id,
const e_spice_model_port_type& port_type);
std::string generate_mux_sram_port_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const size_t& mux_size,

View File

@ -3179,6 +3179,10 @@ void config_circuit_models_sram_port_to_default_sram_model(CircuitLibrary& circu
}
}
}
/* TODO: this should be done right after XML parsing!!!
* Rebuild the submodels for circuit_library, because we have created links for ports
*/
circuit_lib.build_model_links();
}
void determine_sb_port_coordinator(t_sb cur_sb_info, int side,

View File

@ -209,3 +209,151 @@ void add_sram_ports_to_module_manager(ModuleManager& module_manager,
module_manager.add_port(module_id, module_port, module_port_types[iport]);
}
}
/*********************************************************************
* Create a port-to-port map for a CMOS memory module
*
* Configuration Chain
* -------------------
*
* config_bus (head) config_bus (tail)
* | ^
* v |
* +-------------------------------------+
* | CMOS-based Memory Module |
* +-------------------------------------+
* | |
* v v
* sram_out sram_outb
*
*
* Memory bank
* -----------
*
* config_bus (BL) config_bus (WL)
* | |
* v v
* +-------------------------------------+
* | CMOS-based Memory Module |
* +-------------------------------------+
* | |
* v v
* sram_out sram_outb
*
**********************************************************************/
static
std::map<std::string, BasicPort> generate_cmos_mem_module_port2port_map(const ModuleManager& module_manager,
const ModuleId& mem_module,
const std::vector<BasicPort>& config_bus_ports,
const std::vector<BasicPort>& mem_output_bus_ports,
const e_sram_orgz& sram_orgz_type) {
std::map<std::string, BasicPort> port2port_name_map;
switch (sram_orgz_type) {
case SPICE_SRAM_STANDALONE:
/* Nothing to do */
break;
case SPICE_SRAM_SCAN_CHAIN: {
/* Link the head port of the memory module:
* the LSB of config bus port is the head port index
*/
VTR_ASSERT( 1 == config_bus_ports.size() );
BasicPort head_port(config_bus_ports[0].get_name(), config_bus_ports[0].get_lsb(), config_bus_ports[0].get_lsb());
port2port_name_map[generate_configuration_chain_head_name()] = head_port;
/* Link the tail port of the memory module:
* the MSB of config bus port is the tail port index
*/
BasicPort tail_port(config_bus_ports[0].get_name(), config_bus_ports[0].get_msb(), config_bus_ports[0].get_msb());
port2port_name_map[generate_configuration_chain_tail_name()] = tail_port;
/* Link the SRAM output ports of the memory module */
VTR_ASSERT( 2 == mem_output_bus_ports.size() );
port2port_name_map[generate_configuration_chain_data_out_name()] = mem_output_bus_ports[0];
port2port_name_map[generate_configuration_chain_inverted_data_out_name()] = mem_output_bus_ports[1];
break;
}
case SPICE_SRAM_MEMORY_BANK:
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s,[LINE%d])Invalid type of SRAM organization!\n",
__FILE__, __LINE__);
exit(1);
}
return port2port_name_map;
}
/*********************************************************************
* Create a port-to-port map for a ReRAM-based memory module
* Memory bank
* -----------
*
* config_bus (BL) config_bus (WL)
* | |
* v v
* +-------------------------------------+
* | ReRAM-based Memory Module |
* +-------------------------------------+
* | |
* v v
* Mem_out Mem_outb
**********************************************************************/
static
std::map<std::string, BasicPort> generate_rram_mem_module_port2port_map(const ModuleManager& module_manager,
const ModuleId& mem_module,
const e_sram_orgz& sram_orgz_type) {
std::map<std::string, BasicPort> port2port_name_map;
switch (sram_orgz_type) {
case SPICE_SRAM_STANDALONE:
/* Not supported */
break;
case SPICE_SRAM_SCAN_CHAIN:
/* TODO: to be supported */
break;
case SPICE_SRAM_MEMORY_BANK:
/* TODO: link BL/WL/Reserved Ports to the inputs of a memory module */
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s,[LINE%d])Invalid type of SRAM organization!\n",
__FILE__, __LINE__);
exit(1);
}
return port2port_name_map;
}
/*********************************************************************
* Create a port-to-port map for a memory module
* The content of the port-to-port map will depend not only
* the design technology of the memory cells but also the
* configuration styles of FPGA fabric.
* Here we will branch on the design technology
**********************************************************************/
std::map<std::string, BasicPort> generate_mem_module_port2port_map(const ModuleManager& module_manager,
const ModuleId& mem_module,
const std::vector<BasicPort>& config_bus_ports,
const std::vector<BasicPort>& mem_output_bus_ports,
const e_spice_model_design_tech& mem_design_tech,
const e_sram_orgz& sram_orgz_type) {
std::map<std::string, BasicPort> port2port_name_map;
switch (mem_design_tech) {
case SPICE_MODEL_DESIGN_CMOS:
port2port_name_map = generate_cmos_mem_module_port2port_map(module_manager, mem_module, config_bus_ports, mem_output_bus_ports, sram_orgz_type);
break;
case SPICE_MODEL_DESIGN_RRAM:
port2port_name_map = generate_rram_mem_module_port2port_map(module_manager, mem_module, sram_orgz_type);
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s,[LINE%d])Invalid type of memory design technology !\n",
__FILE__, __LINE__);
exit(1);
}
return port2port_name_map;
}

View File

@ -38,5 +38,12 @@ void add_sram_ports_to_module_manager(ModuleManager& module_manager,
const e_sram_orgz sram_orgz_type,
const size_t& port_size);
std::map<std::string, BasicPort> generate_mem_module_port2port_map(const ModuleManager& module_manager,
const ModuleId& mem_module,
const std::vector<BasicPort>& config_bus_ports,
const std::vector<BasicPort>& mem_output_bus_ports,
const e_spice_model_design_tech& mem_design_tech,
const e_sram_orgz& sram_orgz_type);
#endif

View File

@ -77,10 +77,14 @@ size_t find_switch_block_number_of_muxes(const RRGSB& rr_gsb) {
if (OUT_PORT != rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) {
continue;
}
/* Check if this node is driven by a multiplexer */
/* Check if this node is just a passing wire */
if (true == rr_gsb.is_sb_node_passing_wire(side_manager.get_side(), itrack)) {
continue;
}
/* Check if this node has more than 2 drivers */
if (2 > rr_gsb.get_chan_node(side_manager.get_side(), itrack)->num_drive_rr_nodes) {
continue;
}
/* This means we need a multiplexer, update the counter */
num_muxes++;
}

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

@ -299,7 +299,7 @@ void print_verilog_submodule_lut(ModuleManager& module_manager,
/* 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(""));
std::string lut_mux_module_name = generate_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 */

View File

@ -14,6 +14,7 @@
#include "module_manager.h"
#include "physical_types.h"
#include "vpr_types.h"
#include "circuit_library_utils.h"
#include "mux_utils.h"
/* FPGA-X2P context header files */
@ -27,10 +28,7 @@
#include "verilog_memory.h"
/*********************************************************************
* Generate Verilog modules for the memories that are used
* by CMOS (SRAM-based) multiplexers
* We support:
* 1. Flat memory modules
* Flat memory modules
*
* in[0] in[1] in[N]
* | | |
@ -43,68 +41,15 @@
* v v v
* +------------------------------------+
* | Multiplexer Configuration port |
*
* 2. TODO: Local decoders
*
* in[0] in[1] in[N]
* | | |
* v v v
* +-------+ +-------+ +-------+
* | SRAM | | SRAM | ... | SRAM |
* | [0] | | [1] | | [N-1] |
* +-------+ +-------+ +-------+
* | | ... |
* v v v
* +------------------------------------+
* | Local decoders |
* +------------------------------------+
* | | ... |
* v v v
* +------------------------------------+
* | Multiplexer Configuration port |
*
* 3. TODO: Scan-chain organization
*
* in[0] in[1] in[N]
* | | |
* v v v
* +-------+ +-------+ +-------+
* scan-chain--->| SRAM |--->| SRAM |--->... --->| SRAM |---->scan-chain
* input&clock | [0] | | [1] | | [N-1] | output
* +-------+ +-------+ +-------+
* | | ... |
* v v v
* +-----------------------------------------+
* | Multiplexer Configuration port |
*
* 4. TODO: Memory bank organization
*
* Bit lines Word lines
* | |
* v v
* +------------------------------------+
* | Memory Module Configuration port |
* +------------------------------------+
* | | |
* v v v
* +-------+ +-------+ +-------+
* | SRAM | | SRAM | ... | SRAM |
* | [0] | | [1] | | [N-1] |
* +-------+ +-------+ +-------+
* | | ... |
* v v v
* +------------------------------------+
* | Multiplexer Configuration port |
*
********************************************************************/
static
void print_verilog_memory_module(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
std::fstream& fp,
const std::string& module_name,
const CircuitModelId& sram_model,
const size_t& num_mems) {
void print_verilog_memory_standalone_module(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
std::fstream& fp,
const std::string& module_name,
const CircuitModelId& sram_model,
const size_t& num_mems) {
/* Make sure we have a valid file handler*/
check_file_handler(fp);
@ -120,6 +65,236 @@ void print_verilog_memory_module(ModuleManager& module_manager,
std::vector<CircuitPortId> sram_input_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_INPUT, true);
/* Get the output ports from the SRAM */
std::vector<CircuitPortId> sram_output_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_OUTPUT, true);
/* Add module ports: the ports come from the SRAM modules */
/* Add each global port */
for (const auto& port : sram_global_ports) {
/* Configure each global port: global ports are shared among the SRAMs, so it is independent from the memory size */
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 : sram_input_ports) {
BasicPort input_port(circuit_lib.port_lib_name(port), num_mems);
module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT);
}
/* Add each output port: port width should match the number of memories */
for (const auto& port : sram_output_ports) {
BasicPort output_port(circuit_lib.port_lib_name(port), num_mems);
module_manager.add_port(module_id, output_port, ModuleManager::MODULE_OUTPUT_PORT);
}
/* dump module definition + ports */
print_verilog_module_declaration(fp, module_manager, module_id);
/* Finish dumping ports */
/* Find the sram module in the module manager */
ModuleId sram_module_id = module_manager.find_module(circuit_lib.model_name(sram_model));
/* Instanciate each submodule */
for (size_t i = 0; i < num_mems; ++i) {
/* Create a port-to-port map */
std::map<std::string, BasicPort> port2port_name_map;
/* Map instance inputs [i] to SRAM module input */
for (const auto& port : sram_input_ports) {
BasicPort instance_input_port(circuit_lib.port_lib_name(port), i, i);
port2port_name_map[circuit_lib.port_lib_name(port)] = instance_input_port;
}
/* Map instance outputs [i] to SRAM module input */
for (const auto& port : sram_output_ports) {
BasicPort instance_output_port(circuit_lib.port_lib_name(port), i, i);
port2port_name_map[circuit_lib.port_lib_name(port)] = instance_output_port;
}
/* Output an instance of the module */
print_verilog_module_instance(fp, module_manager, module_id, sram_module_id, port2port_name_map, circuit_lib.dump_explicit_port_map(sram_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, sram_module_id);
}
/* Put an end to the Verilog module */
print_verilog_module_end(fp, module_name);
}
/*********************************************************************
* Scan-chain organization
*
* +-------+ +-------+ +-------+
* scan-chain--->| CCFF |--->| CCFF |--->... --->| CCFF |---->scan-chain
* input&clock | [0] | | [1] | | [N-1] | output
* +-------+ +-------+ +-------+
* | | ... |
* v v v
* +-----------------------------------------+
* | Multiplexer Configuration port |
*
********************************************************************/
static
void print_verilog_memory_chain_module(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
std::fstream& fp,
const std::string& module_name,
const CircuitModelId& sram_model,
const size_t& num_mems) {
/* Make sure we have a valid file handler*/
check_file_handler(fp);
/* Create a module and add to the module manager */
ModuleId module_id = module_manager.add_module(module_name);
VTR_ASSERT(ModuleId::INVALID() != module_id);
/* Get the global ports required by the SRAM */
std::vector<enum e_spice_model_port_type> global_port_types;
global_port_types.push_back(SPICE_MODEL_PORT_CLOCK);
global_port_types.push_back(SPICE_MODEL_PORT_INPUT);
std::vector<CircuitPortId> sram_global_ports = circuit_lib.model_global_ports_by_type(sram_model, global_port_types, true, false);
/* Get the input ports from the SRAM */
std::vector<CircuitPortId> sram_input_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_INPUT, true);
/* Should have only 1 input port */
VTR_ASSERT( 1 == sram_input_ports.size() );
/* Get the output ports from the SRAM */
std::vector<CircuitPortId> sram_output_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_OUTPUT, true);
/* Should have only 1 or 2 output port */
VTR_ASSERT( (1 == sram_output_ports.size()) || ( 2 == sram_output_ports.size()) );
/* Add module ports: the ports come from the SRAM modules */
/* Add each global port */
for (const auto& port : sram_global_ports) {
/* Configure each global port: global ports are shared among the SRAMs, so it is independent from the memory size */
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 an input port, which is the head of configuration chain in the module */
/* TODO: restriction!!!
* consider only the first input of the CCFF model as the D port,
* which will be connected to the head of the chain
*/
BasicPort chain_head_port(generate_configuration_chain_head_name(),
circuit_lib.port_size(sram_input_ports[0]));
module_manager.add_port(module_id, chain_head_port, ModuleManager::MODULE_INPUT_PORT);
/* Add an output port, which is the tail of configuration chain in the module */
/* TODO: restriction!!!
* consider only the first output of the CCFF model as the Q port,
* which will be connected to the tail of the chain
*/
BasicPort chain_tail_port(generate_configuration_chain_tail_name(),
circuit_lib.port_size(sram_output_ports[0]));
module_manager.add_port(module_id, chain_tail_port, ModuleManager::MODULE_INPUT_PORT);
/* Add each output port: port width should match the number of memories */
for (size_t iport = 0; iport < sram_output_ports.size(); ++iport) {
std::string port_name;
if (0 == iport) {
port_name = generate_configuration_chain_data_out_name();
} else {
VTR_ASSERT( 1 == iport);
port_name = generate_configuration_chain_inverted_data_out_name();
}
BasicPort output_port(port_name, num_mems);
module_manager.add_port(module_id, output_port, ModuleManager::MODULE_OUTPUT_PORT);
}
/* dump module definition + ports */
print_verilog_module_declaration(fp, module_manager, module_id);
/* Finish dumping ports */
/* Find the sram module in the module manager */
ModuleId sram_module_id = module_manager.find_module(circuit_lib.model_name(sram_model));
/* Instanciate each submodule */
for (size_t i = 0; i < num_mems; ++i) {
/* Create a port-to-port map */
std::map<std::string, BasicPort> port2port_name_map;
/* Map instance inputs [i] to SRAM module input */
for (const auto& port : sram_input_ports) {
BasicPort instance_input_port(circuit_lib.port_lib_name(port), i, i);
port2port_name_map[circuit_lib.port_lib_name(port)] = instance_input_port;
}
/* Map instance outputs [i] to SRAM module input */
for (size_t iport = 0; iport < sram_output_ports.size(); ++iport) {
std::string port_name;
if (0 == iport) {
port_name = generate_configuration_chain_data_out_name();
} else {
VTR_ASSERT( 1 == iport);
port_name = generate_configuration_chain_inverted_data_out_name();
}
BasicPort instance_output_port(port_name, i, i);
port2port_name_map[circuit_lib.port_lib_name(sram_output_ports[iport])] = instance_output_port;
}
/* Output an instance of the module */
print_verilog_module_instance(fp, module_manager, module_id, sram_module_id, port2port_name_map, circuit_lib.dump_explicit_port_map(sram_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, sram_module_id);
}
/* Wire the memory cells into a chain
* The head of the chain will be wired to the input port of the first CCFF
* The tail of the chain will be wired to the output port of the last CCFF
* The output of each CCFF will be wired to the input of the next CCFFF in the chain
*/
BasicPort first_ccff_input_port(circuit_lib.port_lib_name(sram_input_ports[0]), 0, 0);
print_verilog_wire_connection(fp, first_ccff_input_port, chain_head_port, false);
BasicPort last_ccff_output_port(generate_configuration_chain_data_out_name(), num_mems - 1, num_mems - 1);
print_verilog_wire_connection(fp, chain_tail_port, last_ccff_output_port, false);
BasicPort chain_output_port(generate_configuration_chain_data_out_name(), 0, num_mems - 2);
BasicPort chain_input_port(circuit_lib.port_lib_name(sram_input_ports[0]), 1, num_mems - 1);
print_verilog_wire_connection(fp, chain_input_port, chain_output_port, false);
/* Put an end to the Verilog module */
print_verilog_module_end(fp, module_name);
}
/*********************************************************************
* Memory bank organization
*
* Bit lines(BL/BLB) Word lines (WL/WLB)
* | |
* v v
* +------------------------------------+
* | Memory Module Configuration port |
* +------------------------------------+
* | | |
* v v v
* +-------+ +-------+ +-------+
* | SRAM | | SRAM | ... | SRAM |
* | [0] | | [1] | | [N-1] |
* +-------+ +-------+ +-------+
* | | ... |
* v v v
* +------------------------------------+
* | Multiplexer Configuration port |
*
********************************************************************/
static
void print_verilog_memory_bank_module(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
std::fstream& fp,
const std::string& module_name,
const CircuitModelId& sram_model,
const size_t& num_mems) {
/* Make sure we have a valid file handler*/
check_file_handler(fp);
/* Create a module and add to the module manager */
ModuleId module_id = module_manager.add_module(module_name);
VTR_ASSERT(ModuleId::INVALID() != module_id);
/* Get the global ports required by the SRAM */
std::vector<enum e_spice_model_port_type> global_port_types;
global_port_types.push_back(SPICE_MODEL_PORT_CLOCK);
global_port_types.push_back(SPICE_MODEL_PORT_INPUT);
std::vector<CircuitPortId> sram_global_ports = circuit_lib.model_global_ports_by_type(sram_model, global_port_types, true, false);
/* Get the input ports from the SRAM */
std::vector<CircuitPortId> sram_input_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_INPUT, true);
/* A SRAM cell with BL/WL should not have any input */
VTR_ASSERT( 0 == sram_input_ports.size() );
/* Get the output ports from the SRAM */
std::vector<CircuitPortId> sram_output_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_OUTPUT, true);
/* Get the BL/WL ports from the SRAM */
std::vector<CircuitPortId> sram_bl_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_BL, true);
std::vector<CircuitPortId> sram_blb_ports = circuit_lib.model_ports_by_type(sram_model, SPICE_MODEL_PORT_BLB, true);
@ -133,14 +308,7 @@ void print_verilog_memory_module(ModuleManager& module_manager,
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);
}
/* TODO: when Configuration-chain style is selected, the port map should be different!
* It should have only a head as input, a tail as output and other regular output ports
*/
/* Add each input port: port width should match the number of memories
* The number of inputs will not match the number of memory bits of a multiplexer
* when local decoders are used.
* It should be calculated by the decoder builders!
*/
/* Add each input port */
for (const auto& port : sram_input_ports) {
BasicPort input_port(circuit_lib.port_lib_name(port), num_mems);
module_manager.add_port(module_id, input_port, ModuleManager::MODULE_INPUT_PORT);
@ -213,15 +381,54 @@ void print_verilog_memory_module(ModuleManager& module_manager,
* update the module manager with the relationship between the parent and child modules
*/
module_manager.add_child_module(module_id, sram_module_id);
/* TODO: Wire the memory cells into a chain, when Configuration-chain style is selected!!! */
}
/* TODO: if a local memory decoder is required, instanciate it here */
/* Put an end to the Verilog module */
print_verilog_module_end(fp, module_name);
}
/*********************************************************************
* Generate Verilog modules for the memories that are used
* by a circuit model
* The organization of memory circuit will depend on the style of
* configuration protocols
* Currently, we support
* 1. Flat SRAM organization
* 2. Configuration chain
* 3. Memory bank (memory decoders)
********************************************************************/
static
void print_verilog_memory_module(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const e_sram_orgz& sram_orgz_type,
std::fstream& fp,
const std::string& module_name,
const CircuitModelId& sram_model,
const size_t& num_mems) {
switch (sram_orgz_type) {
case SPICE_SRAM_STANDALONE:
print_verilog_memory_standalone_module(module_manager, circuit_lib, fp,
module_name, sram_model, num_mems);
break;
case SPICE_SRAM_SCAN_CHAIN:
print_verilog_memory_chain_module(module_manager, circuit_lib, fp,
module_name, sram_model, num_mems);
break;
case SPICE_SRAM_MEMORY_BANK:
print_verilog_memory_bank_module(module_manager, circuit_lib, fp,
module_name, sram_model, num_mems);
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, LINE%d) Invalid SRAM organization!\n",
__FILE__, __LINE__);
}
}
/*********************************************************************
* Generate Verilog modules for the memories that are used
* by multiplexers
@ -238,28 +445,27 @@ void print_verilog_memory_module(ModuleManager& module_manager,
static
void print_verilog_mux_memory_module(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const e_sram_orgz& sram_orgz_type,
std::fstream& fp,
const CircuitModelId& mux_model,
const MuxGraph& mux_graph) {
/* Find the actual number of configuration bits, based on the mux graph
* Due to the use of local decoders inside mux, this may be
*/
size_t num_config_bits = find_mux_num_config_bits(circuit_lib, mux_model, mux_graph, sram_orgz_type);
/* Multiplexers built with different technology is in different organization */
switch (circuit_lib.design_tech_type(mux_model)) {
case SPICE_MODEL_DESIGN_CMOS: {
/* Generate module name */
std::string module_name = generate_verilog_mux_subckt_name(circuit_lib, mux_model,
find_mux_num_datapath_inputs(circuit_lib, mux_model, mux_graph.num_inputs()),
std::string(verilog_mem_posfix));
std::string module_name = generate_mux_subckt_name(circuit_lib, mux_model,
find_mux_num_datapath_inputs(circuit_lib, mux_model, mux_graph.num_inputs()),
std::string(verilog_mem_posfix));
/* Get the sram ports from the mux */
std::vector<CircuitPortId> mux_sram_ports = circuit_lib.model_ports_by_type(mux_model, SPICE_MODEL_PORT_SRAM, true);
VTR_ASSERT( 1 == mux_sram_ports.size() );
/* Get the circuit model for the memory circuit used by the multiplexer */
CircuitModelId sram_model = circuit_lib.port_tri_state_model(mux_sram_ports[0]);
VTR_ASSERT(CircuitModelId::INVALID() != sram_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 */
size_t num_mems = mux_graph.num_memory_bits();
print_verilog_memory_module(module_manager, circuit_lib, fp, module_name, sram_model, num_mems);
print_verilog_memory_module(module_manager, circuit_lib, sram_orgz_type, fp, module_name, sram_models[0], num_config_bits);
break;
}
case SPICE_MODEL_DESIGN_RRAM:
@ -296,6 +502,7 @@ void print_verilog_mux_memory_module(ModuleManager& module_manager,
void print_verilog_submodule_memories(ModuleManager& module_manager,
const MuxLibrary& mux_lib,
const CircuitLibrary& circuit_lib,
const e_sram_orgz& sram_orgz_type,
const std::string& verilog_dir,
const std::string& submodule_dir) {
/* Plug in with the mux subckt */
@ -329,7 +536,7 @@ void print_verilog_submodule_memories(ModuleManager& module_manager,
continue;
}
/* Create a Verilog module for the memories used by the multiplexer */
print_verilog_mux_memory_module(module_manager, circuit_lib, fp, mux_model, mux_graph);
print_verilog_mux_memory_module(module_manager, circuit_lib, sram_orgz_type, fp, mux_model, mux_graph);
}
/* Create the memory circuits for non-MUX circuit models.
@ -371,7 +578,7 @@ void print_verilog_submodule_memories(ModuleManager& module_manager,
std::string module_name = generate_memory_module_name(circuit_lib, model, sram_models[0], std::string(verilog_mem_posfix));
/* Create a Verilog module for the memories used by the circuit model */
print_verilog_memory_module(module_manager, circuit_lib, fp, module_name, sram_models[0], num_mems);
print_verilog_memory_module(module_manager, circuit_lib, sram_orgz_type, fp, module_name, sram_models[0], num_mems);
}
/* Close the file stream */

View File

@ -16,6 +16,7 @@
void print_verilog_submodule_memories(ModuleManager& module_manager,
const MuxLibrary& mux_lib,
const CircuitLibrary& circuit_lib,
const e_sram_orgz& sram_orgz_type,
const std::string& verilog_dir,
const std::string& submodule_dir);

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"
@ -691,7 +693,7 @@ void generate_verilog_mux_branch_module(ModuleManager& module_manager,
const CircuitModelId& circuit_model,
const size_t& mux_size,
const MuxGraph& mux_graph) {
std::string module_name = generate_verilog_mux_branch_subckt_name(circuit_lib, circuit_model, mux_size, mux_graph.num_inputs(), verilog_mux_basis_posfix);
std::string module_name = generate_mux_branch_subckt_name(circuit_lib, circuit_model, mux_size, mux_graph.num_inputs(), verilog_mux_basis_posfix);
/* Multiplexers built with different technology is in different organization */
switch (circuit_lib.design_tech_type(circuit_model)) {
@ -760,13 +762,13 @@ void generate_verilog_cmos_mux_module_mux2_multiplexing_structure(ModuleManager&
/* Print local wires which are the nodes in the mux graph */
for (size_t level = 0; level < mux_graph.num_levels(); ++level) {
/* Print the internal wires located at this level */
BasicPort internal_wire_port(generate_verilog_mux_node_name(level, false), mux_graph.num_nodes_at_level(level));
BasicPort internal_wire_port(generate_mux_node_name(level, false), mux_graph.num_nodes_at_level(level));
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, internal_wire_port) << ";" << std::endl;
/* Identify if an intermediate buffer is needed */
if (false == inter_buffer_location_map[level]) {
continue;
}
BasicPort internal_wire_buffered_port(generate_verilog_mux_node_name(level, true), mux_graph.num_nodes_at_level(level));
BasicPort internal_wire_buffered_port(generate_mux_node_name(level, true), mux_graph.num_nodes_at_level(level));
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, internal_wire_buffered_port) << std::endl;
}
print_verilog_comment(fp, std::string("---- END Internal wires of a CMOS MUX module -----"));
@ -832,7 +834,7 @@ void generate_verilog_cmos_mux_module_mux2_multiplexing_structure(ModuleManager&
/* Generate the port info of each input node */
size_t input_node_level = mux_graph.node_level(input_node);
size_t input_node_index_at_level = mux_graph.node_index_at_level(input_node);
BasicPort instance_input_port(generate_verilog_mux_node_name(input_node_level, inter_buffer_location_map[input_node_level]), input_node_index_at_level, input_node_index_at_level);
BasicPort instance_input_port(generate_mux_node_name(input_node_level, inter_buffer_location_map[input_node_level]), input_node_index_at_level, input_node_index_at_level);
/* Link nodes to input ports for the branch module */
std::string module_input_port_name = circuit_lib.port_lib_name(std_cell_input_ports[&input_node - &input_nodes[0]]);
@ -841,7 +843,7 @@ void generate_verilog_cmos_mux_module_mux2_multiplexing_structure(ModuleManager&
/* Build the link between output_node[0] and std_cell_output_port[0] */
{ /* Create a code block to accommodate the local variables */
BasicPort instance_output_port(generate_verilog_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
BasicPort instance_output_port(generate_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
std::string module_output_port_name = circuit_lib.port_lib_name(std_cell_output_ports[0]);
port2port_name_map[module_output_port_name] = instance_output_port;
}
@ -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;
}
@ -876,8 +882,8 @@ void generate_verilog_cmos_mux_module_mux2_multiplexing_structure(ModuleManager&
/* We must have a valid model id */
VTR_ASSERT(CircuitModelId::INVALID() != buffer_model);
BasicPort buffer_instance_input_port(generate_verilog_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
BasicPort buffer_instance_output_port(generate_verilog_mux_node_name(output_node_level, true), output_node_index_at_level, output_node_index_at_level);
BasicPort buffer_instance_input_port(generate_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
BasicPort buffer_instance_output_port(generate_mux_node_name(output_node_level, true), output_node_index_at_level, output_node_index_at_level);
print_verilog_buffer_instance(fp, module_manager, circuit_lib, module_id, buffer_model, buffer_instance_input_port, buffer_instance_output_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 */
@ -934,13 +929,13 @@ void generate_verilog_cmos_mux_module_tgate_multiplexing_structure(ModuleManager
/* Print local wires which are the nodes in the mux graph */
for (size_t level = 0; level < mux_graph.num_levels(); ++level) {
/* Print the internal wires located at this level */
BasicPort internal_wire_port(generate_verilog_mux_node_name(level, false), mux_graph.num_nodes_at_level(level));
BasicPort internal_wire_port(generate_mux_node_name(level, false), mux_graph.num_nodes_at_level(level));
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, internal_wire_port) << ";" << std::endl;
/* Identify if an intermediate buffer is needed */
if (false == inter_buffer_location_map[level]) {
continue;
}
BasicPort internal_wire_buffered_port(generate_verilog_mux_node_name(level, true), mux_graph.num_nodes_at_level(level));
BasicPort internal_wire_buffered_port(generate_mux_node_name(level, true), mux_graph.num_nodes_at_level(level));
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, internal_wire_buffered_port) << std::endl;
}
print_verilog_comment(fp, std::string("---- END Internal wires of a CMOS MUX module -----"));
@ -982,7 +977,7 @@ void generate_verilog_cmos_mux_module_tgate_multiplexing_structure(ModuleManager
/* Instanciate the branch module which is a tgate-based module
*/
std::string branch_module_name= generate_verilog_mux_branch_subckt_name(circuit_lib, circuit_model, mux_size, branch_size, verilog_mux_basis_posfix);
std::string branch_module_name= generate_mux_branch_subckt_name(circuit_lib, circuit_model, mux_size, branch_size, verilog_mux_basis_posfix);
/* Get the moduleId for the submodule */
ModuleId branch_module_id = module_manager.find_module(branch_module_name);
/* We must have one */
@ -998,13 +993,13 @@ void generate_verilog_cmos_mux_module_tgate_multiplexing_structure(ModuleManager
/* Generate the port info of each input node */
size_t input_node_level = mux_graph.node_level(input_node);
size_t input_node_index_at_level = mux_graph.node_index_at_level(input_node);
BasicPort branch_node_input_port(generate_verilog_mux_node_name(input_node_level, inter_buffer_location_map[input_node_level]), input_node_index_at_level, input_node_index_at_level);
BasicPort branch_node_input_port(generate_mux_node_name(input_node_level, inter_buffer_location_map[input_node_level]), input_node_index_at_level, input_node_index_at_level);
branch_node_input_ports.push_back(branch_node_input_port);
}
/* Create the port info for the input */
/* TODO: the naming could be more flexible? */
BasicPort instance_input_port = generate_verilog_bus_port(branch_node_input_ports, std::string(generate_verilog_mux_node_name(output_node_level, false) + "_in"));
BasicPort instance_input_port = generate_verilog_bus_port(branch_node_input_ports, std::string(generate_mux_node_name(output_node_level, false) + "_in"));
/* If we have more than 1 port in the combined instance ports ,
* output a local wire */
if (1 < combine_verilog_ports(branch_node_input_ports).size()) {
@ -1023,7 +1018,7 @@ void generate_verilog_cmos_mux_module_tgate_multiplexing_structure(ModuleManager
port2port_name_map[module_input_port.get_name()] = instance_input_port;
/* Link nodes to output ports for the branch module */
BasicPort instance_output_port(generate_verilog_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
BasicPort instance_output_port(generate_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
ModulePortId module_output_port_id = module_manager.find_module_port(branch_module_id, "out");
VTR_ASSERT(ModulePortId::INVALID() != module_output_port_id);
/* Get the port from module */
@ -1035,12 +1030,16 @@ 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);
}
/* Create the port info for the input */
/* TODO: the naming could be more flexible? */
BasicPort instance_mem_port = generate_verilog_bus_port(branch_node_mem_ports, std::string(generate_verilog_mux_node_name(output_node_level, false) + "_mem"));
BasicPort instance_mem_port = generate_verilog_bus_port(branch_node_mem_ports, std::string(generate_mux_node_name(output_node_level, false) + "_mem"));
/* If we have more than 1 port in the combined instance ports ,
* output a local wire */
if (1 < combine_verilog_ports(branch_node_mem_ports).size()) {
@ -1065,12 +1064,16 @@ 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);
}
/* Create the port info for the input */
/* TODO: the naming could be more flexible? */
BasicPort instance_mem_inv_port = generate_verilog_bus_port(branch_node_mem_inv_ports, std::string(generate_verilog_mux_node_name(output_node_level, false) + "_mem_inv"));
BasicPort instance_mem_inv_port = generate_verilog_bus_port(branch_node_mem_inv_ports, std::string(generate_mux_node_name(output_node_level, false) + "_mem_inv"));
/* If we have more than 1 port in the combined instance ports ,
* output a local wire */
if (1 < combine_verilog_ports(branch_node_mem_inv_ports).size()) {
@ -1110,8 +1113,8 @@ void generate_verilog_cmos_mux_module_tgate_multiplexing_structure(ModuleManager
/* We must have a valid model id */
VTR_ASSERT(CircuitModelId::INVALID() != buffer_model);
BasicPort buffer_instance_input_port(generate_verilog_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
BasicPort buffer_instance_output_port(generate_verilog_mux_node_name(output_node_level, true), output_node_index_at_level, output_node_index_at_level);
BasicPort buffer_instance_input_port(generate_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
BasicPort buffer_instance_output_port(generate_mux_node_name(output_node_level, true), output_node_index_at_level, output_node_index_at_level);
print_verilog_buffer_instance(fp, module_manager, circuit_lib, module_id, buffer_model, buffer_instance_input_port, buffer_instance_output_port);
@ -1167,7 +1170,7 @@ void generate_verilog_cmos_mux_module_input_buffers(ModuleManager& module_manage
BasicPort instance_input_port(module_input_port.get_name(), size_t(input_index), size_t(input_index));
/* Create the port information of the MUX graph input, which is the output of buffer instance */
BasicPort instance_output_port(generate_verilog_mux_node_name(input_node_level, false), input_node_index_at_level, input_node_index_at_level);
BasicPort instance_output_port(generate_mux_node_name(input_node_level, false), input_node_index_at_level, input_node_index_at_level);
/* For last input:
* Add a constant value to the last input, if this MUX needs a constant input
@ -1261,7 +1264,7 @@ void generate_verilog_cmos_mux_module_output_buffers(ModuleManager& module_manag
VTR_ASSERT(MuxNodeId::INVALID() != mux_graph.node_id(output_node_level, output_node_index_at_level));
/* Create the port information of the MUX input, which is the input of buffer instance */
BasicPort instance_input_port(generate_verilog_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
BasicPort instance_input_port(generate_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
/* Create the port information of the module output at the given pin range, which is the output of buffer instance */
BasicPort instance_output_port(module_output_port.get_name(), pin, pin);
@ -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());
@ -1383,12 +1401,6 @@ void generate_verilog_cmos_mux_module(ModuleManager& module_manager,
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);
@ -1396,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
@ -1467,13 +1524,13 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu
/* Print local wires which are the nodes in the mux graph */
for (size_t level = 0; level < mux_graph.num_levels(); ++level) {
/* Print the internal wires located at this level */
BasicPort internal_wire_port(generate_verilog_mux_node_name(level, false), mux_graph.num_nodes_at_level(level));
BasicPort internal_wire_port(generate_mux_node_name(level, false), mux_graph.num_nodes_at_level(level));
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, internal_wire_port) << ";" << std::endl;
/* Identify if an intermediate buffer is needed */
if (false == inter_buffer_location_map[level]) {
continue;
}
BasicPort internal_wire_buffered_port(generate_verilog_mux_node_name(level, true), mux_graph.num_nodes_at_level(level));
BasicPort internal_wire_buffered_port(generate_mux_node_name(level, true), mux_graph.num_nodes_at_level(level));
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, internal_wire_buffered_port) << std::endl;
}
print_verilog_comment(fp, std::string("---- END Internal wires of a RRAM-based MUX module -----"));
@ -1515,7 +1572,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_verilog_mux_branch_subckt_name(circuit_lib, circuit_model, mux_size, branch_size, verilog_mux_basis_posfix);
std::string branch_module_name= generate_mux_branch_subckt_name(circuit_lib, circuit_model, mux_size, branch_size, verilog_mux_basis_posfix);
/* Get the moduleId for the submodule */
ModuleId branch_module_id = module_manager.find_module(branch_module_name);
/* We must have one */
@ -1531,13 +1588,13 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu
/* Generate the port info of each input node */
size_t input_node_level = mux_graph.node_level(input_node);
size_t input_node_index_at_level = mux_graph.node_index_at_level(input_node);
BasicPort branch_node_input_port(generate_verilog_mux_node_name(input_node_level, inter_buffer_location_map[input_node_level]), input_node_index_at_level, input_node_index_at_level);
BasicPort branch_node_input_port(generate_mux_node_name(input_node_level, inter_buffer_location_map[input_node_level]), input_node_index_at_level, input_node_index_at_level);
branch_node_input_ports.push_back(branch_node_input_port);
}
/* Create the port info for the input */
/* TODO: the naming could be more flexible? */
BasicPort instance_input_port = generate_verilog_bus_port(branch_node_input_ports, std::string(generate_verilog_mux_node_name(output_node_level, false) + "_in"));
BasicPort instance_input_port = generate_verilog_bus_port(branch_node_input_ports, std::string(generate_mux_node_name(output_node_level, false) + "_in"));
/* If we have more than 1 port in the combined instance ports ,
* output a local wire */
if (1 < combine_verilog_ports(branch_node_input_ports).size()) {
@ -1556,7 +1613,7 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu
port2port_name_map[module_input_port.get_name()] = instance_input_port;
/* Link nodes to output ports for the branch module */
BasicPort instance_output_port(generate_verilog_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
BasicPort instance_output_port(generate_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
ModulePortId module_output_port_id = module_manager.find_module_port(branch_module_id, "out");
VTR_ASSERT(ModulePortId::INVALID() != module_output_port_id);
/* Get the port from module */
@ -1589,7 +1646,7 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu
/* Create the port info for the input */
/* TODO: the naming could be more flexible? */
BasicPort instance_blb_port = generate_verilog_bus_port(branch_node_blb_ports, std::string(generate_verilog_mux_node_name(output_node_level, false) + "_blb"));
BasicPort instance_blb_port = generate_verilog_bus_port(branch_node_blb_ports, std::string(generate_mux_node_name(output_node_level, false) + "_blb"));
/* If we have more than 1 port in the combined instance ports ,
* output a local wire */
if (1 < combine_verilog_ports(branch_node_blb_ports).size()) {
@ -1630,7 +1687,7 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu
/* Create the port info for the WL */
/* TODO: the naming could be more flexible? */
BasicPort instance_wl_port = generate_verilog_bus_port(branch_node_wl_ports, std::string(generate_verilog_mux_node_name(output_node_level, false) + "_wl"));
BasicPort instance_wl_port = generate_verilog_bus_port(branch_node_wl_ports, std::string(generate_mux_node_name(output_node_level, false) + "_wl"));
/* If we have more than 1 port in the combined instance ports ,
* output a local wire */
if (1 < combine_verilog_ports(branch_node_wl_ports).size()) {
@ -1669,8 +1726,8 @@ void generate_verilog_rram_mux_module_multiplexing_structure(ModuleManager& modu
/* We must have a valid model id */
VTR_ASSERT(CircuitModelId::INVALID() != buffer_model);
BasicPort buffer_instance_input_port(generate_verilog_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
BasicPort buffer_instance_output_port(generate_verilog_mux_node_name(output_node_level, true), output_node_index_at_level, output_node_index_at_level);
BasicPort buffer_instance_input_port(generate_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
BasicPort buffer_instance_output_port(generate_mux_node_name(output_node_level, true), output_node_index_at_level, output_node_index_at_level);
print_verilog_buffer_instance(fp, module_manager, circuit_lib, module_id, buffer_model, buffer_instance_input_port, buffer_instance_output_port);
@ -1825,9 +1882,9 @@ void generate_verilog_mux_module(ModuleManager& module_manager,
std::fstream& fp,
const CircuitModelId& circuit_model,
const MuxGraph& mux_graph) {
std::string module_name = generate_verilog_mux_subckt_name(circuit_lib, circuit_model,
find_mux_num_datapath_inputs(circuit_lib, circuit_model, mux_graph.num_inputs()),
std::string(""));
std::string module_name = generate_mux_subckt_name(circuit_lib, circuit_model,
find_mux_num_datapath_inputs(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)) {

View File

@ -66,7 +66,8 @@ void print_verilog_switch_block_local_sram_wires(std::fstream& fp,
const size_t& port_size) {
size_t local_port_size = port_size;
if (SPICE_SRAM_SCAN_CHAIN == sram_orgz_type) {
local_port_size = find_switch_block_number_of_muxes(rr_gsb);
/* Plus 1 for the wire size to connect to the tail of the configuration chain */
local_port_size = find_switch_block_number_of_muxes(rr_gsb) + 1;
}
print_verilog_local_sram_wires(fp, circuit_lib, sram_model, sram_orgz_type, local_port_size);
}
@ -2348,7 +2349,7 @@ void print_verilog_unique_switch_box_mux(ModuleManager& module_manager,
const MuxGraph& mux_graph = mux_lib.mux_graph(mux_id);
/* Find the module name of the multiplexer and try to find it in the module manager */
std::string mux_module_name = generate_verilog_mux_subckt_name(circuit_lib, mux_model, datapath_mux_size, std::string(""));
std::string mux_module_name = generate_mux_subckt_name(circuit_lib, mux_model, datapath_mux_size, std::string(""));
ModuleId mux_module = module_manager.find_module(mux_module_name);
VTR_ASSERT (true == module_manager.valid_module_id(mux_module));
@ -2440,35 +2441,36 @@ void print_verilog_unique_switch_box_mux(ModuleManager& module_manager,
*/
module_manager.add_child_module(sb_module, mux_module);
/* TODO: Instanciate memory modules */
switch (circuit_lib.design_tech_type(mux_model)) {
case SPICE_MODEL_DESIGN_CMOS:
/* Call the memory module defined for this SRAM-based MUX! */
/*
mem_subckt_name = generate_verilog_mux_subckt_name(verilog_model, mux_size, verilog_mem_posfix);
dump_verilog_mem_sram_submodule(fp, cur_sram_orgz_info,
verilog_model, mux_size, mem_model,
cur_num_sram, cur_num_sram + num_mux_conf_bits - 1,
is_explicit_mapping);
*/
break;
case SPICE_MODEL_DESIGN_RRAM:
/* RRAM-based MUX does not need any SRAM dumping
* But we have to get the number of configuration bits required by this MUX
* and update the number of memory bits
*/
/*
update_sram_orgz_info_num_mem_bit(cur_sram_orgz_info, cur_num_sram + num_mux_conf_bits);
update_sram_orgz_info_num_blwl(cur_sram_orgz_info,
cur_bl + num_mux_conf_bits,
cur_wl + num_mux_conf_bits);
*/
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s,[LINE%d])Invalid design technology for circuit model (%s)!\n",
__FILE__, __LINE__, circuit_lib.model_name(mux_model).c_str());
}
/* Instanciate memory modules */
/* Find the name and module id of the memory module */
std::string mem_module_name = generate_mux_subckt_name(circuit_lib, mux_model, datapath_mux_size, std::string(verilog_mem_posfix));
ModuleId mem_module = module_manager.find_module(mem_module_name);
VTR_ASSERT (true == module_manager.valid_module_id(mem_module));
/* Create port-to-port map */
std::map<std::string, BasicPort> mem_port2port_name_map;
/* TODO: Make the port2port map generation more generic!!! */
std::vector<BasicPort> config_ports;
config_ports.push_back(BasicPort(generate_local_config_bus_port_name(), mux_instance_id - 1, mux_instance_id));
std::vector<BasicPort> mem_output_ports;
mem_output_ports.push_back(mux_config_port);
mem_output_ports.push_back(mux_config_inv_port);
mem_port2port_name_map = generate_mem_module_port2port_map(module_manager, mem_module,
config_ports,
mem_output_ports,
circuit_lib.design_tech_type(mux_model),
cur_sram_orgz_info->type);
/* Print an instance of the MUX Module */
print_verilog_comment(fp, std::string("----- BEGIN Instanciation of memory cells for a routing multiplexer -----"));
print_verilog_module_instance(fp, module_manager, sb_module, mem_module, mem_port2port_name_map, use_explicit_mapping);
print_verilog_comment(fp, std::string("----- END Instanciation of memory cells for a routing multiplexer -----"));
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(sb_module, mem_module);
/* Create the path of the input of multiplexer in the hierarchy
* TODO: this MUST be deprecated later because module manager is created to handle these problems!!!

View File

@ -3201,9 +3201,13 @@ void dump_verilog_submodules(ModuleManager& module_manager,
dump_verilog_submodule_muxes(cur_sram_orgz_info, verilog_dir, submodule_dir, routing_arch->num_switch,
switch_inf, Arch.spice, routing_arch, fpga_verilog_opts.dump_explicit_verilog);
/* NOTE: local decoders generation must go before the MUX generation!!!
* because local decoders modules will be instanciated in the MUX modules
*/
print_verilog_submodule_mux_local_decoders(module_manager, mux_lib, Arch.spice->circuit_lib,
std::string(verilog_dir), std::string(submodule_dir));
print_verilog_submodule_muxes(module_manager, mux_lib, Arch.spice->circuit_lib, cur_sram_orgz_info, std::string(verilog_dir), std::string(submodule_dir));
print_verilog_submodule_mux_local_decoders(module_manager, mux_lib, Arch.spice->circuit_lib, std::string(verilog_dir), std::string(submodule_dir));
/* 2. LUTes */
vpr_printf(TIO_MESSAGE_INFO, "Generating modules of LUTs...\n");
@ -3221,7 +3225,9 @@ void dump_verilog_submodules(ModuleManager& module_manager,
vpr_printf(TIO_MESSAGE_INFO, "Generating modules of memories...\n");
dump_verilog_submodule_memories(cur_sram_orgz_info, verilog_dir, submodule_dir, routing_arch->num_switch,
switch_inf, Arch.spice, routing_arch, fpga_verilog_opts.dump_explicit_verilog);
print_verilog_submodule_memories(module_manager, mux_lib, Arch.spice->circuit_lib, std::string(verilog_dir), std::string(submodule_dir));
print_verilog_submodule_memories(module_manager, mux_lib, Arch.spice->circuit_lib,
cur_sram_orgz_info->type,
std::string(verilog_dir), std::string(submodule_dir));
/* 5. Dump template for all the modules */
if (TRUE == fpga_verilog_opts.print_user_defined_template) {

View File

@ -651,7 +651,8 @@ void print_verilog_buffer_instance(std::fstream& fp,
/********************************************************************
* Print local wires that are used for SRAM configuration
* The local wires are strongly dependent on the organization of SRAMs.
* 1. Standalone SRAMs:
* Standalone SRAMs:
* -----------------
* No need for local wires, their outputs are port of the module
*
* Module
@ -665,36 +666,61 @@ void print_verilog_buffer_instance(std::fstream& fp,
* | +---------------------+ |
* +------------------------------+
*
* 2. Configuration-chain Flip-flops:
* two ports will be added, which are the head of scan-chain
* and the tail of scan-chain
* Configuration chain-style
* -------------------------
* wire [0:N] config_bus
*
* Module
* +-----------------------------------------+
* | |
* | +------+ +------+ +------+ |
* | +->| CCFF |--->| CCFF | ... | CCFF |-+ |
* | | +------+ | +------+ | +------+ | |
* head--->|-+-----------+------------+-----------+->|--->tail
* | local wire |
* +-----------------------------------------+
* 3. Memory decoders:
*
* Module
* +--------------------------------------------------------------+
* | config_bus config_bus config_bus config_bus |
* | [0] [1] [2] [N] |
* | | | | | |
* | v v v v |
* ccff_head| ----------+ +---------+ +------------+ +----------------|-> ccff_tail
* | | ^ | ^ | ^ |
* | head v |tail v | v | |
* | +----------+ +----------+ +----------+ |
* | | Memory | | Memory | | Memory | |
* | | Module | | Module | ... | Module | |
* | | [0] | | [1] | | [N] | |
* | +----------+ +----------+ +----------+ |
* | | | | |
* | v v v |
* | +----------+ +----------+ +----------+ |
* | | MUX | | MUX | | MUX | |
* | | Module | | Module | ... | Module | |
* | | [0] | | [1] | | [N] | |
* | +----------+ +----------+ +----------+ |
* | |
* +--------------------------------------------------------------+
*
* Memory bank-style
* -----------------
* two ports will be added, which are regular output and inverted output
* Note that the outputs are the data outputs of SRAMs
* BL/WLs of memory decoders are ports of module but not local wires
*
* Module
* +-----------------------------------------+
* | |
* | +------+ +------+ +------+ |
* | | SRAM | | SRAM | ... | SRAM | |
* | +------+ +------+ +------+ |
* | ^ ^ ^ |
* | | | | |
* BL/WL--->|---------------------------------------->|
* | local wire |
* +-----------------------------------------+
* Module
* +-------------------------------------------------+
* | |
BL/WL bus --+--------+------------+-----------------+ |
* | | | | |
* | BL/WL v BL/WL v BL/WL v |
* | +----------+ +----------+ +----------+ |
* | | Memory | | Memory | | Memory | |
* | | Module | | Module | ... | Module | |
* | | [0] | | [1] | | [N] | |
* | +----------+ +----------+ +----------+ |
* | | | | |
* | v v v |
* | +----------+ +----------+ +----------+ |
* | | MUX | | MUX | | MUX | |
* | | Module | | Module | ... | Module | |
* | | [0] | | [1] | | [N] | |
* | +----------+ +----------+ +----------+ |
* | |
* +-------------------------------------------------+
*
********************************************************************/
void print_verilog_local_sram_wires(std::fstream& fp,
@ -717,36 +743,19 @@ void print_verilog_local_sram_wires(std::fstream& fp,
break;
case SPICE_SRAM_SCAN_CHAIN: {
/* Generate the name of local wire for the CCFF inputs, CCFF output and inverted output */
std::vector<BasicPort> ccff_ports;
/* [0] => CCFF input */
ccff_ports.push_back(BasicPort(generate_sram_local_port_name(circuit_lib, sram_model, sram_orgz_type, SPICE_MODEL_PORT_INPUT), port_size));
/* [1] => CCFF output */
ccff_ports.push_back(BasicPort(generate_sram_local_port_name(circuit_lib, sram_model, sram_orgz_type, SPICE_MODEL_PORT_OUTPUT), port_size));
/* [2] => CCFF inverted output */
ccff_ports.push_back(BasicPort(generate_sram_local_port_name(circuit_lib, sram_model, sram_orgz_type, SPICE_MODEL_PORT_INOUT), port_size));
/* Print local wire definition */
for (const auto& ccff_port : ccff_ports) {
fp << generate_verilog_port(VERILOG_PORT_WIRE, ccff_port) << ";" << std::endl;
}
BasicPort ccff_config_bus_port(generate_local_config_bus_port_name(), port_size);
fp << generate_verilog_port(VERILOG_PORT_WIRE, ccff_config_bus_port) << ";" << std::endl;
/* Connect first CCFF to the head */
/* Head is always a 1-bit port */
BasicPort ccff_head_port(generate_sram_port_name(circuit_lib, sram_model, sram_orgz_type, SPICE_MODEL_PORT_INPUT), 1);
BasicPort ccff_head_local_port(ccff_ports[0].get_name(), 1);
BasicPort ccff_head_local_port(ccff_config_bus_port.get_name(), 1);
print_verilog_wire_connection(fp, ccff_head_local_port, ccff_head_port, false);
/* Connect last CCFF to the tail */
/* Tail is always a 1-bit port */
BasicPort ccff_tail_port(generate_sram_port_name(circuit_lib, sram_model, sram_orgz_type, SPICE_MODEL_PORT_OUTPUT), 1);
BasicPort ccff_tail_local_port(ccff_ports[1].get_name(), ccff_ports[1].get_msb(), ccff_ports[1].get_msb());
BasicPort ccff_tail_local_port(ccff_config_bus_port.get_name(), ccff_config_bus_port.get_msb(), ccff_config_bus_port.get_msb());
print_verilog_wire_connection(fp, ccff_tail_local_port, ccff_tail_port, false);
/* Connect CCFFs into chains */
/* If port size is 0 or 1, there is no need for the chain connection */
if (2 > port_size) {
break;
}
/* Cascade the CCFF between head and tail */
BasicPort ccff_chain_input_port(ccff_ports[0].get_name(), port_size - 1);
BasicPort ccff_chain_output_port(ccff_ports[1].get_name(), 1, port_size - 1);
print_verilog_wire_connection(fp, ccff_chain_output_port, ccff_chain_input_port, false);
break;
}
case SPICE_SRAM_MEMORY_BANK: {
@ -776,59 +785,61 @@ void print_verilog_local_sram_wires(std::fstream& fp,
* ports of a CMOS (SRAM-based) routing multiplexer
* This port is supposed to be used locally inside a Verilog/SPICE module
*
* The following shows a few representative examples:
*
* For standalone configuration style:
* ------------------------------------
* No bus needed
*
* For configuration-chain configuration style:
* --------------------------------------------
* Configuration chain-style
* -------------------------
* wire [0:N] config_bus
*
* Module Port
* |
* v
* bus_port --------+----------------+----> ...
* | |
* sram_outputs v v
* +-----------+ +-----------+
* | Memory | | Memory |
* | Module[0] | | Module[1] | ...
* +-----------+ +-----------+
* | |
* v v
* +-----------+ +-----------+
* | Routing | | Routing |
* | MUX [0] | | MUX[1] | ...
* +-----------+ +-----------+
* config_bus config_bus config_bus config_bus
* [0] [1] [2] [N]
* | | | |
* v v v v
* ccff_head ----------+ +---------+ +------------+ +----> ccff_tail
* | ^ | ^ | ^
* head v |tail v | v |
* +----------+ +----------+ +----------+
* | Memory | | Memory | | Memory |
* | Module | | Module | ... | Module |
* | [0] | | [1] | | [N] |
* +----------+ +----------+ +----------+
* | | |
* v v v
* +----------+ +----------+ +----------+
* | MUX | | MUX | | MUX |
* | Module | | Module | ... | Module |
* | [0] | | [1] | | [N] |
* +----------+ +----------+ +----------+
*
* For memory-bank configuration style:
* ------------------------------------
*
* Module Port
* |
* v
* bus_port --------+----------------+----> ...
* | |
* bl/wl/../sram_ports v v
* +-----------+ +-----------+
* | Memory | | Memory |
* | Module[0] | | Module[1] | ...
* +-----------+ +-----------+
* | |
* v v
* +-----------+ +-----------+
* | Routing | | Routing |
* | MUX [0] | | MUX[1] | ...
* +-----------+ +-----------+
* Memory bank-style
* -----------------
* BL/WL bus --+------------+-------------------->
* | | |
* BL/WL v BL/WL v BL/WL v
* +----------+ +----------+ +----------+
* | Memory | | Memory | | Memory |
* | Module | | Module | ... | Module |
* | [0] | | [1] | | [N] |
* +----------+ +----------+ +----------+
* | | |
* v v v
* +----------+ +----------+ +----------+
* | MUX | | MUX | | MUX |
* | Module | | Module | ... | Module |
* | [0] | | [1] | | [N] |
* +----------+ +----------+ +----------+
*
*********************************************************************/
static
void print_verilog_cmos_mux_config_bus(std::fstream& fp,
const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model,
const e_sram_orgz& sram_orgz_type,
const size_t& mux_size,
const size_t& mux_instance_id,
const size_t& num_conf_bits) {
void print_verilog_local_config_bus(std::fstream& fp,
const std::string& prefix,
const e_sram_orgz& sram_orgz_type,
const size_t& instance_id,
const size_t& num_conf_bits) {
/* Make sure we have a valid file handler*/
check_file_handler(fp);
@ -838,78 +849,20 @@ void print_verilog_cmos_mux_config_bus(std::fstream& fp,
* The configuration ports of SRAM are directly wired to the ports of modules
*/
break;
case SPICE_SRAM_SCAN_CHAIN: {
/* To support chain-like configuration protocol, two configuration buses should be outputted
case SPICE_SRAM_SCAN_CHAIN:
case SPICE_SRAM_MEMORY_BANK: {
/* Two configuration buses should be outputted
* One for the regular SRAM ports of a routing multiplexer
* The other for the inverted SRAM ports of a routing multiplexer
*/
BasicPort config_port(generate_mux_sram_port_name(circuit_lib, mux_model, mux_size, mux_instance_id, SPICE_MODEL_PORT_INPUT),
BasicPort config_port(generate_local_sram_port_name(prefix, instance_id, SPICE_MODEL_PORT_INPUT),
num_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, config_port) << ";" << std::endl;
BasicPort inverted_config_port(generate_mux_sram_port_name(circuit_lib, mux_model, mux_size, mux_instance_id, SPICE_MODEL_PORT_OUTPUT),
BasicPort inverted_config_port(generate_local_sram_port_name(prefix, instance_id, SPICE_MODEL_PORT_OUTPUT),
num_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, inverted_config_port) << ";" << std::endl;
break;
}
case SPICE_SRAM_MEMORY_BANK: {
/* To support memory-bank configuration, SRAM outputs are supposed to be exposed to the upper level as buses
* In addition, the BL/WL ports should be grouped and be exposed to the upper level as buses
*/
/* Print configuration bus to group BL/WLs */
BasicPort bl_bus(generate_mux_config_bus_port_name(circuit_lib, mux_model, mux_size, 0, false),
num_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, bl_bus) << ";" << std::endl;
BasicPort wl_bus(generate_mux_config_bus_port_name(circuit_lib, mux_model, mux_size, 1, false),
num_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, wl_bus) << ";" << std::endl;
/* Print bus to group SRAM outputs, this is to interface memory cells to routing multiplexers */
BasicPort sram_output_bus(generate_mux_sram_port_name(circuit_lib, mux_model, mux_size, mux_instance_id, SPICE_MODEL_PORT_INPUT),
num_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, sram_output_bus) << ";" << std::endl;
BasicPort inverted_sram_output_bus(generate_mux_sram_port_name(circuit_lib, mux_model, mux_size, mux_instance_id, SPICE_MODEL_PORT_OUTPUT),
num_conf_bits);
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);
/* 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);
std::vector<CircuitPortId> wlb_ports = circuit_lib.model_ports_by_type(sram_models[0], SPICE_MODEL_PORT_WLB);
/* Connect SRAM BL/WLs to bus */
BasicPort mux_bl_wire(generate_sram_port_name(circuit_lib, sram_models[0], sram_orgz_type, SPICE_MODEL_PORT_BL),
num_conf_bits);
print_verilog_wire_connection(fp, bl_bus, mux_bl_wire, false);
BasicPort mux_wl_wire(generate_sram_port_name(circuit_lib, sram_models[0], sram_orgz_type, SPICE_MODEL_PORT_WL),
num_conf_bits);
print_verilog_wire_connection(fp, wl_bus, mux_wl_wire, false);
/* Print configuration bus to group BLBs, if the ports are available in SRAM models */
if (0 < blb_ports.size()) {
BasicPort blb_bus(generate_mux_config_bus_port_name(circuit_lib, mux_model, mux_size, 0, true),
num_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, blb_bus) << ";" << std::endl;
/* Connect SRAM BLBs to bus */
BasicPort mux_blb_wire(generate_sram_port_name(circuit_lib, sram_models[0], sram_orgz_type, SPICE_MODEL_PORT_BLB),
num_conf_bits);
print_verilog_wire_connection(fp, blb_bus, mux_blb_wire, false);
}
/* Print configuration bus to group WLBs, if the ports are available in SRAM models */
if (0 < wlb_ports.size()) {
BasicPort wlb_bus(generate_mux_config_bus_port_name(circuit_lib, mux_model, mux_size, 1, true),
num_conf_bits);
fp << generate_verilog_port(VERILOG_PORT_WIRE, wlb_bus) << ";" << std::endl;
/* Connect SRAM WLBs to bus */
BasicPort mux_wlb_wire(generate_sram_port_name(circuit_lib, sram_models[0], sram_orgz_type, SPICE_MODEL_PORT_WLB),
num_conf_bits);
print_verilog_wire_connection(fp, wlb_bus, mux_wlb_wire, false);
}
break;
}
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s,[LINE%d])Invalid SRAM organization!\n",
@ -998,7 +951,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() );
@ -1031,7 +984,11 @@ void print_verilog_rram_mux_config_bus(std::fstream& fp,
/*********************************************************************
* Print a number of bus ports which are wired to the configuration
* ports of a routing multiplexer
* ports of a memory module, which consists of a number of configuration
* memory cells, such as SRAMs.
* Note that the configuration bus will only interface the memory
* module, rather than the programming routing multiplexers, LUTs, IOs
* etc. This helps us to keep clean and simple Verilog generation
*********************************************************************/
void print_verilog_mux_config_bus(std::fstream& fp,
const CircuitLibrary& circuit_lib,
@ -1050,9 +1007,11 @@ void print_verilog_mux_config_bus(std::fstream& fp,
* Currently, this is fine.
*/
switch (circuit_lib.design_tech_type(mux_model)) {
case SPICE_MODEL_DESIGN_CMOS:
print_verilog_cmos_mux_config_bus(fp, circuit_lib, mux_model, sram_orgz_type, mux_size, mux_instance_id, num_conf_bits);
case SPICE_MODEL_DESIGN_CMOS: {
std::string prefix = generate_mux_subckt_name(circuit_lib, mux_model, mux_size, std::string());
print_verilog_local_config_bus(fp, prefix, sram_orgz_type, mux_instance_id, num_conf_bits);
break;
}
case SPICE_MODEL_DESIGN_RRAM:
print_verilog_rram_mux_config_bus(fp, circuit_lib, mux_model, sram_orgz_type, mux_size, mux_instance_id, num_reserved_conf_bits, num_conf_bits);
break;
@ -1078,7 +1037,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]),