OpenFPGA/openfpga/src/base/openfpga_naming.cpp

1393 lines
60 KiB
C++
Raw Normal View History

2020-02-12 18:53:23 -06:00
/********************************************************************
* 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 "vtr_assert.h"
#include "vtr_log.h"
#include "openfpga_side_manager.h"
#include "pb_type_utils.h"
#include "circuit_library_utils.h"
#include "openfpga_reserved_words.h"
2020-02-12 18:53:23 -06:00
#include "openfpga_naming.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("_");
}
2020-02-12 18:53:23 -06:00
/************************************************
* 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& mux_size,
const size_t& branch_mux_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);
}
std::string branch_postfix = postfix + "_size" + std::to_string(branch_mux_size);
return generate_mux_subckt_name(circuit_lib, circuit_model, mux_size, branch_postfix);
}
/************************************************
* 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 = "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 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
********************************************************************/
std::string generate_memory_module_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model,
const CircuitModelId& sram_model,
const std::string& postfix) {
return std::string( circuit_lib.model_name(circuit_model) + "_" + 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()) + 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 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("_");
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);
}
/* 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 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!
*********************************************************************/
std::string generate_cb_module_track_port_name(const t_rr_type& chan_type,
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("_");
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 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 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 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 vtr::Point<size_t>& coordinate,
const size_t& width,
const size_t& height,
const e_side& side,
const size_t& pin_id,
const bool& for_top_netlist) {
if (true == for_top_netlist) {
std::string port_name = std::string("grid_");
port_name += std::to_string(coordinate.x());
port_name += std::string("__");
port_name += std::to_string(coordinate.y());
port_name += std::string("__pin_");
port_name += std::to_string(height);
port_name += std::string("__");
port_name += std::to_string(size_t(side));
port_name += std::string("__");
port_name += std::to_string(pin_id);
port_name += std::string("_");
return port_name;
}
/* For non-top netlist */
VTR_ASSERT( false == for_top_netlist );
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("__pin_");
port_name += std::to_string(pin_id);
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 e_side& side,
const size_t& pin_id,
const bool& upper_port) {
/* For non-top netlist */
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("__pin_");
2020-02-12 18:53:23 -06:00
port_name += std::to_string(pin_id);
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 module
* To keep a short and simple name, this function will not
* include any grid coorindate information!
*********************************************************************/
std::string generate_grid_module_port_name(const size_t& pin_id) {
/* For non-top netlist */
std::string port_name = std::string("grid_");
port_name += std::string("pin_");
port_name += std::to_string(pin_id);
port_name += std::string("_");
return port_name;
}
/*********************************************************************
* Generate the port name for a Grid
* This is a wrapper function for generate_port_name()
* which can automatically decode the port name by the pin side and height
*********************************************************************/
std::string generate_grid_side_port_name(const DeviceGrid& grids,
const vtr::Point<size_t>& coordinate,
const e_side& side,
const size_t& pin_id) {
/* Output the pins on the side*/
size_t width = grids[coordinate.x()][coordinate.y()].type->pin_width_offset[pin_id];
size_t height = grids[coordinate.x()][coordinate.y()].type->pin_height_offset[pin_id];
if (true != grids[coordinate.x()][coordinate.y()].type->pinloc[width][height][side][pin_id]) {
SideManager side_manager(side);
VTR_LOG_ERROR("Fail to generate a grid pin (x=%lu, y=%lu, width=%lu, height=%lu, side=%s, index=%d)\n",
coordinate.x(), coordinate.y(), width, height, side_manager.c_str(), pin_id);
exit(1);
}
return generate_grid_port_name(coordinate, width, height, side, pin_id, true);
}
/*********************************************************************
* Generate the port name of a grid pin for a routing module,
* which could be a switch block or a connection block
* Note that to ensure unique grid port name in the context of a routing module,
* we need a prefix which denotes the relative location of the port in the routing module
*
* The prefix is created by considering the the grid coordinate
* and switch block coordinate
* Detailed rules in conversion is as follows:
*
* top_left top_right
* +------------------------+
* left_top | | right_top
* | Switch Block |
* | [x][y] |
* | |
* | |
* left_right | | right_bottom
* +------------------------+
* bottom_left bottom_right
*
* +--------------------------------------------------------
* | Grid Coordinate | Pin side of grid | module side
* +--------------------------------------------------------
* | [x][y+1] | right | top_left
* +--------------------------------------------------------
* | [x][y+1] | bottom | left_top
* +--------------------------------------------------------
* | [x+1][y+1] | left | top_right
* +--------------------------------------------------------
* | [x+1][y+1] | bottom | right_top
* +--------------------------------------------------------
* | [x][y] | top | left_right
* +--------------------------------------------------------
* | [x][y] | right | bottom_left
* +--------------------------------------------------------
* | [x+1][y] | top | right_bottom
* +--------------------------------------------------------
* | [x+1][y] | left | bottom_right
* +--------------------------------------------------------
*
*********************************************************************/
std::string generate_sb_module_grid_port_name(const e_side& sb_side,
const e_side& grid_side,
const size_t& pin_id) {
SideManager sb_side_manager(sb_side);
SideManager grid_side_manager(grid_side);
/* Relative location is opposite to the side in grid context */
grid_side_manager.set_opposite();
std::string prefix = sb_side_manager.to_string() + std::string("_") + grid_side_manager.to_string();
return prefix + std::string("_") + generate_grid_module_port_name(pin_id);
}
/*********************************************************************
* Generate the port name of a grid pin for a routing module,
* which could be a switch block or a connection block
* Note that to ensure unique grid port name in the context of a routing module,
* we need a prefix which denotes the relative location of the port in the routing module
*********************************************************************/
std::string generate_cb_module_grid_port_name(const e_side& cb_side,
const size_t& pin_id) {
SideManager side_manager(cb_side);
std::string prefix = side_manager.to_string();
return prefix + std::string("_") + generate_grid_module_port_name(pin_id);
}
/*********************************************************************
* 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("ccff_head");
}
/*********************************************************************
* Generate the tail port name of a configuration chain
* TODO: This could be replaced as a constexpr string
*********************************************************************/
std::string generate_configuration_chain_tail_name() {
return std::string("ccff_tail");
}
/*********************************************************************
* Generate the memory output port name of a configuration chain
* TODO: This could be replaced as a constexpr string
*********************************************************************/
std::string generate_configuration_chain_data_out_name() {
return std::string("mem_out");
}
/*********************************************************************
* Generate the inverted memory output port name of a configuration chain
* TODO: This could be replaced as a constexpr string
*********************************************************************/
std::string generate_configuration_chain_inverted_data_out_name() {
return std::string("mem_outb");
}
/*********************************************************************
* Generate the addr port (input) for a local decoder of a multiplexer
* TODO: This could be replaced as a constexpr string
*********************************************************************/
std::string generate_mux_local_decoder_addr_port_name() {
return std::string("addr");
}
/*********************************************************************
* Generate the data port (output) for a local decoder of a multiplexer
* TODO: This could be replaced as a constexpr string
*********************************************************************/
std::string generate_mux_local_decoder_data_port_name() {
return std::string("data");
}
/*********************************************************************
* Generate the inverted data port (output) for a local decoder of a multiplexer
* TODO: This could be replaced as a constexpr string
*********************************************************************/
std::string generate_mux_local_decoder_data_inv_port_name() {
return std::string("data_inv");
}
/*********************************************************************
* Generate the port name of a local configuration bus
* TODO: This could be replaced as a constexpr string
*********************************************************************/
std::string generate_local_config_bus_port_name() {
return std::string("config_bus");
}
/*********************************************************************
* Generate the port name for a regular sram port which appears in the
* port list of a module
* 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_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("mem_out");
} else {
VTR_ASSERT( CIRCUIT_MODEL_PORT_OUTPUT == port_type );
port_name = std::string("mem_outb");
}
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_MEMORY_BANK:
/* Four 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
* (3) Inverted Bit Lines (BLBs) of a SRAM cell, enabled by port type of BLB
* (4) Inverted Word Lines (WLBs) of a SRAM cell, enabled by port type of WLB
*
* BL BLB WL WLB BL BLB WL WLB BL BLB WL WLB
* [0] [0] [0] [0] [1] [1] [1] [1] [i] [i] [i] [i]
* ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
* | | | | | | | | | | | |
* +----------+ +----------+ +----------+
* | SRAM | | SRAM | ... | SRAM |
* +----------+ +----------+ +----------+
*/
if (CIRCUIT_MODEL_PORT_BL == port_type) {
port_name = std::string("bl");
} else if (CIRCUIT_MODEL_PORT_WL == port_type) {
port_name = std::string("wl");
} else if (CIRCUIT_MODEL_PORT_BLB == port_type) {
port_name = std::string("blb");
} else {
VTR_ASSERT( CIRCUIT_MODEL_PORT_WLB == port_type );
port_name = std::string("wlb");
}
break;
default:
VTR_LOG_ERROR("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 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);
}
2020-02-16 17:04:41 -06:00
/*********************************************************************
* 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) {
/* This must be the root node */
VTR_ASSERT(true == pb_graph_head->is_root());
/* Add the name of physical block */
std::string module_name = prefix + std::string(pb_graph_head->pb_type->name);
module_name += postfix;
return module_name;
}
2020-02-12 18:53:23 -06:00
/*********************************************************************
* 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) {
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) {
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 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) {
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 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) {
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 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());
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'
2020-02-12 18:53:23 -06:00
* 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) {
2020-02-12 18:53:23 -06:00
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;
2020-02-12 18:53:23 -06:00
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,
2020-02-12 18:53:23 -06:00
const size_t& index) {
std::string instance_name = generate_physical_block_module_name(pb_type);
2020-02-12 18:53:23 -06:00
/* 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_port* pb_type_port) {
std::string port_name;
port_name = std::string(pb_type_port->parent_pb_type->name) + std::string("_") + std::string(pb_type_port->name);
return port_name;
}
/*********************************************************************
* 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) {
2020-02-12 18:53:23 -06:00
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);
2020-02-12 18:53:23 -06:00
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");
}
/*********************************************************************
* 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" + 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);
}
} /* end namespace openfpga */