1602 lines
67 KiB
C++
1602 lines
67 KiB
C++
/********************************************************************
|
|
* This file includes functions to generate module/port names for
|
|
* Verilog and SPICE netlists
|
|
*
|
|
* IMPORTANT: keep all the naming functions in this file to be
|
|
* generic for both Verilog and SPICE generators
|
|
********************************************************************/
|
|
#include "openfpga_naming.h"
|
|
|
|
#include "circuit_library_utils.h"
|
|
#include "openfpga_reserved_words.h"
|
|
#include "openfpga_side_manager.h"
|
|
#include "pb_type_utils.h"
|
|
#include "vtr_assert.h"
|
|
#include "vtr_log.h"
|
|
|
|
/* begin namespace openfpga */
|
|
namespace openfpga {
|
|
|
|
/************************************************
|
|
* A generic function to generate the instance name
|
|
* in the following format:
|
|
* <instance_name>_<id>_
|
|
* This is mainly used by module manager to give a default
|
|
* name for each instance when outputting the module
|
|
* in Verilog/SPICE format
|
|
***********************************************/
|
|
std::string generate_instance_name(const std::string& instance_name,
|
|
const size_t& instance_id) {
|
|
return instance_name + std::string("_") + std::to_string(instance_id) +
|
|
std::string("_");
|
|
}
|
|
|
|
/************************************************
|
|
* A generic function to generate the instance name
|
|
* in the following format:
|
|
* <instance_name>_<id>_
|
|
* This is mainly used by module manager to give a default
|
|
* name for each instance when outputting the module
|
|
* in Verilog/SPICE format
|
|
***********************************************/
|
|
std::string generate_instance_wildcard_name(const std::string& instance_name,
|
|
const std::string& wildcard_str) {
|
|
return instance_name + std::string("_") + wildcard_str + std::string("_");
|
|
}
|
|
|
|
/************************************************
|
|
* Generate the node name for a multiplexing structure
|
|
* Case 1 : If there is an intermediate buffer followed by,
|
|
* the node name will be mux_l<node_level>_in_buf
|
|
* Case 1 : If there is NO intermediate buffer followed by,
|
|
* the node name will be mux_l<node_level>_in
|
|
***********************************************/
|
|
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";
|
|
|
|
/* Add a postfix upon requests */
|
|
if (true == add_buffer_postfix) {
|
|
/* '1' indicates that the location is needed */
|
|
node_name += "_buf";
|
|
}
|
|
|
|
return node_name;
|
|
}
|
|
|
|
/************************************************
|
|
* Generate the instance name for a branch circuit in multiplexing structure
|
|
* Case 1 : If there is an intermediate buffer followed by,
|
|
* the node name will be mux_l<node_level>_in_buf
|
|
* Case 1 : If there is NO intermediate buffer followed by,
|
|
* the node name will be mux_l<node_level>_in
|
|
***********************************************/
|
|
std::string generate_mux_branch_instance_name(const size_t& node_level,
|
|
const size_t& node_index_at_level,
|
|
const bool& add_buffer_postfix) {
|
|
return std::string(generate_mux_node_name(node_level, add_buffer_postfix) +
|
|
"_" + std::to_string(node_index_at_level) + "_");
|
|
}
|
|
|
|
/************************************************
|
|
* Generate the module name for a multiplexer in Verilog format
|
|
* Different circuit model requires different names:
|
|
* 1. LUTs are named as <model_name>_mux
|
|
* 2. MUXes are named as <model_name>_size<num_inputs>
|
|
***********************************************/
|
|
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 (CIRCUIT_MODEL_MUX == circuit_lib.model_type(circuit_model)) {
|
|
module_name += "_size";
|
|
module_name += std::to_string(mux_size);
|
|
} else {
|
|
VTR_ASSERT(CIRCUIT_MODEL_LUT == circuit_lib.model_type(circuit_model));
|
|
module_name += "_mux";
|
|
}
|
|
|
|
/* Add postfix if it is not empty */
|
|
if (!postfix.empty()) {
|
|
module_name += postfix;
|
|
}
|
|
|
|
return module_name;
|
|
}
|
|
|
|
/************************************************
|
|
* Generate the module name of a branch for a
|
|
* multiplexer in Verilog format
|
|
***********************************************/
|
|
std::string generate_mux_branch_subckt_name(const CircuitLibrary& circuit_lib,
|
|
const CircuitModelId& circuit_model,
|
|
const size_t& branch_mux_size,
|
|
const size_t& branch_mem_size,
|
|
const std::string& postfix) {
|
|
/* If the tgate circuit model of this MUX is a MUX2 standard cell,
|
|
* the mux_subckt name will be the name of the standard cell
|
|
*/
|
|
CircuitModelId subckt_model =
|
|
circuit_lib.pass_gate_logic_model(circuit_model);
|
|
if (CIRCUIT_MODEL_GATE == circuit_lib.model_type(subckt_model)) {
|
|
VTR_ASSERT(CIRCUIT_MODEL_GATE_MUX2 == circuit_lib.gate_type(subckt_model));
|
|
return circuit_lib.model_name(subckt_model);
|
|
}
|
|
|
|
/* Include memory size as a second unique signature for the branch module
|
|
* This is due to some branch modules have the same input sizes but different
|
|
* memory sizes
|
|
*/
|
|
std::string branch_postfix = postfix + "_input" +
|
|
std::to_string(branch_mux_size) + "_mem" +
|
|
std::to_string(branch_mem_size);
|
|
|
|
std::string module_name = circuit_lib.model_name(circuit_model);
|
|
if (CIRCUIT_MODEL_LUT == circuit_lib.model_type(circuit_model)) {
|
|
module_name += "_mux";
|
|
} else {
|
|
VTR_ASSERT(CIRCUIT_MODEL_MUX == circuit_lib.model_type(circuit_model));
|
|
}
|
|
module_name += branch_postfix;
|
|
|
|
return module_name;
|
|
}
|
|
|
|
/************************************************
|
|
* Generate the module name of a local decoder
|
|
* for multiplexer
|
|
***********************************************/
|
|
std::string generate_mux_local_decoder_subckt_name(const size_t& addr_size,
|
|
const size_t& data_size) {
|
|
std::string subckt_name = "local_encoder";
|
|
subckt_name += std::to_string(addr_size);
|
|
subckt_name += "to";
|
|
subckt_name += std::to_string(data_size);
|
|
|
|
return subckt_name;
|
|
}
|
|
|
|
/************************************************
|
|
* Generate the module name of a decoder
|
|
* for frame-based memories
|
|
***********************************************/
|
|
std::string generate_memory_decoder_subckt_name(const size_t& addr_size,
|
|
const size_t& data_size) {
|
|
std::string subckt_name = "decoder";
|
|
subckt_name += std::to_string(addr_size);
|
|
subckt_name += "to";
|
|
subckt_name += std::to_string(data_size);
|
|
|
|
return subckt_name;
|
|
}
|
|
|
|
/************************************************
|
|
* Generate the module name of a word-line decoder
|
|
* for memories
|
|
***********************************************/
|
|
std::string generate_memory_decoder_with_data_in_subckt_name(
|
|
const size_t& addr_size, const size_t& data_size) {
|
|
std::string subckt_name = "decoder_with_data_in_";
|
|
subckt_name += std::to_string(addr_size);
|
|
subckt_name += "to";
|
|
subckt_name += std::to_string(data_size);
|
|
|
|
return subckt_name;
|
|
}
|
|
|
|
/************************************************
|
|
* Generate the module name of a routing track wire
|
|
***********************************************/
|
|
std::string generate_segment_wire_subckt_name(
|
|
const std::string& wire_model_name, const size_t& segment_id) {
|
|
std::string segment_wire_subckt_name =
|
|
wire_model_name + "_seg" + std::to_string(segment_id);
|
|
|
|
return segment_wire_subckt_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the port name for the mid-output of a routing track wire
|
|
* Mid-output is the output that is wired to a Connection block multiplexer.
|
|
*
|
|
* | CLB |
|
|
* +------------+
|
|
* ^
|
|
* |
|
|
* +------------------------------+
|
|
* | Connection block multiplexer |
|
|
* +------------------------------+
|
|
* ^
|
|
* | mid-output +--------------
|
|
* +--------------------+ |
|
|
* input --->| Routing track wire |--------->| Switch Block
|
|
* +--------------------+ output |
|
|
* +--------------
|
|
*
|
|
********************************************************************/
|
|
std::string generate_segment_wire_mid_output_name(
|
|
const std::string& regular_output_name) {
|
|
/* TODO: maybe have a postfix? */
|
|
return std::string("mid_" + regular_output_name);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the module name for a memory sub-circuit
|
|
* If this is a module just to feed through memory lines, use a special name
|
|
********************************************************************/
|
|
std::string generate_memory_module_name(const CircuitLibrary& circuit_lib,
|
|
const CircuitModelId& circuit_model,
|
|
const CircuitModelId& sram_model,
|
|
const std::string& postfix,
|
|
const bool& feedthrough_memory) {
|
|
std::string mid_name;
|
|
if (feedthrough_memory) {
|
|
mid_name = "feedthrough_";
|
|
}
|
|
return std::string(circuit_lib.model_name(circuit_model) + "_" + mid_name +
|
|
circuit_lib.model_name(sram_model) + postfix);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the netlist name for a unique routing block
|
|
* It could be
|
|
* 1. Routing channel
|
|
* 2. Connection block
|
|
* 3. Switch block
|
|
* A unique block id should be given
|
|
*********************************************************************/
|
|
std::string generate_routing_block_netlist_name(const std::string& prefix,
|
|
const size_t& block_id,
|
|
const std::string& postfix) {
|
|
return std::string(prefix + std::to_string(block_id) + postfix);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the netlist name for a routing block with a given coordinate
|
|
* It could be
|
|
* 1. Routing channel
|
|
* 2. Connection block
|
|
* 3. Switch block
|
|
*********************************************************************/
|
|
std::string generate_routing_block_netlist_name(
|
|
const std::string& prefix, const vtr::Point<size_t>& coordinate,
|
|
const std::string& postfix) {
|
|
return std::string(prefix + std::to_string(coordinate.x()) +
|
|
std::string("__") + std::to_string(coordinate.y()) +
|
|
std::string("_") + postfix);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the netlist name for a connection block with a given coordinate
|
|
*********************************************************************/
|
|
std::string generate_connection_block_netlist_name(
|
|
const t_rr_type& cb_type, const vtr::Point<size_t>& coordinate,
|
|
const std::string& postfix) {
|
|
std::string prefix("cb");
|
|
switch (cb_type) {
|
|
case CHANX:
|
|
prefix += std::string("x_");
|
|
break;
|
|
case CHANY:
|
|
prefix += std::string("y_");
|
|
break;
|
|
default:
|
|
VTR_LOG_ERROR("Invalid type of connection block!\n");
|
|
exit(1);
|
|
}
|
|
|
|
return generate_routing_block_netlist_name(prefix, coordinate, postfix);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the module name for a unique routing channel
|
|
*********************************************************************/
|
|
std::string generate_routing_channel_module_name(const t_rr_type& chan_type,
|
|
const size_t& block_id) {
|
|
/* Channel must be either CHANX or CHANY */
|
|
VTR_ASSERT((CHANX == chan_type) || (CHANY == chan_type));
|
|
|
|
/* Create a map between chan_type and module_prefix */
|
|
std::map<t_rr_type, std::string> module_prefix_map;
|
|
/* TODO: use a constexpr string to replace the fixed name? */
|
|
module_prefix_map[CHANX] = std::string("chanx");
|
|
module_prefix_map[CHANY] = std::string("chany");
|
|
|
|
return std::string(module_prefix_map[chan_type] + std::string("_") +
|
|
std::to_string(block_id) + std::string("_"));
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the module name for a routing channel with a given coordinate
|
|
*********************************************************************/
|
|
std::string generate_routing_channel_module_name(
|
|
const t_rr_type& chan_type, const vtr::Point<size_t>& coordinate) {
|
|
/* Channel must be either CHANX or CHANY */
|
|
VTR_ASSERT((CHANX == chan_type) || (CHANY == chan_type));
|
|
|
|
/* Create a map between chan_type and module_prefix */
|
|
std::map<t_rr_type, std::string> module_prefix_map;
|
|
/* TODO: use a constexpr string to replace the fixed name? */
|
|
module_prefix_map[CHANX] = std::string("chanx");
|
|
module_prefix_map[CHANY] = std::string("chany");
|
|
|
|
return std::string(module_prefix_map[chan_type] +
|
|
std::to_string(coordinate.x()) + std::string("_") +
|
|
std::to_string(coordinate.y()) + std::string("_"));
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the port name for a routing track with a given coordinate
|
|
* and port direction
|
|
* This function is mainly used in naming routing tracks in the top-level
|
|
*netlists where we do need unique names (with coordinates) for each routing
|
|
*tracks
|
|
*********************************************************************/
|
|
std::string generate_routing_track_port_name(
|
|
const t_rr_type& chan_type, const vtr::Point<size_t>& coordinate,
|
|
const size_t& track_id, const PORTS& port_direction) {
|
|
/* Channel must be either CHANX or CHANY */
|
|
VTR_ASSERT((CHANX == chan_type) || (CHANY == chan_type));
|
|
|
|
/* Create a map between chan_type and module_prefix */
|
|
std::map<t_rr_type, std::string> module_prefix_map;
|
|
/* TODO: use a constexpr string to replace the fixed name? */
|
|
module_prefix_map[CHANX] = std::string("chanx");
|
|
module_prefix_map[CHANY] = std::string("chany");
|
|
|
|
std::string port_name = module_prefix_map[chan_type];
|
|
port_name +=
|
|
std::string("_" + std::to_string(coordinate.x()) + std::string("__") +
|
|
std::to_string(coordinate.y()) + std::string("__"));
|
|
|
|
switch (port_direction) {
|
|
case OUT_PORT:
|
|
port_name += std::string("out_");
|
|
break;
|
|
case IN_PORT:
|
|
port_name += std::string("in_");
|
|
break;
|
|
default:
|
|
VTR_LOG_ERROR("Invalid direction of chan_rr_node!\n");
|
|
exit(1);
|
|
}
|
|
|
|
/* Add the track id to the port name */
|
|
port_name += std::to_string(track_id) + std::string("_");
|
|
|
|
return port_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the port name for a routing track in a Switch Block module
|
|
* This function is created to ease the PnR for each unique routing module
|
|
* So it is mainly used when creating non-top-level modules!
|
|
* Note that this function does not include any port coordinate
|
|
* Instead, we use the relative location of the pins in the context of routing
|
|
*modules so that each module can be instanciated across the fabric Even though,
|
|
*port direction must be provided!
|
|
*********************************************************************/
|
|
std::string generate_sb_module_track_port_name(const t_rr_type& chan_type,
|
|
const e_side& module_side,
|
|
const PORTS& port_direction) {
|
|
/* Channel must be either CHANX or CHANY */
|
|
VTR_ASSERT((CHANX == chan_type) || (CHANY == chan_type));
|
|
|
|
/* Create a map between chan_type and module_prefix */
|
|
std::map<t_rr_type, std::string> module_prefix_map;
|
|
/* TODO: use a constexpr string to replace the fixed name? */
|
|
module_prefix_map[CHANX] = std::string("chanx");
|
|
module_prefix_map[CHANY] = std::string("chany");
|
|
|
|
std::string port_name = module_prefix_map[chan_type];
|
|
port_name += std::string("_");
|
|
|
|
SideManager side_manager(module_side);
|
|
port_name += std::string(side_manager.to_string());
|
|
port_name += std::string("_");
|
|
|
|
switch (port_direction) {
|
|
case OUT_PORT:
|
|
port_name += std::string("out");
|
|
break;
|
|
case IN_PORT:
|
|
port_name += std::string("in");
|
|
break;
|
|
default:
|
|
VTR_LOG_ERROR("Invalid direction of chan_rr_node!\n");
|
|
exit(1);
|
|
}
|
|
|
|
return port_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Get the physical side for a routing track in a Connection Block module
|
|
* Upper_location: specify if an upper/lower prefix to be added.
|
|
* The location indicates where the bus port should be
|
|
* placed on the perimeter of the connection block
|
|
* - For X-directional CB:
|
|
* - upper is the left side
|
|
* - lower is the right side
|
|
* - For Y-directional CB:
|
|
* - upper is the bottom side
|
|
* - lower is the top side
|
|
*********************************************************************/
|
|
e_side get_cb_module_track_port_side(const t_rr_type& chan_type,
|
|
const bool& upper_location) {
|
|
/* Channel must be either CHANX or CHANY */
|
|
VTR_ASSERT((CHANX == chan_type) || (CHANY == chan_type));
|
|
|
|
/* Create a map between chan_type and module_prefix */
|
|
std::map<t_rr_type, std::map<bool, e_side>> port_side_map;
|
|
/* TODO: use a constexpr string to replace the fixed name? */
|
|
/* IMPORTANT: This part must be consistent with the mapping in the generate_cb_module_track_port_name() !!! */
|
|
port_side_map[CHANX][true] = LEFT;
|
|
port_side_map[CHANX][false] = RIGHT;
|
|
port_side_map[CHANY][true] = BOTTOM;
|
|
port_side_map[CHANY][false] = TOP;
|
|
return port_side_map[chan_type][upper_location];
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the port name for a routing track in a Connection Block module
|
|
* This function is created to ease the PnR for each unique routing module
|
|
* So it is mainly used when creating non-top-level modules!
|
|
* Note that this function does not include any port coordinate
|
|
* Instead, we use the relative location of the pins in the context of routing
|
|
*modules so that each module can be instanciated across the fabric Even though,
|
|
*port direction must be provided!
|
|
*
|
|
* Upper_location: specify if an upper/lower prefix to be added.
|
|
* The location indicates where the bus port should be
|
|
* placed on the perimeter of the connection block
|
|
* - For X-directional CB:
|
|
* - upper is the left side
|
|
* - lower is the right side
|
|
* - For Y-directional CB:
|
|
* - upper is the bottom side
|
|
* - lower is the top side
|
|
*********************************************************************/
|
|
std::string generate_cb_module_track_port_name(const t_rr_type& chan_type,
|
|
const PORTS& port_direction,
|
|
const bool& upper_location) {
|
|
/* Channel must be either CHANX or CHANY */
|
|
VTR_ASSERT((CHANX == chan_type) || (CHANY == chan_type));
|
|
|
|
/* Create a map between chan_type and module_prefix */
|
|
std::map<t_rr_type, std::map<bool, std::string>> module_prefix_map;
|
|
/* TODO: use a constexpr string to replace the fixed name? */
|
|
module_prefix_map[CHANX][true] = std::string("chanx_left");
|
|
module_prefix_map[CHANX][false] = std::string("chanx_right");
|
|
module_prefix_map[CHANY][true] = std::string("chany_bottom");
|
|
module_prefix_map[CHANY][false] = std::string("chany_top");
|
|
|
|
std::string port_name = module_prefix_map[chan_type][upper_location];
|
|
port_name += std::string("_");
|
|
|
|
switch (port_direction) {
|
|
case OUT_PORT:
|
|
port_name += std::string("out");
|
|
break;
|
|
case IN_PORT:
|
|
port_name += std::string("in");
|
|
break;
|
|
default:
|
|
VTR_LOG_ERROR("Invalid direction of chan_rr_node!\n");
|
|
exit(1);
|
|
}
|
|
|
|
return port_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the middle output port name for a routing track
|
|
* with a given coordinate
|
|
*********************************************************************/
|
|
std::string generate_routing_track_middle_output_port_name(
|
|
const t_rr_type& chan_type, const vtr::Point<size_t>& coordinate,
|
|
const size_t& track_id) {
|
|
/* Channel must be either CHANX or CHANY */
|
|
VTR_ASSERT((CHANX == chan_type) || (CHANY == chan_type));
|
|
|
|
/* Create a map between chan_type and module_prefix */
|
|
std::map<t_rr_type, std::string> module_prefix_map;
|
|
/* TODO: use a constexpr string to replace the fixed name? */
|
|
module_prefix_map[CHANX] = std::string("chanx");
|
|
module_prefix_map[CHANY] = std::string("chany");
|
|
|
|
std::string port_name = module_prefix_map[chan_type];
|
|
port_name +=
|
|
std::string("_" + std::to_string(coordinate.x()) + std::string("__") +
|
|
std::to_string(coordinate.y()) + std::string("__"));
|
|
|
|
port_name += std::string("midout_");
|
|
|
|
/* Add the track id to the port name */
|
|
port_name += std::to_string(track_id) + std::string("_");
|
|
|
|
return port_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the module name for a switch block with a given coordinate
|
|
*********************************************************************/
|
|
std::string generate_switch_block_module_name(
|
|
const vtr::Point<size_t>& coordinate) {
|
|
return std::string("sb_" + std::to_string(coordinate.x()) +
|
|
std::string("__") + std::to_string(coordinate.y()) +
|
|
std::string("_"));
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the module name for a switch block with a given index
|
|
*********************************************************************/
|
|
std::string generate_switch_block_module_name_using_index(const size_t& index) {
|
|
return std::string("sb_" + std::to_string(index) + std::string("_"));
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the module name for a tile module with a given coordinate
|
|
*********************************************************************/
|
|
std::string generate_tile_module_name(const vtr::Point<size_t>& tile_coord) {
|
|
return std::string("tile_" + std::to_string(tile_coord.x()) + "__" +
|
|
std::to_string(tile_coord.y()) + "_");
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the module name for a tile module with a given index
|
|
*********************************************************************/
|
|
std::string generate_tile_module_name_using_index(const size_t& index) {
|
|
return std::string("tile_" + std::to_string(index) + "_");
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the port name for a tile. Note that use the index to make the tile
|
|
*port name unique!
|
|
*********************************************************************/
|
|
std::string generate_tile_module_port_name(const std::string& prefix,
|
|
const std::string& port_name) {
|
|
return prefix + std::string("_") + port_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the netlist name of a grid block
|
|
**********************************************************************/
|
|
std::string generate_tile_module_netlist_name(const std::string& block_name,
|
|
const std::string& postfix) {
|
|
return block_name + postfix;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the module name of a physical memory module
|
|
**********************************************************************/
|
|
std::string generate_physical_memory_module_name(const std::string& prefix,
|
|
const size_t& mem_size) {
|
|
return prefix + std::string("_config_group_mem_size") +
|
|
std::to_string(mem_size);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the module name for a connection block with a given coordinate
|
|
*********************************************************************/
|
|
std::string generate_connection_block_module_name(
|
|
const t_rr_type& cb_type, const vtr::Point<size_t>& coordinate) {
|
|
std::string prefix("cb");
|
|
switch (cb_type) {
|
|
case CHANX:
|
|
prefix += std::string("x_");
|
|
break;
|
|
case CHANY:
|
|
prefix += std::string("y_");
|
|
break;
|
|
default:
|
|
VTR_LOG_ERROR("Invalid type of connection block!\n");
|
|
exit(1);
|
|
}
|
|
|
|
return std::string(prefix + std::to_string(coordinate.x()) +
|
|
std::string("__") + std::to_string(coordinate.y()) +
|
|
std::string("_"));
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the module name for a connection block with a given index
|
|
*********************************************************************/
|
|
std::string generate_connection_block_module_name_using_index(
|
|
const t_rr_type& cb_type, const size_t& index) {
|
|
std::string prefix("cb");
|
|
switch (cb_type) {
|
|
case CHANX:
|
|
prefix += std::string("x_");
|
|
break;
|
|
case CHANY:
|
|
prefix += std::string("y_");
|
|
break;
|
|
default:
|
|
VTR_LOG_ERROR("Invalid type of connection block!\n");
|
|
exit(1);
|
|
}
|
|
|
|
return std::string(prefix + std::to_string(index) + std::string("_"));
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the port name for a grid in top-level netlists, i.e., full FPGA
|
|
*fabric This function will generate a full port name including coordinates so
|
|
*that each pin in top-level netlists is unique!
|
|
*********************************************************************/
|
|
std::string generate_grid_port_name(const size_t& width, const size_t& height,
|
|
const int& subtile_index,
|
|
const e_side& side,
|
|
const BasicPort& pin_info) {
|
|
/* Ensure that the pin is 1-bit ONLY !!! */
|
|
VTR_ASSERT(1 == pin_info.get_width());
|
|
|
|
SideManager side_manager(side);
|
|
std::string port_name = std::string(side_manager.to_string());
|
|
port_name += std::string("_width_");
|
|
port_name += std::to_string(width);
|
|
port_name += std::string("_height_");
|
|
port_name += std::to_string(height);
|
|
port_name += std::string("_subtile_");
|
|
port_name += std::to_string(subtile_index);
|
|
port_name += std::string("__pin_");
|
|
port_name += pin_info.get_name();
|
|
port_name += std::string("_");
|
|
port_name += std::to_string(pin_info.get_lsb());
|
|
port_name += std::string("_");
|
|
return port_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the port name for a grid with duplication
|
|
* This function will generate two types of port names.
|
|
* One with a postfix of "upper"
|
|
* The other with a postfix of "lower"
|
|
*********************************************************************/
|
|
std::string generate_grid_duplicated_port_name(
|
|
const size_t& width, const size_t& height, const int& subtile_index,
|
|
const e_side& side, const BasicPort& pin_info, const bool& upper_port) {
|
|
/* Ensure that the pin is 1-bit ONLY !!! */
|
|
VTR_ASSERT(1 == pin_info.get_width());
|
|
|
|
SideManager side_manager(side);
|
|
std::string port_name = std::string(side_manager.to_string());
|
|
port_name += std::string("_width_");
|
|
port_name += std::to_string(width);
|
|
port_name += std::string("_height_");
|
|
port_name += std::to_string(height);
|
|
port_name += std::string("_subtile_");
|
|
port_name += std::to_string(subtile_index);
|
|
port_name += std::string("__pin_");
|
|
port_name += pin_info.get_name();
|
|
port_name += std::string("_");
|
|
port_name += std::to_string(pin_info.get_lsb());
|
|
port_name += std::string("_");
|
|
|
|
if (true == upper_port) {
|
|
port_name += std::string("upper");
|
|
} else {
|
|
VTR_ASSERT_SAFE(false == upper_port);
|
|
port_name += std::string("lower");
|
|
}
|
|
|
|
return port_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the port name for a grid in the context of a routing module
|
|
* To keep a short and simple name, this function will not
|
|
* include any grid coorindate information!
|
|
**********************************************************************/
|
|
std::string generate_routing_module_grid_port_name(const size_t& width,
|
|
const size_t& height,
|
|
const int& subtile_index,
|
|
const e_side& side,
|
|
const BasicPort& pin_info) {
|
|
/* For non-top netlist */
|
|
std::string port_name = std::string("grid_");
|
|
return port_name +
|
|
generate_grid_port_name(width, height, subtile_index, side, pin_info);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the port name for a reserved sram port, i.e., BLB/WL port
|
|
* When port_type is BLB, a string denoting to the reserved BLB port is
|
|
*generated When port_type is WL, a string denoting to the reserved WL port is
|
|
*generated
|
|
*
|
|
* DO NOT put any SRAM organization check codes HERE!!!
|
|
* Even though the reserved BLB/WL ports are used by RRAM-based FPGA only,
|
|
* try to keep this function does simple job.
|
|
* Check codes should be added outside, when print the ports to files!!!
|
|
*********************************************************************/
|
|
std::string generate_reserved_sram_port_name(
|
|
const e_circuit_model_port_type& port_type) {
|
|
VTR_ASSERT((port_type == CIRCUIT_MODEL_PORT_BLB) ||
|
|
(port_type == CIRCUIT_MODEL_PORT_WL));
|
|
|
|
if (CIRCUIT_MODEL_PORT_BLB == port_type) {
|
|
return std::string("reserved_blb");
|
|
}
|
|
return std::string("reserved_wl");
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the port name for a sram port, used for formal verification
|
|
* The port name is named after the cell name of SRAM in circuit library
|
|
*********************************************************************/
|
|
std::string generate_formal_verification_sram_port_name(
|
|
const CircuitLibrary& circuit_lib, const CircuitModelId& sram_model) {
|
|
std::string port_name =
|
|
circuit_lib.model_name(sram_model) + std::string("_out_fm");
|
|
|
|
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(CONFIGURABLE_MEMORY_CHAIN_IN_NAME);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* 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(CONFIGURABLE_MEMORY_CHAIN_OUT_NAME);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the memory output port name of a configurable memory
|
|
* TODO: This could be replaced as a constexpr string
|
|
*********************************************************************/
|
|
std::string generate_configurable_memory_data_out_name() {
|
|
return std::string(CONFIGURABLE_MEMORY_DATA_OUT_NAME);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the inverted memory output port name of a configurable memory
|
|
* TODO: This could be replaced as a constexpr string
|
|
*********************************************************************/
|
|
std::string generate_configurable_memory_inverted_data_out_name() {
|
|
return std::string(CONFIGURABLE_MEMORY_INVERTED_DATA_OUT_NAME);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* 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
|
|
* The port name is named after the cell name of SRAM in circuit library
|
|
*********************************************************************/
|
|
std::string generate_sram_port_name(
|
|
const e_config_protocol_type& sram_orgz_type,
|
|
const e_circuit_model_port_type& port_type) {
|
|
std::string port_name;
|
|
|
|
switch (sram_orgz_type) {
|
|
case CONFIG_MEM_FEEDTHROUGH:
|
|
/* Two types of ports are available:
|
|
* (1) BL indicates the mem port
|
|
* (2) BLB indicates the inverted mem port
|
|
*
|
|
* mem mem_inv
|
|
* [0] [0]
|
|
* | |
|
|
* v v
|
|
* +----------------+
|
|
* | Virtual Mem |
|
|
* +----------------+
|
|
*/
|
|
if (CIRCUIT_MODEL_PORT_BL == port_type) {
|
|
port_name = std::string(MEMORY_FEEDTHROUGH_DATA_IN_PORT_NAME);
|
|
} else {
|
|
VTR_ASSERT(CIRCUIT_MODEL_PORT_BLB == port_type);
|
|
port_name = std::string(MEMORY_FEEDTHROUGH_DATA_IN_INV_PORT_NAME);
|
|
}
|
|
break;
|
|
case CONFIG_MEM_SCAN_CHAIN:
|
|
/* Two types of ports are available:
|
|
* (1) Head of a chain of Configuration-chain Flip-Flops (CCFFs), enabled
|
|
* by port type of INPUT (2) Tail of a chian of Configuration-chain
|
|
* Flip-flops (CCFFs), enabled by port type of OUTPUT
|
|
* +------+ +------+ +------+
|
|
* Head --->| CCFF |--->| CCFF |--->| CCFF |---> Tail
|
|
* +------+ +------+ +------+
|
|
*/
|
|
if (CIRCUIT_MODEL_PORT_INPUT == port_type) {
|
|
port_name = std::string("ccff_head");
|
|
} else {
|
|
VTR_ASSERT(CIRCUIT_MODEL_PORT_OUTPUT == port_type);
|
|
port_name = std::string("ccff_tail");
|
|
}
|
|
break;
|
|
case CONFIG_MEM_STANDALONE:
|
|
case CONFIG_MEM_QL_MEMORY_BANK:
|
|
case CONFIG_MEM_MEMORY_BANK:
|
|
/* Two types of ports are available:
|
|
* (1) Bit Lines (BLs) of a SRAM cell, enabled by port type of BL
|
|
* (2) Word Lines (WLs) of a SRAM cell, enabled by port type of WL
|
|
*
|
|
* BL WL BL WL BL WL
|
|
* [0] [0] [1] [1] [i] [i]
|
|
* ^ ^ ^ ^ ^ ^
|
|
* | | | | | |
|
|
* +----------+ +----------+ +----------+
|
|
* | SRAM | | SRAM | ... | SRAM |
|
|
* +----------+ +----------+ +----------+
|
|
*/
|
|
if (CIRCUIT_MODEL_PORT_BL == port_type) {
|
|
port_name = std::string(MEMORY_BL_PORT_NAME);
|
|
} else if (CIRCUIT_MODEL_PORT_WL == port_type) {
|
|
port_name = std::string(MEMORY_WL_PORT_NAME);
|
|
} else {
|
|
VTR_ASSERT(CIRCUIT_MODEL_PORT_WLR == port_type);
|
|
port_name = std::string(MEMORY_WLR_PORT_NAME);
|
|
}
|
|
break;
|
|
case CONFIG_MEM_FRAME_BASED:
|
|
/* Only one input port is required, which is the address port
|
|
*
|
|
* EN ADDR DATA_IN
|
|
* | | |
|
|
* v v v
|
|
* +---------------------------------+
|
|
* | Frame decoder |
|
|
* +---------------------------------+
|
|
*
|
|
*/
|
|
VTR_ASSERT(port_type == CIRCUIT_MODEL_PORT_INPUT);
|
|
port_name = std::string(DECODER_ADDRESS_PORT_NAME);
|
|
break;
|
|
default:
|
|
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
|
"Invalid type of SRAM organization !\n");
|
|
exit(1);
|
|
}
|
|
|
|
return port_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the port name for a regular sram port which is an internal
|
|
* wire of a module
|
|
* The port name is named after the cell name of SRAM in circuit library
|
|
*********************************************************************/
|
|
std::string generate_sram_local_port_name(
|
|
const CircuitLibrary& circuit_lib, const CircuitModelId& sram_model,
|
|
const e_config_protocol_type& sram_orgz_type,
|
|
const e_circuit_model_port_type& port_type) {
|
|
std::string port_name = circuit_lib.model_name(sram_model) + std::string("_");
|
|
|
|
switch (sram_orgz_type) {
|
|
case CONFIG_MEM_STANDALONE: {
|
|
/* Two types of ports are available:
|
|
* (1) Regular output of a SRAM, enabled by port type of INPUT
|
|
* (2) Inverted output of a SRAM, enabled by port type of OUTPUT
|
|
*/
|
|
if (CIRCUIT_MODEL_PORT_INPUT == port_type) {
|
|
port_name += std::string("out_local_bus");
|
|
} else {
|
|
VTR_ASSERT(CIRCUIT_MODEL_PORT_OUTPUT == port_type);
|
|
port_name += std::string("outb_local_bus");
|
|
}
|
|
break;
|
|
}
|
|
case CONFIG_MEM_SCAN_CHAIN:
|
|
/* Three types of ports are available:
|
|
* (1) Input of Configuration-chain Flip-Flops (CCFFs), enabled by port
|
|
* type of INPUT (2) Output of a chian of Configuration-chain Flip-flops
|
|
* (CCFFs), enabled by port type of OUTPUT (2) Inverted output of a chian
|
|
* of Configuration-chain Flip-flops (CCFFs), enabled by port type of
|
|
* INOUT
|
|
* +------+ +------+ +------+
|
|
* Head --->| CCFF |--->| CCFF |--->| CCFF |---> Tail
|
|
* +------+ +------+ +------+
|
|
*/
|
|
if (CIRCUIT_MODEL_PORT_INPUT == port_type) {
|
|
port_name += std::string("ccff_in_local_bus");
|
|
} else if (CIRCUIT_MODEL_PORT_OUTPUT == port_type) {
|
|
port_name += std::string("ccff_out_local_bus");
|
|
} else {
|
|
VTR_ASSERT(CIRCUIT_MODEL_PORT_INOUT == port_type);
|
|
port_name += std::string("ccff_outb_local_bus");
|
|
}
|
|
break;
|
|
case CONFIG_MEM_MEMORY_BANK: {
|
|
/* Two types of ports are available:
|
|
* (1) Regular output of a SRAM, enabled by port type of INPUT
|
|
* (2) Inverted output of a SRAM, enabled by port type of OUTPUT
|
|
*/
|
|
if (CIRCUIT_MODEL_PORT_INPUT == port_type) {
|
|
port_name += std::string("out_local_bus");
|
|
} else {
|
|
VTR_ASSERT(CIRCUIT_MODEL_PORT_OUTPUT == port_type);
|
|
port_name += std::string("outb_local_bus");
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
VTR_LOG_ERROR("Invalid type of SRAM organization !\n");
|
|
exit(1);
|
|
}
|
|
|
|
return port_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the BL/WL port names for the top-level module of an FPGA fabric
|
|
* Each BL/WL bus drive a specific configuration region has an unique name
|
|
*********************************************************************/
|
|
std::string generate_regional_blwl_port_name(
|
|
const std::string& blwl_port_prefix, const ConfigRegionId& region_id) {
|
|
return blwl_port_prefix + std::string("_config_region_") +
|
|
std::to_string(size_t(region_id));
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the module name for a shift register chain which configures BLs
|
|
*********************************************************************/
|
|
std::string generate_bl_shift_register_module_name(
|
|
const std::string& memory_model_name, const size_t& shift_register_size) {
|
|
return std::string("bl_shift_register_") + memory_model_name +
|
|
std::string("_size") + std::to_string(shift_register_size);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the module name for a shift register chain which configures WLs
|
|
*********************************************************************/
|
|
std::string generate_wl_shift_register_module_name(
|
|
const std::string& memory_model_name, const size_t& shift_register_size) {
|
|
return std::string("wl_shift_register_") + memory_model_name +
|
|
std::string("_size") + std::to_string(shift_register_size);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* 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_mux_subckt_name(circuit_lib, mux_model, mux_size, postfix);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the name of a bus port which is wired to the configuration
|
|
* ports of a routing multiplexer
|
|
* This port is supposed to be used locally inside a Verilog/SPICE module
|
|
*********************************************************************/
|
|
std::string generate_mux_config_bus_port_name(const CircuitLibrary& circuit_lib,
|
|
const CircuitModelId& mux_model,
|
|
const size_t& mux_size,
|
|
const size_t& bus_id,
|
|
const bool& inverted) {
|
|
std::string postfix = std::string("_configbus") + std::to_string(bus_id);
|
|
/* Add a bar to the end of the name for inverted bus ports */
|
|
if (true == inverted) {
|
|
postfix += std::string("_b");
|
|
}
|
|
|
|
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_circuit_model_port_type& port_type) {
|
|
std::string port_name = port_prefix + std::string("_") +
|
|
std::to_string(instance_id) + std::string("_");
|
|
|
|
if (CIRCUIT_MODEL_PORT_INPUT == port_type) {
|
|
port_name += std::string("out");
|
|
} else {
|
|
VTR_ASSERT(CIRCUIT_MODEL_PORT_OUTPUT == port_type);
|
|
port_name += std::string("outb");
|
|
}
|
|
|
|
return port_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the port name for a SRAM port of a routing multiplexer
|
|
* This name is used for local wires that connecting SRAM ports
|
|
* 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_circuit_model_port_type& port_type) {
|
|
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);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the netlist name of a logical tile
|
|
**********************************************************************/
|
|
std::string generate_logical_tile_netlist_name(
|
|
const std::string& prefix, const t_pb_graph_node* pb_graph_head,
|
|
const std::string& postfix) {
|
|
/* Add the name of physical block */
|
|
std::string module_name =
|
|
prefix + generate_physical_block_module_name(pb_graph_head->pb_type);
|
|
|
|
module_name += postfix;
|
|
|
|
return module_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the prefix for naming a grid block netlist or a grid module
|
|
* This function will consider the io side and add it to the prefix
|
|
**********************************************************************/
|
|
std::string generate_grid_block_prefix(const std::string& prefix,
|
|
const e_side& io_side) {
|
|
std::string block_prefix(prefix);
|
|
|
|
if (NUM_SIDES != io_side) {
|
|
SideManager side_manager(io_side);
|
|
block_prefix += std::string(side_manager.to_string());
|
|
block_prefix += std::string("_");
|
|
}
|
|
|
|
return block_prefix;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the netlist name of a grid block
|
|
**********************************************************************/
|
|
std::string generate_grid_block_netlist_name(const std::string& block_name,
|
|
const bool& is_block_io,
|
|
const e_side& io_side,
|
|
const std::string& postfix) {
|
|
/* Add the name of physical block */
|
|
std::string module_name(block_name);
|
|
|
|
if ((true == is_block_io) && (NUM_SIDES != io_side)) {
|
|
SideManager side_manager(io_side);
|
|
module_name += std::string("_");
|
|
module_name += std::string(side_manager.to_string());
|
|
}
|
|
|
|
module_name += postfix;
|
|
|
|
return module_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the module name of a grid block
|
|
**********************************************************************/
|
|
std::string generate_grid_block_module_name(const std::string& prefix,
|
|
const std::string& block_name,
|
|
const bool& is_block_io,
|
|
const e_side& io_side) {
|
|
std::string module_name(prefix);
|
|
|
|
module_name += generate_grid_block_netlist_name(block_name, is_block_io,
|
|
io_side, std::string());
|
|
|
|
return module_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the instance name for a programmable routing multiplexer module
|
|
* in a Switch Block
|
|
* To keep a unique name in each module and also consider unique routing
|
|
*modules, please do NOT include any coordinates in the naming!!! Consider only
|
|
*relative coordinate, such as side!
|
|
********************************************************************/
|
|
std::string generate_sb_mux_instance_name(const std::string& prefix,
|
|
const e_side& sb_side,
|
|
const size_t& track_id,
|
|
const std::string& postfix) {
|
|
std::string instance_name(prefix);
|
|
instance_name += SideManager(sb_side).to_string();
|
|
instance_name += std::string("_track_") + std::to_string(track_id);
|
|
instance_name += postfix;
|
|
|
|
return instance_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the instance name for a configurable memory module in a Switch Block
|
|
* To keep a unique name in each module and also consider unique routing
|
|
*modules, please do NOT include any coordinates in the naming!!! Consider only
|
|
*relative coordinate, such as side!
|
|
********************************************************************/
|
|
std::string generate_sb_memory_instance_name(const std::string& prefix,
|
|
const e_side& sb_side,
|
|
const size_t& track_id,
|
|
const std::string& postfix,
|
|
const bool& feedthrough_memory) {
|
|
std::string instance_name(prefix);
|
|
if (feedthrough_memory) {
|
|
instance_name = std::string("feedthrough_") + instance_name;
|
|
}
|
|
instance_name += SideManager(sb_side).to_string();
|
|
instance_name += std::string("_track_") + std::to_string(track_id);
|
|
instance_name += postfix;
|
|
|
|
return instance_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the instance name for a programmable routing multiplexer module
|
|
* in a Connection Block
|
|
* To keep a unique name in each module and also consider unique routing
|
|
*modules, please do NOT include any coordinates in the naming!!! Consider only
|
|
*relative coordinate, such as side!
|
|
********************************************************************/
|
|
std::string generate_cb_mux_instance_name(const std::string& prefix,
|
|
const e_side& cb_side,
|
|
const size_t& pin_id,
|
|
const std::string& postfix) {
|
|
std::string instance_name(prefix);
|
|
|
|
instance_name += SideManager(cb_side).to_string();
|
|
instance_name += std::string("_ipin_") + std::to_string(pin_id);
|
|
instance_name += postfix;
|
|
|
|
return instance_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the instance name for a configurable memory module in a Connection
|
|
*Block To keep a unique name in each module and also consider unique routing
|
|
*modules, please do NOT include any coordinates in the naming!!! Consider only
|
|
*relative coordinate, such as side!
|
|
********************************************************************/
|
|
std::string generate_cb_memory_instance_name(const std::string& prefix,
|
|
const e_side& cb_side,
|
|
const size_t& pin_id,
|
|
const std::string& postfix,
|
|
const bool& feedthrough_memory) {
|
|
std::string instance_name(prefix);
|
|
if (feedthrough_memory) {
|
|
instance_name = std::string("feedthrough_") + instance_name;
|
|
}
|
|
|
|
instance_name += SideManager(cb_side).to_string();
|
|
instance_name += std::string("_ipin_") + std::to_string(pin_id);
|
|
instance_name += postfix;
|
|
|
|
return instance_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the instance name for a programmable routing multiplexer
|
|
* module in a physical block of a grid
|
|
* To guarentee a unique name for pb_graph pin,
|
|
* the instance name includes the index of parent node
|
|
* as well as the port name and pin index of this pin
|
|
*
|
|
* Exceptions:
|
|
* For OUTPUT ports, due to hierarchical module organization,
|
|
* their parent nodes will be uniquified
|
|
* So, we should not add any index here
|
|
********************************************************************/
|
|
std::string generate_pb_mux_instance_name(const std::string& prefix,
|
|
t_pb_graph_pin* pb_graph_pin,
|
|
const std::string& postfix) {
|
|
std::string instance_name(prefix);
|
|
instance_name += std::string(pb_graph_pin->parent_node->pb_type->name);
|
|
|
|
if (IN_PORT == pb_graph_pin->port->type) {
|
|
instance_name += std::string("_");
|
|
instance_name += std::to_string(pb_graph_pin->parent_node->placement_index);
|
|
}
|
|
|
|
instance_name += std::string("_");
|
|
instance_name += std::string(pb_graph_pin->port->name);
|
|
instance_name += std::string("_");
|
|
instance_name += std::to_string(pb_graph_pin->pin_number);
|
|
instance_name += postfix;
|
|
|
|
return instance_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the instance name for a configurable memory module in a
|
|
* physical block of a grid
|
|
* To guarentee a unique name for pb_graph pin,
|
|
* the instance name includes the index of parent node
|
|
* as well as the port name and pin index of this pin
|
|
*
|
|
* Exceptions:
|
|
* For OUTPUT ports, due to hierarchical module organization,
|
|
* their parent nodes will be uniquified
|
|
* So, we should not add any index here
|
|
********************************************************************/
|
|
std::string generate_pb_memory_instance_name(const std::string& prefix,
|
|
t_pb_graph_pin* pb_graph_pin,
|
|
const std::string& postfix,
|
|
const bool& feedthrough_memory) {
|
|
std::string mid_name = feedthrough_memory ? "virtual_" : "";
|
|
std::string instance_name(mid_name + prefix);
|
|
instance_name += std::string(pb_graph_pin->parent_node->pb_type->name);
|
|
|
|
if (IN_PORT == pb_graph_pin->port->type) {
|
|
instance_name += std::string("_");
|
|
instance_name += std::to_string(pb_graph_pin->parent_node->placement_index);
|
|
}
|
|
|
|
instance_name += std::string("_");
|
|
instance_name += std::string(pb_graph_pin->port->name);
|
|
instance_name += std::string("_");
|
|
instance_name += std::to_string(pb_graph_pin->pin_number);
|
|
instance_name += postfix;
|
|
|
|
return instance_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the instance name of a grid block
|
|
**********************************************************************/
|
|
std::string generate_grid_block_instance_name(
|
|
const std::string& prefix, const std::string& block_name,
|
|
const bool& is_block_io, const e_side& io_side,
|
|
const vtr::Point<size_t>& grid_coord) {
|
|
std::string module_name(prefix);
|
|
|
|
module_name += generate_grid_block_netlist_name(block_name, is_block_io,
|
|
io_side, std::string());
|
|
module_name += std::string("_");
|
|
module_name += std::to_string(grid_coord.x());
|
|
module_name += std::string("__");
|
|
module_name += std::to_string(grid_coord.y());
|
|
module_name += std::string("_");
|
|
|
|
return module_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the module name of a logical block type (pb_type)
|
|
* Since the logical block does not carry any physical attributes,
|
|
* this logical block will have a common prefix 'logical_type'
|
|
* To ensure a unique name for each physical block inside the graph of complex
|
|
*blocks (pb_graph_nodes), this function trace backward to the top-level node in
|
|
*the graph and add the name of these parents The final name will be in the
|
|
*following format:
|
|
* <top_physical_block_name>_<mode_name>_<parent_physical_block_name> ...
|
|
*<current_physical_block_name>
|
|
*
|
|
* TODO: to make sure the length of this name does not exceed the size of
|
|
* chars in a line of a file!!!
|
|
**********************************************************************/
|
|
std::string generate_physical_block_module_name(t_pb_type* physical_pb_type) {
|
|
std::string module_name(physical_pb_type->name);
|
|
|
|
t_pb_type* parent_pb_type = physical_pb_type;
|
|
|
|
/* Backward trace until we meet the top-level pb_type */
|
|
while (1) {
|
|
/* If there is no parent mode, this is a top-level pb_type, quit the loop
|
|
* here */
|
|
t_mode* parent_mode = parent_pb_type->parent_mode;
|
|
if (NULL == parent_mode) {
|
|
break;
|
|
}
|
|
|
|
/* Add the mode name to the module name */
|
|
module_name = std::string("mode_") + std::string(parent_mode->name) +
|
|
std::string("__") + module_name;
|
|
|
|
/* Backtrace to the upper level */
|
|
parent_pb_type = parent_mode->parent_pb_type;
|
|
|
|
/* If there is no parent pb_type, this is a top-level pb_type, quit the loop
|
|
* here */
|
|
if (NULL == parent_pb_type) {
|
|
break;
|
|
}
|
|
|
|
/* Add the current pb_type name to the module name */
|
|
module_name =
|
|
std::string(parent_pb_type->name) + std::string("_") + module_name;
|
|
}
|
|
|
|
/* Exception for top-level pb_type: add an virtual mode name (same name as the
|
|
* pb_type) This is to follow the naming convention as non top-level pb_types
|
|
* In addition, the name can be really unique, being different than the grid
|
|
* blocks
|
|
*/
|
|
if (NULL == physical_pb_type->parent_mode) {
|
|
module_name += std::string("_mode_") + std::string(physical_pb_type->name) +
|
|
std::string("_");
|
|
}
|
|
|
|
/* Add the prefix */
|
|
module_name = LOGICAL_MODULE_NAME_PREFIX + module_name;
|
|
|
|
return module_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the instance name for physical block with a given index
|
|
**********************************************************************/
|
|
std::string generate_physical_block_instance_name(t_pb_type* pb_type,
|
|
const size_t& index) {
|
|
std::string instance_name = generate_physical_block_module_name(pb_type);
|
|
/* Add index to the name */
|
|
instance_name += std::string("_");
|
|
instance_name += std::to_string(index);
|
|
|
|
return instance_name;
|
|
}
|
|
|
|
/********************************************************************
|
|
* This function try to infer if a grid locates at the border of a
|
|
* FPGA fabric, i.e., TOP/RIGHT/BOTTOM/LEFT sides
|
|
* 1. if this grid is on the border, it will return the side it locates,
|
|
* 2. if this grid is in the center, it will return an valid value NUM_SIDES
|
|
*
|
|
* In this function, we assume that the corner grids are actually empty!
|
|
*
|
|
* +-------+ +----------------------------+ +-------+
|
|
* | EMPTY | | TOP side I/O | | EMPTY |
|
|
* +-------+ +----------------------------+ +-------+
|
|
*
|
|
* +-------+ +----------------------------+ +-------+
|
|
* | | | | | |
|
|
* | | | | | |
|
|
* | | | | | |
|
|
* | LEFT | | | | RIGHT |
|
|
* | side | | Core grids | | side |
|
|
* | I/O | | | | I/O |
|
|
* | | | | | |
|
|
* | | | | | |
|
|
* | | | | | |
|
|
* | | | | | |
|
|
* +-------+ +----------------------------+ +-------+
|
|
*
|
|
* +-------+ +----------------------------+ +-------+
|
|
* | EMPTY | | BOTTOM side I/O | | EMPTY |
|
|
* +-------+ +----------------------------+ +-------+
|
|
*******************************************************************/
|
|
e_side find_grid_border_side(const vtr::Point<size_t>& device_size,
|
|
const vtr::Point<size_t>& grid_coordinate) {
|
|
e_side grid_side = NUM_SIDES;
|
|
|
|
if (device_size.y() - 1 == grid_coordinate.y()) {
|
|
return TOP;
|
|
}
|
|
if (device_size.x() - 1 == grid_coordinate.x()) {
|
|
return RIGHT;
|
|
}
|
|
if (0 == grid_coordinate.y()) {
|
|
return BOTTOM;
|
|
}
|
|
if (0 == grid_coordinate.x()) {
|
|
return LEFT;
|
|
}
|
|
|
|
return grid_side;
|
|
}
|
|
|
|
/********************************************************************
|
|
* This function try to infer if a grid locates at the border of the
|
|
* core FPGA fabric, i.e., TOP/RIGHT/BOTTOM/LEFT sides
|
|
* 1. if this grid is on the border and it matches the given side, return true,
|
|
* 2. if this grid is in the center, return false
|
|
*
|
|
* In this function, we assume that the corner grids are actually empty!
|
|
*
|
|
* +-------+ +----------------------------+ +-------+
|
|
* | EMPTY | | TOP side I/O | | EMPTY |
|
|
* +-------+ +----------------------------+ +-------+
|
|
*
|
|
* +-------+ +----------------------------+ +-------+
|
|
* | | | TOP | | |
|
|
* | | |----------------------------| | |
|
|
* | | | | | | | |
|
|
* | LEFT | | | | | | RIGHT |
|
|
* | side | | LEFT | Core grids | RIGHT| | side |
|
|
* | I/O | | | | | | I/O |
|
|
* | | | | | | | |
|
|
* | | | | | | | |
|
|
* | | |---------------------| | | |
|
|
* | | | BOTTOM | | | |
|
|
* +-------+ +----------------------------+ +-------+
|
|
*
|
|
* +-------+ +----------------------------+ +-------+
|
|
* | EMPTY | | BOTTOM side I/O | | EMPTY |
|
|
* +-------+ +----------------------------+ +-------+
|
|
*
|
|
* Note: for the blocks on the four corners of the core grids
|
|
* Please refer to the figure above to infer its border_side
|
|
*******************************************************************/
|
|
bool is_core_grid_on_given_border_side(
|
|
const vtr::Point<size_t>& device_size,
|
|
const vtr::Point<size_t>& grid_coordinate, const e_side& border_side) {
|
|
if ((device_size.y() - 2 == grid_coordinate.y()) && (TOP == border_side)) {
|
|
return true;
|
|
}
|
|
if ((device_size.x() - 2 == grid_coordinate.x()) && (RIGHT == border_side)) {
|
|
return true;
|
|
}
|
|
if ((1 == grid_coordinate.y()) && (BOTTOM == border_side)) {
|
|
return true;
|
|
}
|
|
if ((1 == grid_coordinate.x()) && (LEFT == border_side)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the port name of a Verilog module describing a pb_type
|
|
* The name convention is
|
|
* <pb_type_name>_<port_name>
|
|
********************************************************************/
|
|
std::string generate_pb_type_port_name(t_pb_type* pb_type,
|
|
t_port* pb_type_port) {
|
|
std::string port_name;
|
|
|
|
port_name = std::string(pb_type->name) + std::string("_") +
|
|
std::string(pb_type_port->name);
|
|
|
|
return port_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the port name of a Verilog module describing a pb_type
|
|
* The name convention is
|
|
* <pb_type_name>_<port_name>
|
|
*
|
|
* This is a wrapper on the generate_pb_type_port_name() function
|
|
* which can infer the parent_pb_type
|
|
********************************************************************/
|
|
std::string generate_pb_type_port_name(t_port* pb_type_port) {
|
|
return generate_pb_type_port_name(pb_type_port->parent_pb_type, pb_type_port);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the global I/O port name of a Verilog module
|
|
* This is mainly used by I/O circuit models
|
|
********************************************************************/
|
|
std::string generate_fpga_global_io_port_name(
|
|
const std::string& prefix, const CircuitLibrary& circuit_lib,
|
|
const CircuitModelId& circuit_model, const CircuitPortId& circuit_port) {
|
|
std::string port_name(prefix);
|
|
|
|
port_name += circuit_lib.model_name(circuit_model);
|
|
port_name += std::string("_");
|
|
port_name += circuit_lib.port_prefix(circuit_port);
|
|
|
|
return port_name;
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the module name for the top-level module
|
|
* The top-level module is actually the FPGA fabric
|
|
* We give a fixed name here, because it is independent from benchmark file
|
|
********************************************************************/
|
|
std::string generate_fpga_top_module_name() {
|
|
return std::string(FPGA_TOP_MODULE_NAME);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the module name for the fpga core module
|
|
* We give a fixed name here, because it is independent from benchmark file
|
|
********************************************************************/
|
|
std::string generate_fpga_core_module_name() {
|
|
return std::string(FPGA_CORE_MODULE_NAME);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the module name for the fpga core module
|
|
* We give a fixed name here, because it is independent from benchmark file
|
|
********************************************************************/
|
|
std::string generate_fpga_core_instance_name() {
|
|
return std::string(FPGA_CORE_INSTANCE_NAME);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the netlist name for the top-level module
|
|
* The top-level module is actually the FPGA fabric
|
|
* We give a fixed name here, because it is independent from benchmark file
|
|
********************************************************************/
|
|
std::string generate_fpga_top_netlist_name(const std::string& postfix) {
|
|
return std::string(FPGA_TOP_MODULE_NAME + postfix);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the netlist name for the top-level module
|
|
* The top-level module is actually the FPGA fabric
|
|
* We give a fixed name here, because it is independent from benchmark file
|
|
********************************************************************/
|
|
std::string generate_fpga_core_netlist_name(const std::string& postfix) {
|
|
return std::string(FPGA_CORE_MODULE_NAME + postfix);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the module name for a constant generator
|
|
* either VDD or GND, depending on the input argument
|
|
********************************************************************/
|
|
std::string generate_const_value_module_name(const size_t& const_val) {
|
|
if (0 == const_val) {
|
|
return std::string("const0");
|
|
}
|
|
|
|
VTR_ASSERT(1 == const_val);
|
|
return std::string("const1");
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the output port name for a constant generator module
|
|
* either VDD or GND, depending on the input argument
|
|
********************************************************************/
|
|
std::string generate_const_value_module_output_port_name(
|
|
const size_t& const_val) {
|
|
return generate_const_value_module_name(const_val);
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Generate the analysis SDC file name
|
|
* The format is
|
|
* <circuit_name>_<postfix>
|
|
********************************************************************/
|
|
std::string generate_analysis_sdc_file_name(
|
|
const std::string& circuit_name, const std::string& file_name_postfix) {
|
|
return circuit_name + "_" + file_name_postfix;
|
|
}
|
|
|
|
} /* end namespace openfpga */
|