refactoring mux Verilog generation for switch blocks
This commit is contained in:
parent
05eaa412b1
commit
f0589cc2cf
|
@ -32,8 +32,9 @@ class MuxLibrary {
|
|||
public: /* Public mutators */
|
||||
/* Add a mux to the library */
|
||||
void add_mux(const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model, const size_t& mux_size);
|
||||
private: /* Private accessors */
|
||||
public: /* Public validators */
|
||||
bool valid_mux_id(const MuxId& mux) const;
|
||||
private: /* Private accessors */
|
||||
bool valid_mux_lookup() const;
|
||||
bool valid_mux_circuit_model_id(const CircuitModelId& circuit_model) const;
|
||||
bool valid_mux_size(const CircuitModelId& circuit_model, const size_t& mux_size) const;
|
||||
|
|
|
@ -3,10 +3,12 @@
|
|||
* that are used to implement a multiplexer
|
||||
*************************************************/
|
||||
#include <cmath>
|
||||
#include <algorithm>
|
||||
|
||||
#include "spice_types.h"
|
||||
#include "util.h"
|
||||
#include "vtr_assert.h"
|
||||
#include "decoder_library_utils.h"
|
||||
#include "mux_utils.h"
|
||||
|
||||
/* Validate the number of inputs for a multiplexer implementation,
|
||||
|
@ -237,3 +239,50 @@ MuxLibrary convert_mux_arch_to_library(const CircuitLibrary& circuit_lib, t_llis
|
|||
|
||||
return mux_lib;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Find the number of reserved configuration bits for a multiplexer
|
||||
* The reserved configuration bits is only used by ReRAM-based multiplexers
|
||||
* It is actually the shared BL/WLs among ReRAMs
|
||||
*************************************************/
|
||||
size_t find_mux_num_reserved_config_bits(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const MuxGraph& mux_graph) {
|
||||
if (SPICE_MODEL_DESIGN_RRAM != circuit_lib.design_tech_type(mux_model)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<size_t> mux_branch_sizes = mux_graph.branch_sizes();
|
||||
/* For tree-like multiplexers: they have two shared configuration bits */
|
||||
if ( (1 == mux_branch_sizes.size())
|
||||
&& (2 == mux_branch_sizes[0]) ) {
|
||||
return mux_branch_sizes[0];
|
||||
}
|
||||
/* One-level multiplexer */
|
||||
if ( 1 == mux_graph.num_levels() ) {
|
||||
return mux_graph.num_inputs();
|
||||
}
|
||||
/* Multi-level multiplexers: TODO: This should be better tested and clarified
|
||||
* Now the multi-level multiplexers are treated as cascaded one-level multiplexers
|
||||
* Use the maximum branch sizes and multiply it by the number of levels
|
||||
*/
|
||||
std::vector<size_t>::iterator max_mux_branch_size = std::max_element(mux_branch_sizes.begin(), mux_branch_sizes.end());
|
||||
return mux_graph.num_levels() * (*max_mux_branch_size);
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Find the number of configuration bits for a multiplexer
|
||||
* In general, the number of configuration bits is
|
||||
* the number of memory bits for a mux_graph
|
||||
* However, when local decoders are used, this should be changed!
|
||||
*************************************************/
|
||||
size_t find_mux_num_config_bits(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const MuxGraph& mux_graph) {
|
||||
if (true == circuit_lib.mux_use_local_encoder(mux_model)) {
|
||||
return find_mux_local_decoder_addr_size(mux_graph.num_memory_bits());
|
||||
}
|
||||
|
||||
return mux_graph.num_memory_bits();
|
||||
}
|
||||
|
||||
|
|
|
@ -37,4 +37,12 @@ std::vector<bool> build_mux_intermediate_buffer_location_map(const CircuitLibrar
|
|||
|
||||
MuxLibrary convert_mux_arch_to_library(const CircuitLibrary& circuit_lib, t_llist* muxes_head);
|
||||
|
||||
size_t find_mux_num_reserved_config_bits(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const MuxGraph& mux_graph);
|
||||
|
||||
size_t find_mux_num_config_bits(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const MuxGraph& mux_graph);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -189,20 +189,20 @@ int multilevel_mux_last_level_input_num(int num_level, int num_input_per_unit,
|
|||
|
||||
/***************************************************************************************
|
||||
* Find the number of inputs for a encoder with a given output size
|
||||
* Inputs
|
||||
* | | | | |
|
||||
* +-----------+
|
||||
* / \
|
||||
* / Encoder \
|
||||
* +-----------------+
|
||||
* | | | | | | | |
|
||||
* Outputs
|
||||
*
|
||||
* The outputs are assumes to be one-hot codes (at most only one '1' exist)
|
||||
* Considering this fact, there are only num_of_outputs + 1 conditions to be encoded.
|
||||
* Therefore, the number of inputs is ceil(log(num_of_outputs+1)/log(2))
|
||||
* We plus 1, which is all-zero condition for outputs
|
||||
***************************************************************************************/
|
||||
* Inputs
|
||||
* | | | | |
|
||||
* +-----------+
|
||||
* / \
|
||||
* / Encoder \
|
||||
* +-----------------+
|
||||
* | | | | | | | |
|
||||
* Outputs
|
||||
*
|
||||
* The outputs are assumes to be one-hot codes (at most only one '1' exist)
|
||||
* Considering this fact, there are only num_of_outputs + 1 conditions to be encoded.
|
||||
* Therefore, the number of inputs is ceil(log(num_of_outputs+1)/log(2))
|
||||
* We plus 1, which is all-zero condition for outputs
|
||||
****************************************************************************************/
|
||||
int determine_mux_local_encoder_num_inputs(int num_outputs) {
|
||||
return ceil(log(num_outputs) / log(2));
|
||||
}
|
||||
|
|
|
@ -259,28 +259,28 @@ std::string generate_grid_port_name(const vtr::Point<size_t>& coordinate,
|
|||
const size_t& pin_id,
|
||||
const bool& for_top_netlist) {
|
||||
if (true == for_top_netlist) {
|
||||
std::string port_name = "grid_";
|
||||
std::string port_name = std::string("grid_");
|
||||
port_name += std::to_string(coordinate.x());
|
||||
port_name += "__";
|
||||
port_name += std::string("__");
|
||||
port_name += std::to_string(coordinate.y());
|
||||
port_name += "__pin_";
|
||||
port_name += std::string("__pin_");
|
||||
port_name += std::to_string(height);
|
||||
port_name += "__";
|
||||
port_name += std::string("__");
|
||||
port_name += std::to_string(size_t(side));
|
||||
port_name += "__";
|
||||
port_name += std::string("__");
|
||||
port_name += std::to_string(pin_id);
|
||||
port_name += "_";
|
||||
port_name += std::string("_");
|
||||
return port_name;
|
||||
}
|
||||
/* For non-top netlist */
|
||||
VTR_ASSERT( false == for_top_netlist );
|
||||
Side side_manager(side);
|
||||
std::string port_name = std::string(side_manager.to_string());
|
||||
port_name += "_height_";
|
||||
port_name += std::string("_height_");
|
||||
port_name += std::to_string(height);
|
||||
port_name += "__pin_";
|
||||
port_name += std::string("__pin_");
|
||||
port_name += std::to_string(pin_id);
|
||||
port_name += "_";
|
||||
port_name += std::string("_");
|
||||
return port_name;
|
||||
}
|
||||
|
||||
|
@ -456,3 +456,22 @@ std::string generate_sram_local_port_name(const CircuitLibrary& circuit_lib,
|
|||
|
||||
return port_name;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate the port name for the input bus of a routing multiplexer
|
||||
* This is very useful in Verilog code generation where the inputs of
|
||||
* a routing multiplexer may come from different ports.
|
||||
* On the other side, the datapath input of a routing multiplexer
|
||||
* is defined as a bus port.
|
||||
* Therefore, to interface, a bus port is required, and this function
|
||||
* give a name to the bus port
|
||||
* To keep the bus port name unique to each multiplexer we will instance,
|
||||
* a mux_instance_id should be provided by user
|
||||
*********************************************************************/
|
||||
std::string generate_mux_input_bus_port_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -82,4 +82,9 @@ std::string generate_sram_local_port_name(const CircuitLibrary& circuit_lib,
|
|||
const e_sram_orgz& sram_orgz_type,
|
||||
const e_spice_model_port_type& port_type);
|
||||
|
||||
std::string generate_mux_input_bus_port_name(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& mux_model,
|
||||
const size_t& mux_size,
|
||||
const size_t& mux_instance_id);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -64,9 +64,10 @@ class ModuleManager {
|
|||
void set_port_preproc_flag(const ModuleId& module, const ModulePortId& port, const std::string& preproc_flag);
|
||||
/* Add a child module to a parent module */
|
||||
void add_child_module(const ModuleId& parent_module, const ModuleId& child_module);
|
||||
private: /* Private validators/invalidators */
|
||||
public: /* Public validators/invalidators */
|
||||
bool valid_module_id(const ModuleId& module) const;
|
||||
bool valid_module_port_id(const ModuleId& module, const ModulePortId& port) const;
|
||||
private: /* Private validators/invalidators */
|
||||
void invalidate_name2id_map();
|
||||
void invalidate_port_lookup();
|
||||
private: /* Internal data */
|
||||
|
|
|
@ -118,7 +118,6 @@ void add_formal_verification_sram_ports_to_module_manager(ModuleManager& module_
|
|||
const ModuleId& module_id,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const e_sram_orgz sram_orgz_type,
|
||||
const std::string& preproc_flag,
|
||||
const size_t& port_size) {
|
||||
/* Create a port */
|
||||
|
|
|
@ -28,7 +28,6 @@ void add_formal_verification_sram_ports_to_module_manager(ModuleManager& module_
|
|||
const ModuleId& module_id,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const e_sram_orgz sram_orgz_type,
|
||||
const std::string& preproc_flag,
|
||||
const size_t& port_size);
|
||||
|
||||
|
|
|
@ -39,6 +39,7 @@
|
|||
#include "fpga_x2p_bitstream_utils.h"
|
||||
#include "fpga_x2p_globals.h"
|
||||
#include "fpga_x2p_naming.h"
|
||||
#include "mux_utils.h"
|
||||
#include "module_manager.h"
|
||||
#include "module_manager_utils.h"
|
||||
|
||||
|
@ -2167,6 +2168,92 @@ BasicPort generate_verilog_unique_switch_box_chan_port(const RRGSB& rr_sb,
|
|||
return BasicPort(chan_port_name, 1); /* Every track has a port size of 1 */
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate an input port for routing multiplexer inside the switch block
|
||||
* In addition to give the Routing Resource node of the input
|
||||
* Users should provide the side of input, which is different case by case:
|
||||
* 1. When the input is a pin of a CLB/Logic Block, the input_side should
|
||||
* be the side of the node on its grid!
|
||||
* For example, the input pin is on the top side of a switch block
|
||||
* but on the right side of a switch block
|
||||
* +--------+
|
||||
* | |
|
||||
* | Grid |---+
|
||||
* | | |
|
||||
* +--------+ v input_pin
|
||||
* +----------------+
|
||||
* | Switch Block |
|
||||
* +----------------+
|
||||
* 2. When the input is a routing track, the input_side should be
|
||||
* the side of the node locating on the switch block
|
||||
********************************************************************/
|
||||
static
|
||||
BasicPort generate_switch_block_input_port(const RRGSB& rr_sb,
|
||||
const e_side& input_side,
|
||||
t_rr_node* input_rr_node) {
|
||||
BasicPort input_port;
|
||||
/* Generate the input port object */
|
||||
switch (input_rr_node->type) {
|
||||
/* case SOURCE: */
|
||||
case OPIN: {
|
||||
/* Find the coordinator (grid_x and grid_y) for the input port */
|
||||
vtr::Point<size_t> input_port_coord(input_rr_node->xlow, input_rr_node->ylow);
|
||||
std::string input_port_name = generate_grid_side_port_name(input_port_coord,
|
||||
input_side,
|
||||
input_rr_node->ptc_num);
|
||||
input_port.set_name(input_port_name);
|
||||
input_port.set_width(1); /* Every grid output has a port size of 1 */
|
||||
break;
|
||||
}
|
||||
case CHANX:
|
||||
case CHANY: {
|
||||
input_port = generate_verilog_unique_switch_box_chan_port(rr_sb, input_side, input_rr_node, IN_PORT);
|
||||
break;
|
||||
}
|
||||
default: /* SOURCE, IPIN, SINK are invalid*/
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
return input_port;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Generate a list of input ports for routing multiplexer inside the switch block
|
||||
********************************************************************/
|
||||
static
|
||||
std::vector<BasicPort> generate_switch_block_input_ports(const RRGSB& rr_sb,
|
||||
const std::vector<t_rr_node*>& input_rr_nodes) {
|
||||
std::vector<BasicPort> input_ports;
|
||||
|
||||
for (auto input_rr_node : input_rr_nodes) {
|
||||
enum e_side input_pin_side = NUM_SIDES;
|
||||
switch (input_rr_node->type) {
|
||||
case OPIN:
|
||||
input_pin_side = rr_sb.get_opin_node_grid_side(input_rr_node);
|
||||
break;
|
||||
case CHANX:
|
||||
case CHANY: {
|
||||
/* The input could be at any side of the switch block, find it */
|
||||
int index = -1;
|
||||
rr_sb.get_node_side_and_index(input_rr_node, IN_PORT, &input_pin_side, &index);
|
||||
VTR_ASSERT(NUM_SIDES != input_pin_side);
|
||||
break;
|
||||
}
|
||||
default: /* SOURCE, IPIN, SINK are invalid*/
|
||||
vpr_printf(TIO_MESSAGE_ERROR,
|
||||
"(File:%s, [LINE%d])Invalid rr_node type! Should be [OPIN|CHANX|CHANY].\n",
|
||||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
input_ports.push_back(generate_switch_block_input_port(rr_sb, input_pin_side, input_rr_node));
|
||||
}
|
||||
|
||||
return input_ports;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Print a short interconneciton in switch box
|
||||
* There are two cases should be noticed.
|
||||
|
@ -2180,38 +2267,21 @@ void print_verilog_unique_switch_box_short_interc(std::fstream& fp,
|
|||
const RRGSB& rr_sb,
|
||||
const e_side& chan_side,
|
||||
t_rr_node* cur_rr_node,
|
||||
const size_t& actual_fan_in,
|
||||
t_rr_node* drive_rr_node) {
|
||||
/* Check the driver*/
|
||||
if (0 == actual_fan_in) {
|
||||
VTR_ASSERT(drive_rr_node == cur_rr_node);
|
||||
} else {
|
||||
VTR_ASSERT(1 == actual_fan_in);
|
||||
}
|
||||
|
||||
/* Check the file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Find the name of output port */
|
||||
BasicPort output_port = generate_verilog_unique_switch_box_chan_port(rr_sb, chan_side, cur_rr_node, OUT_PORT);
|
||||
/* Find the name of input port */
|
||||
BasicPort input_port;
|
||||
enum e_side input_pin_side = chan_side;
|
||||
|
||||
/* Generate the input port object */
|
||||
switch (drive_rr_node->type) {
|
||||
/* case SOURCE: */
|
||||
case OPIN: {
|
||||
/* Find the coordinator (grid_x and grid_y) for the input port */
|
||||
vtr::Point<size_t> input_port_coord(drive_rr_node->xlow, drive_rr_node->ylow);
|
||||
std::string input_port_name = generate_grid_side_port_name(input_port_coord,
|
||||
rr_sb.get_opin_node_grid_side(drive_rr_node),
|
||||
drive_rr_node->ptc_num);
|
||||
input_port.set_name(input_port_name);
|
||||
input_port.set_width(1); /* Every grid output has a port size of 1 */
|
||||
case OPIN:
|
||||
input_pin_side = rr_sb.get_opin_node_grid_side(drive_rr_node);
|
||||
break;
|
||||
}
|
||||
case CHANX:
|
||||
case CHANY: {
|
||||
enum e_side input_pin_side = chan_side;
|
||||
/* This should be an input in the data structure of RRGSB */
|
||||
if (cur_rr_node == drive_rr_node) {
|
||||
/* To be strict, the input should locate on the opposite side.
|
||||
|
@ -2224,8 +2294,6 @@ void print_verilog_unique_switch_box_short_interc(std::fstream& fp,
|
|||
int index = -1;
|
||||
rr_sb.get_node_side_and_index(drive_rr_node, IN_PORT, &input_pin_side, &index);
|
||||
}
|
||||
/* We need to be sure that drive_rr_node is part of the SB */
|
||||
input_port = generate_verilog_unique_switch_box_chan_port(rr_sb, input_pin_side, drive_rr_node, IN_PORT);
|
||||
break;
|
||||
}
|
||||
default: /* SOURCE, IPIN, SINK are invalid*/
|
||||
|
@ -2234,6 +2302,8 @@ void print_verilog_unique_switch_box_short_interc(std::fstream& fp,
|
|||
__FILE__, __LINE__);
|
||||
exit(1);
|
||||
}
|
||||
/* Find the name of input port */
|
||||
BasicPort input_port = generate_switch_block_input_port(rr_sb, input_pin_side, drive_rr_node);
|
||||
|
||||
/* Print the wire connection in Verilog format */
|
||||
print_verilog_comment(fp, std::string("----- Short connection " + output_port.get_name() + " -----"));
|
||||
|
@ -2241,6 +2311,145 @@ void print_verilog_unique_switch_box_short_interc(std::fstream& fp,
|
|||
fp << std::endl;
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
* Print a Verilog instance of a routing multiplexer as well as
|
||||
* associated memory modules for a connection inside a switch block
|
||||
********************************************************************/
|
||||
static
|
||||
void print_verilog_unique_switch_box_mux(ModuleManager& module_manager,
|
||||
std::fstream& fp,
|
||||
t_sram_orgz_info* cur_sram_orgz_info,
|
||||
const ModuleId& sb_module,
|
||||
const RRGSB& rr_sb,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const MuxLibrary& mux_lib,
|
||||
const std::vector<t_switch_inf>& rr_switches,
|
||||
const e_side& chan_side,
|
||||
t_rr_node* cur_rr_node,
|
||||
const std::vector<t_rr_node*>& drive_rr_nodes,
|
||||
const size_t& switch_index,
|
||||
const bool& is_explicit_mapping) {
|
||||
/* Check the file handler*/
|
||||
check_file_handler(fp);
|
||||
|
||||
/* Check */
|
||||
/* Check current rr_node is CHANX or CHANY*/
|
||||
VTR_ASSERT((CHANX == cur_rr_node->type)||(CHANY == cur_rr_node->type));
|
||||
|
||||
/* Get the circuit model id of the routing multiplexer */
|
||||
CircuitModelId mux_model = rr_switches[switch_index].circuit_model;
|
||||
|
||||
/* Find the input size of the implementation of a routing multiplexer */
|
||||
size_t datapath_mux_size = drive_rr_nodes.size();
|
||||
size_t impl_mux_size = find_mux_implementation_num_inputs(circuit_lib, mux_model, datapath_mux_size);
|
||||
VTR_ASSERT(true == valid_mux_implementation_num_inputs(impl_mux_size));
|
||||
|
||||
/* Get the multiplexing graph from the Mux Library */
|
||||
MuxId mux_id = mux_lib.mux_graph(mux_model, impl_mux_size);
|
||||
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(""));
|
||||
ModuleId mux_module = module_manager.find_module(mux_module_name);
|
||||
VTR_ASSERT (true == module_manager.valid_module_id(mux_module));
|
||||
|
||||
/* Get the MUX instance id from the module manager */
|
||||
size_t mux_instance_id = module_manager.num_instance(sb_module, mux_module);
|
||||
|
||||
/* Print the input bus for the inputs of a multiplexer
|
||||
* We use the datapath input size (mux_size) to name the bus
|
||||
* just to following the naming convention when the tool is built
|
||||
* The bus port size should be the input size of multiplexer implementation
|
||||
*/
|
||||
BasicPort inbus_port;
|
||||
inbus_port.set_name(generate_mux_input_bus_port_name(circuit_lib, mux_model, datapath_mux_size, mux_instance_id));
|
||||
inbus_port.set_width(datapath_mux_size);
|
||||
|
||||
/* 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!!!
|
||||
*/
|
||||
std::string mux_input_hie_path = std::string(rr_sb.gen_sb_verilog_instance_name()) + std::string("/")
|
||||
+ mux_module_name + std::string("_")
|
||||
+ std::to_string(mux_instance_id) + std::string("_/in");
|
||||
cur_rr_node->name_mux = my_strdup(mux_input_hie_path.c_str());
|
||||
|
||||
/* Generate input ports that are wired to the input bus of the routing multiplexer */
|
||||
std::vector<BasicPort> mux_input_ports = generate_switch_block_input_ports(rr_sb, drive_rr_nodes);
|
||||
/* Connect input ports to bus */
|
||||
fp << generate_verilog_local_wire(inbus_port, mux_input_ports);
|
||||
|
||||
/* TODO: Find the number of reserved configuration bits for the routing multiplexer
|
||||
num_mux_reserved_conf_bits = count_num_reserved_conf_bits_one_spice_model(verilog_model,
|
||||
cur_sram_orgz_info->type,
|
||||
mux_size);
|
||||
*/
|
||||
|
||||
/* TODO: Find the number of configuration bits for the routing multiplexer
|
||||
num_mux_conf_bits = count_num_conf_bits_one_spice_model(verilog_model,
|
||||
cur_sram_orgz_info->type,
|
||||
mux_size);
|
||||
*/
|
||||
|
||||
/* Print the configuration port bus */
|
||||
/* TODO: Print the configuration bus for the routing multiplexers
|
||||
dump_verilog_mux_config_bus(fp, verilog_model, cur_sram_orgz_info,
|
||||
mux_size, cur_num_sram, num_mux_reserved_conf_bits, num_mux_conf_bits);
|
||||
*/
|
||||
|
||||
/* Dump ports visible only during formal verification */
|
||||
fp << std::endl;
|
||||
print_verilog_preprocessing_flag(fp, std::string(verilog_formal_verification_preproc_flag));
|
||||
/* TODO: Print the SRAM configuration ports for formal verification
|
||||
dump_verilog_formal_verification_mux_sram_ports_wiring(fp, cur_sram_orgz_info,
|
||||
verilog_model, mux_size,
|
||||
cur_num_sram,
|
||||
cur_num_sram + num_mux_conf_bits - 1);
|
||||
*/
|
||||
print_verilog_endif(fp);
|
||||
|
||||
/* TODO: Instanciate the Mux Module */
|
||||
/* TODO: add global ports */
|
||||
/* TODO: add input bus port */
|
||||
/* TODO: add output port */
|
||||
/* TODO: Add different configuraton port for the routing multiplexer
|
||||
* Different design technology requires different configuration bus!
|
||||
dump_verilog_mux_config_bus_ports(fp, verilog_model, cur_sram_orgz_info,
|
||||
mux_size, cur_num_sram, num_mux_reserved_conf_bits,
|
||||
num_mux_conf_bits, is_explicit_mapping);
|
||||
*/
|
||||
|
||||
/* 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());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*********************************************************************
|
||||
* Print the Verilog modules for a interconnection inside switch block
|
||||
* The interconnection could be either a wire or a routing multiplexer,
|
||||
|
@ -2250,6 +2459,7 @@ static
|
|||
void print_verilog_unique_switch_box_interc(ModuleManager& module_manager,
|
||||
std::fstream& fp,
|
||||
t_sram_orgz_info* cur_sram_orgz_info,
|
||||
const ModuleId& sb_module,
|
||||
const RRGSB& rr_sb,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const MuxLibrary& mux_lib,
|
||||
|
@ -2257,42 +2467,38 @@ void print_verilog_unique_switch_box_interc(ModuleManager& module_manager,
|
|||
const e_side& chan_side,
|
||||
const size_t& chan_node_id,
|
||||
const bool& use_explicit_mapping) {
|
||||
int num_drive_rr_nodes = 0;
|
||||
t_rr_node** drive_rr_nodes = NULL;
|
||||
std::vector<t_rr_node*> drive_rr_nodes;
|
||||
|
||||
/* Get the node */
|
||||
t_rr_node* cur_rr_node = rr_sb.get_chan_node(chan_side, chan_node_id);
|
||||
|
||||
/* Determine if the interc lies inside a channel wire, that is interc between segments */
|
||||
/* Check each num_drive_rr_nodes, see if they appear in the cur_sb_info */
|
||||
if (true == rr_sb.is_sb_node_passing_wire(chan_side, chan_node_id)) {
|
||||
num_drive_rr_nodes = 0;
|
||||
drive_rr_nodes = NULL;
|
||||
} else {
|
||||
num_drive_rr_nodes = cur_rr_node->num_drive_rr_nodes;
|
||||
drive_rr_nodes = cur_rr_node->drive_rr_nodes;
|
||||
if (false == rr_sb.is_sb_node_passing_wire(chan_side, chan_node_id)) {
|
||||
for (int i = 0; i < cur_rr_node->num_drive_rr_nodes; ++i) {
|
||||
drive_rr_nodes.push_back(cur_rr_node->drive_rr_nodes[i]);
|
||||
}
|
||||
/* Special: if there are zero-driver nodes. We skip here */
|
||||
if (0 == num_drive_rr_nodes) {
|
||||
if (0 == drive_rr_nodes.size()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == num_drive_rr_nodes) {
|
||||
if (0 == drive_rr_nodes.size()) {
|
||||
/* Print a special direct connection*/
|
||||
print_verilog_unique_switch_box_short_interc(fp, rr_sb, chan_side, cur_rr_node,
|
||||
num_drive_rr_nodes, cur_rr_node);
|
||||
} else if (1 == num_drive_rr_nodes) {
|
||||
cur_rr_node);
|
||||
} else if (1 == drive_rr_nodes.size()) {
|
||||
/* Print a direct connection*/
|
||||
print_verilog_unique_switch_box_short_interc(fp, rr_sb, chan_side, cur_rr_node,
|
||||
num_drive_rr_nodes, drive_rr_nodes[DEFAULT_SWITCH_ID]);
|
||||
} else if (1 < num_drive_rr_nodes) {
|
||||
drive_rr_nodes[DEFAULT_SWITCH_ID]);
|
||||
} else if (1 < drive_rr_nodes.size()) {
|
||||
/* Print the multiplexer, fan_in >= 2 */
|
||||
/*
|
||||
dump_verilog_unique_switch_box_mux(cur_sram_orgz_info, fp, rr_sb, chan_side, cur_rr_node,
|
||||
num_drive_rr_nodes, drive_rr_nodes,
|
||||
cur_rr_node->drive_switches[DEFAULT_SWITCH_ID],
|
||||
is_explicit_mapping);
|
||||
*/
|
||||
print_verilog_unique_switch_box_mux(module_manager, fp, cur_sram_orgz_info,
|
||||
sb_module, rr_sb, circuit_lib, mux_lib,
|
||||
rr_switches, chan_side, cur_rr_node,
|
||||
drive_rr_nodes,
|
||||
cur_rr_node->drive_switches[DEFAULT_SWITCH_ID],
|
||||
use_explicit_mapping);
|
||||
} /*Nothing should be done else*/
|
||||
}
|
||||
|
||||
|
@ -2473,7 +2679,6 @@ void print_verilog_routing_switch_box_unique_module(ModuleManager& module_manage
|
|||
rr_gsb.get_sb_num_conf_bits());
|
||||
/* Add ports only visible during formal verification to the module */
|
||||
add_formal_verification_sram_ports_to_module_manager(module_manager, module_id, circuit_lib, sram_model,
|
||||
cur_sram_orgz_info->type,
|
||||
std::string(verilog_formal_verification_preproc_flag),
|
||||
rr_gsb.get_sb_num_conf_bits());
|
||||
}
|
||||
|
@ -2495,7 +2700,7 @@ void print_verilog_routing_switch_box_unique_module(ModuleManager& module_manage
|
|||
for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) {
|
||||
/* We care INC_DIRECTION tracks at this side*/
|
||||
if (OUT_PORT == rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) {
|
||||
print_verilog_unique_switch_box_interc(module_manager, fp, cur_sram_orgz_info, rr_sb,
|
||||
print_verilog_unique_switch_box_interc(module_manager, fp, cur_sram_orgz_info, module_id, rr_sb,
|
||||
circuit_lib, mux_lib, rr_switches,
|
||||
side_manager.get_side(),
|
||||
itrack, is_explicit_mapping);
|
||||
|
|
|
@ -994,7 +994,7 @@ void dump_verilog_cmos_mux_multilevel_structure(FILE* fp,
|
|||
if (TRUE == spice_model.design_tech_info.mux_info->local_encoder) {
|
||||
/* Get the number of inputs */
|
||||
int num_outputs = cur_num_input_basis;
|
||||
int num_inputs = determine_mux_local_encoder_num_inputs(num_outputs);
|
||||
int num_inputs = determine_mux_local_encoder_num_inputs(num_outputs);
|
||||
/* Find the decoder name */
|
||||
fprintf(fp, "%s %s_%d_ (",
|
||||
generate_verilog_decoder_subckt_name(num_inputs, num_outputs),
|
||||
|
|
|
@ -449,7 +449,7 @@ std::string generate_verilog_ports(const std::vector<BasicPort>& merged_ports) {
|
|||
if (&port != &merged_ports[0]) {
|
||||
verilog_line += ", ";
|
||||
}
|
||||
verilog_line += generate_verilog_port(VERILOG_PORT_CONKT, merged_ports[0]);
|
||||
verilog_line += generate_verilog_port(VERILOG_PORT_CONKT, port);
|
||||
}
|
||||
verilog_line += "}";
|
||||
|
||||
|
|
Loading…
Reference in New Issue