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 */
|
public: /* Public mutators */
|
||||||
/* Add a mux to the library */
|
/* Add a mux to the library */
|
||||||
void add_mux(const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model, const size_t& mux_size);
|
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;
|
bool valid_mux_id(const MuxId& mux) const;
|
||||||
|
private: /* Private accessors */
|
||||||
bool valid_mux_lookup() const;
|
bool valid_mux_lookup() const;
|
||||||
bool valid_mux_circuit_model_id(const CircuitModelId& circuit_model) 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;
|
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
|
* that are used to implement a multiplexer
|
||||||
*************************************************/
|
*************************************************/
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "spice_types.h"
|
#include "spice_types.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
#include "vtr_assert.h"
|
#include "vtr_assert.h"
|
||||||
|
#include "decoder_library_utils.h"
|
||||||
#include "mux_utils.h"
|
#include "mux_utils.h"
|
||||||
|
|
||||||
/* Validate the number of inputs for a multiplexer implementation,
|
/* 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;
|
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);
|
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
|
#endif
|
||||||
|
|
|
@ -202,7 +202,7 @@ int multilevel_mux_last_level_input_num(int num_level, int num_input_per_unit,
|
||||||
* Considering this fact, there are only num_of_outputs + 1 conditions to be encoded.
|
* 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))
|
* Therefore, the number of inputs is ceil(log(num_of_outputs+1)/log(2))
|
||||||
* We plus 1, which is all-zero condition for outputs
|
* We plus 1, which is all-zero condition for outputs
|
||||||
***************************************************************************************/
|
****************************************************************************************/
|
||||||
int determine_mux_local_encoder_num_inputs(int num_outputs) {
|
int determine_mux_local_encoder_num_inputs(int num_outputs) {
|
||||||
return ceil(log(num_outputs) / log(2));
|
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 size_t& pin_id,
|
||||||
const bool& for_top_netlist) {
|
const bool& for_top_netlist) {
|
||||||
if (true == 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 += std::to_string(coordinate.x());
|
||||||
port_name += "__";
|
port_name += std::string("__");
|
||||||
port_name += std::to_string(coordinate.y());
|
port_name += std::to_string(coordinate.y());
|
||||||
port_name += "__pin_";
|
port_name += std::string("__pin_");
|
||||||
port_name += std::to_string(height);
|
port_name += std::to_string(height);
|
||||||
port_name += "__";
|
port_name += std::string("__");
|
||||||
port_name += std::to_string(size_t(side));
|
port_name += std::to_string(size_t(side));
|
||||||
port_name += "__";
|
port_name += std::string("__");
|
||||||
port_name += std::to_string(pin_id);
|
port_name += std::to_string(pin_id);
|
||||||
port_name += "_";
|
port_name += std::string("_");
|
||||||
return port_name;
|
return port_name;
|
||||||
}
|
}
|
||||||
/* For non-top netlist */
|
/* For non-top netlist */
|
||||||
VTR_ASSERT( false == for_top_netlist );
|
VTR_ASSERT( false == for_top_netlist );
|
||||||
Side side_manager(side);
|
Side side_manager(side);
|
||||||
std::string port_name = std::string(side_manager.to_string());
|
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 += std::to_string(height);
|
||||||
port_name += "__pin_";
|
port_name += std::string("__pin_");
|
||||||
port_name += std::to_string(pin_id);
|
port_name += std::to_string(pin_id);
|
||||||
port_name += "_";
|
port_name += std::string("_");
|
||||||
return port_name;
|
return port_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -456,3 +456,22 @@ std::string generate_sram_local_port_name(const CircuitLibrary& circuit_lib,
|
||||||
|
|
||||||
return port_name;
|
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_sram_orgz& sram_orgz_type,
|
||||||
const e_spice_model_port_type& port_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
|
#endif
|
||||||
|
|
|
@ -64,9 +64,10 @@ class ModuleManager {
|
||||||
void set_port_preproc_flag(const ModuleId& module, const ModulePortId& port, const std::string& preproc_flag);
|
void set_port_preproc_flag(const ModuleId& module, const ModulePortId& port, const std::string& preproc_flag);
|
||||||
/* Add a child module to a parent module */
|
/* Add a child module to a parent module */
|
||||||
void add_child_module(const ModuleId& parent_module, const ModuleId& child_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_id(const ModuleId& module) const;
|
||||||
bool valid_module_port_id(const ModuleId& module, const ModulePortId& port) const;
|
bool valid_module_port_id(const ModuleId& module, const ModulePortId& port) const;
|
||||||
|
private: /* Private validators/invalidators */
|
||||||
void invalidate_name2id_map();
|
void invalidate_name2id_map();
|
||||||
void invalidate_port_lookup();
|
void invalidate_port_lookup();
|
||||||
private: /* Internal data */
|
private: /* Internal data */
|
||||||
|
|
|
@ -118,7 +118,6 @@ void add_formal_verification_sram_ports_to_module_manager(ModuleManager& module_
|
||||||
const ModuleId& module_id,
|
const ModuleId& module_id,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
const CircuitModelId& sram_model,
|
const CircuitModelId& sram_model,
|
||||||
const e_sram_orgz sram_orgz_type,
|
|
||||||
const std::string& preproc_flag,
|
const std::string& preproc_flag,
|
||||||
const size_t& port_size) {
|
const size_t& port_size) {
|
||||||
/* Create a port */
|
/* Create a port */
|
||||||
|
|
|
@ -28,7 +28,6 @@ void add_formal_verification_sram_ports_to_module_manager(ModuleManager& module_
|
||||||
const ModuleId& module_id,
|
const ModuleId& module_id,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
const CircuitModelId& sram_model,
|
const CircuitModelId& sram_model,
|
||||||
const e_sram_orgz sram_orgz_type,
|
|
||||||
const std::string& preproc_flag,
|
const std::string& preproc_flag,
|
||||||
const size_t& port_size);
|
const size_t& port_size);
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "fpga_x2p_bitstream_utils.h"
|
#include "fpga_x2p_bitstream_utils.h"
|
||||||
#include "fpga_x2p_globals.h"
|
#include "fpga_x2p_globals.h"
|
||||||
#include "fpga_x2p_naming.h"
|
#include "fpga_x2p_naming.h"
|
||||||
|
#include "mux_utils.h"
|
||||||
#include "module_manager.h"
|
#include "module_manager.h"
|
||||||
#include "module_manager_utils.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 */
|
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
|
* Print a short interconneciton in switch box
|
||||||
* There are two cases should be noticed.
|
* 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 RRGSB& rr_sb,
|
||||||
const e_side& chan_side,
|
const e_side& chan_side,
|
||||||
t_rr_node* cur_rr_node,
|
t_rr_node* cur_rr_node,
|
||||||
const size_t& actual_fan_in,
|
|
||||||
t_rr_node* drive_rr_node) {
|
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 the file handler*/
|
||||||
check_file_handler(fp);
|
check_file_handler(fp);
|
||||||
|
|
||||||
/* Find the name of output port */
|
/* 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);
|
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 */
|
enum e_side input_pin_side = chan_side;
|
||||||
BasicPort input_port;
|
|
||||||
/* Generate the input port object */
|
/* Generate the input port object */
|
||||||
switch (drive_rr_node->type) {
|
switch (drive_rr_node->type) {
|
||||||
/* case SOURCE: */
|
case OPIN:
|
||||||
case OPIN: {
|
input_pin_side = rr_sb.get_opin_node_grid_side(drive_rr_node);
|
||||||
/* 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 */
|
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
case CHANX:
|
case CHANX:
|
||||||
case CHANY: {
|
case CHANY: {
|
||||||
enum e_side input_pin_side = chan_side;
|
|
||||||
/* This should be an input in the data structure of RRGSB */
|
/* This should be an input in the data structure of RRGSB */
|
||||||
if (cur_rr_node == drive_rr_node) {
|
if (cur_rr_node == drive_rr_node) {
|
||||||
/* To be strict, the input should locate on the opposite side.
|
/* 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;
|
int index = -1;
|
||||||
rr_sb.get_node_side_and_index(drive_rr_node, IN_PORT, &input_pin_side, &index);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
default: /* SOURCE, IPIN, SINK are invalid*/
|
default: /* SOURCE, IPIN, SINK are invalid*/
|
||||||
|
@ -2234,6 +2302,8 @@ void print_verilog_unique_switch_box_short_interc(std::fstream& fp,
|
||||||
__FILE__, __LINE__);
|
__FILE__, __LINE__);
|
||||||
exit(1);
|
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 the wire connection in Verilog format */
|
||||||
print_verilog_comment(fp, std::string("----- Short connection " + output_port.get_name() + " -----"));
|
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;
|
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
|
* Print the Verilog modules for a interconnection inside switch block
|
||||||
* The interconnection could be either a wire or a routing multiplexer,
|
* 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,
|
void print_verilog_unique_switch_box_interc(ModuleManager& module_manager,
|
||||||
std::fstream& fp,
|
std::fstream& fp,
|
||||||
t_sram_orgz_info* cur_sram_orgz_info,
|
t_sram_orgz_info* cur_sram_orgz_info,
|
||||||
|
const ModuleId& sb_module,
|
||||||
const RRGSB& rr_sb,
|
const RRGSB& rr_sb,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
const MuxLibrary& mux_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 e_side& chan_side,
|
||||||
const size_t& chan_node_id,
|
const size_t& chan_node_id,
|
||||||
const bool& use_explicit_mapping) {
|
const bool& use_explicit_mapping) {
|
||||||
int num_drive_rr_nodes = 0;
|
std::vector<t_rr_node*> drive_rr_nodes;
|
||||||
t_rr_node** drive_rr_nodes = NULL;
|
|
||||||
|
|
||||||
/* Get the node */
|
/* Get the node */
|
||||||
t_rr_node* cur_rr_node = rr_sb.get_chan_node(chan_side, chan_node_id);
|
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 */
|
/* 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 (false == rr_sb.is_sb_node_passing_wire(chan_side, chan_node_id)) {
|
||||||
if (true == 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) {
|
||||||
num_drive_rr_nodes = 0;
|
drive_rr_nodes.push_back(cur_rr_node->drive_rr_nodes[i]);
|
||||||
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;
|
|
||||||
/* Special: if there are zero-driver nodes. We skip here */
|
/* Special: if there are zero-driver nodes. We skip here */
|
||||||
if (0 == num_drive_rr_nodes) {
|
if (0 == drive_rr_nodes.size()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 == num_drive_rr_nodes) {
|
if (0 == drive_rr_nodes.size()) {
|
||||||
/* Print a special direct connection*/
|
/* Print a special direct connection*/
|
||||||
print_verilog_unique_switch_box_short_interc(fp, rr_sb, chan_side, cur_rr_node,
|
print_verilog_unique_switch_box_short_interc(fp, rr_sb, chan_side, cur_rr_node,
|
||||||
num_drive_rr_nodes, cur_rr_node);
|
cur_rr_node);
|
||||||
} else if (1 == num_drive_rr_nodes) {
|
} else if (1 == drive_rr_nodes.size()) {
|
||||||
/* Print a direct connection*/
|
/* Print a direct connection*/
|
||||||
print_verilog_unique_switch_box_short_interc(fp, rr_sb, chan_side, cur_rr_node,
|
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]);
|
drive_rr_nodes[DEFAULT_SWITCH_ID]);
|
||||||
} else if (1 < num_drive_rr_nodes) {
|
} else if (1 < drive_rr_nodes.size()) {
|
||||||
/* Print the multiplexer, fan_in >= 2 */
|
/* Print the multiplexer, fan_in >= 2 */
|
||||||
/*
|
print_verilog_unique_switch_box_mux(module_manager, fp, cur_sram_orgz_info,
|
||||||
dump_verilog_unique_switch_box_mux(cur_sram_orgz_info, fp, rr_sb, chan_side, cur_rr_node,
|
sb_module, rr_sb, circuit_lib, mux_lib,
|
||||||
num_drive_rr_nodes, drive_rr_nodes,
|
rr_switches, chan_side, cur_rr_node,
|
||||||
|
drive_rr_nodes,
|
||||||
cur_rr_node->drive_switches[DEFAULT_SWITCH_ID],
|
cur_rr_node->drive_switches[DEFAULT_SWITCH_ID],
|
||||||
is_explicit_mapping);
|
use_explicit_mapping);
|
||||||
*/
|
|
||||||
} /*Nothing should be done else*/
|
} /*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());
|
rr_gsb.get_sb_num_conf_bits());
|
||||||
/* Add ports only visible during formal verification to the module */
|
/* 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,
|
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),
|
std::string(verilog_formal_verification_preproc_flag),
|
||||||
rr_gsb.get_sb_num_conf_bits());
|
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) {
|
for (size_t itrack = 0; itrack < rr_gsb.get_chan_width(side_manager.get_side()); ++itrack) {
|
||||||
/* We care INC_DIRECTION tracks at this side*/
|
/* We care INC_DIRECTION tracks at this side*/
|
||||||
if (OUT_PORT == rr_gsb.get_chan_node_direction(side_manager.get_side(), itrack)) {
|
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,
|
circuit_lib, mux_lib, rr_switches,
|
||||||
side_manager.get_side(),
|
side_manager.get_side(),
|
||||||
itrack, is_explicit_mapping);
|
itrack, is_explicit_mapping);
|
||||||
|
|
|
@ -449,7 +449,7 @@ std::string generate_verilog_ports(const std::vector<BasicPort>& merged_ports) {
|
||||||
if (&port != &merged_ports[0]) {
|
if (&port != &merged_ports[0]) {
|
||||||
verilog_line += ", ";
|
verilog_line += ", ";
|
||||||
}
|
}
|
||||||
verilog_line += generate_verilog_port(VERILOG_PORT_CONKT, merged_ports[0]);
|
verilog_line += generate_verilog_port(VERILOG_PORT_CONKT, port);
|
||||||
}
|
}
|
||||||
verilog_line += "}";
|
verilog_line += "}";
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue