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"
|
2020-02-13 16:27:16 -06:00
|
|
|
#include "openfpga_reserved_words.h"
|
2020-02-12 18:53:23 -06:00
|
|
|
#include "openfpga_naming.h"
|
|
|
|
|
|
|
|
/* begin namespace openfpga */
|
|
|
|
namespace openfpga {
|
|
|
|
|
2020-03-03 13:29:58 -06:00
|
|
|
/************************************************
|
|
|
|
* 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);
|
2020-03-07 16:44:57 -06:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************************
|
2020-02-13 16:27:16 -06:00
|
|
|
* 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!!!
|
|
|
|
**********************************************************************/
|
2020-02-13 16:27:16 -06:00
|
|
|
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 */
|
2020-02-13 16:27:16 -06:00
|
|
|
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
|
|
|
|
**********************************************************************/
|
2020-02-13 16:27:16 -06:00
|
|
|
std::string generate_physical_block_instance_name(t_pb_type* pb_type,
|
2020-02-12 18:53:23 -06:00
|
|
|
const size_t& index) {
|
2020-02-13 16:27:16 -06:00
|
|
|
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,
|
2020-04-05 18:26:44 -05:00
|
|
|
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);
|
2020-04-05 18:26:44 -05:00
|
|
|
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 */
|