Merge remote-tracking branch 'origin/dev' into heterogeneous
This commit is contained in:
commit
fdc3c5e4a9
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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!!!
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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]),
|
||||
|
|
Loading…
Reference in New Issue