implementing mux Verilog generation. Bugs detected, fixing ongoing

This commit is contained in:
tangxifan 2019-09-04 23:54:53 -06:00
parent fde9c8b4ec
commit e623c19055
13 changed files with 496 additions and 3 deletions

View File

@ -298,6 +298,22 @@ size_t CircuitLibrary::buffer_num_levels(const CircuitModelId& model_id) const {
return buffer_num_levels_[model_id];
}
/* Return the location map of intermediate buffers
* that are inserted inside LUT multiplexing structures
*/
std::string CircuitLibrary::lut_intermediate_buffer_location_map(const CircuitModelId& model_id) const {
/* validate the model_id */
VTR_ASSERT(valid_model_id(model_id));
/* validate the circuit model type is BUF */
VTR_ASSERT(SPICE_MODEL_LUT == model_type(model_id));
/* if we have an intermediate buffer, we return something, otherwise return an empty map */
if (true == is_lut_intermediate_buffered(model_id)) {
return buffer_location_maps_[model_id][LUT_INTER_BUFFER];
} else {
return std::string();
}
}
/* Return the number of levels of delay types for a circuit model */
size_t CircuitLibrary::num_delay_info(const CircuitModelId& model_id) const {
/* validate the model_id */

View File

@ -239,6 +239,7 @@ class CircuitLibrary {
/* Buffer information */
enum e_spice_model_buffer_type buffer_type(const CircuitModelId& model_id) const;
size_t buffer_num_levels(const CircuitModelId& model_id) const;
std::string lut_intermediate_buffer_location_map(const CircuitModelId& model_id) const;
/* Delay information */
size_t num_delay_info(const CircuitModelId& model_id) const;
public: /* Public Accessors: Basic data query on cirucit models' Circuit Ports*/

View File

@ -43,6 +43,20 @@ MuxGraph::node_range MuxGraph::nodes() const {
return vtr::make_range(node_ids_.begin(), node_ids_.end());
}
/* Find the non-input nodes */
std::vector<MuxNodeId> MuxGraph::non_input_nodes() const {
std::vector<MuxNodeId> node_list;
for (const auto& node : nodes()) {
/* Bypass any nodes which are not OUTPUT and INTERNAL */
if (MUX_INPUT_NODE == node_types_[node]) {
continue;
}
/* Reach here, this is either an OUTPUT or INTERNAL node */
node_list.push_back(node);
}
return node_list;
}
MuxGraph::edge_range MuxGraph::edges() const {
return vtr::make_range(edge_ids_.begin(), edge_ids_.end());
}
@ -137,6 +151,47 @@ size_t MuxGraph::num_memory_bits() const {
return mem_ids_.size();
}
/* Find the number of nodes at a given level in the MUX graph */
size_t MuxGraph::num_nodes_at_level(const size_t& level) const {
/* validate the level numbers */
VTR_ASSERT_SAFE(valid_level(level));
VTR_ASSERT_SAFE(valid_mux_graph());
size_t num_nodes = 0;
for (size_t node_type = 0; node_type < size_t(NUM_MUX_NODE_TYPES); ++node_type) {
num_nodes += node_lookup_[level][node_type].size();
}
return num_nodes;
}
/* Find the level of a node */
size_t MuxGraph::node_level(const MuxNodeId& node) const {
/* validate the node */
VTR_ASSERT(valid_node_id(node));
return node_levels_[node];
}
/* Find the index of a node at its level */
size_t MuxGraph::node_index_at_level(const MuxNodeId& node) const {
/* validate the node */
VTR_ASSERT(valid_node_id(node));
return node_ids_at_level_[node];
}
/* Find the input edges for a node */
std::vector<MuxEdgeId> MuxGraph::node_in_edges(const MuxNodeId& node) const {
/* validate the node */
VTR_ASSERT(valid_node_id(node));
return node_in_edges_[node];
}
/* Find the input nodes for a edge */
std::vector<MuxNodeId> MuxGraph::edge_src_nodes(const MuxEdgeId& edge) const {
/* validate the edge */
VTR_ASSERT(valid_edge_id(edge));
return edge_src_nodes_[edge];
}
/* Find the mem that control the edge */
MuxMemId MuxGraph::find_edge_mem(const MuxEdgeId& edge) const {
/* validate the edge */
@ -846,6 +901,10 @@ bool MuxGraph::valid_output_id(const MuxOutputId& output_id) const {
return true;
}
bool MuxGraph::valid_level(const size_t& level) const {
return level < num_levels();
}
bool MuxGraph::valid_node_lookup() const {
return node_lookup_.empty();
}

View File

@ -58,6 +58,8 @@ class MuxGraph {
MuxGraph();
public: /* Public accessors: Aggregates */
node_range nodes() const;
/* Find the non-input nodes */
std::vector<MuxNodeId> non_input_nodes() const;
edge_range edges() const;
mem_range memories() const;
public: /* Public accessors: Data query */
@ -73,6 +75,16 @@ class MuxGraph {
size_t num_levels() const;
/* Find the number of SRAMs in the MUX graph */
size_t num_memory_bits() const;
/* Find the number of nodes at a given level in the MUX graph */
size_t num_nodes_at_level(const size_t& level) const;
/* Find the level of a node */
size_t node_level(const MuxNodeId& node) const;
/* Find the index of a node at its level */
size_t node_index_at_level(const MuxNodeId& node) const;
/* Find the input edges for a node */
std::vector<MuxEdgeId> node_in_edges(const MuxNodeId& node) const;
/* Find the input nodes for a edge */
std::vector<MuxNodeId> edge_src_nodes(const MuxEdgeId& edge) const;
/* Find the mem that control the edge */
MuxMemId find_edge_mem(const MuxEdgeId& edge) const;
/* Identify if the edge is controlled by the inverted output of a mem */
@ -122,6 +134,7 @@ class MuxGraph {
bool valid_mem_id(const MuxMemId& mem) const;
bool valid_input_id(const MuxInputId& input_id) const;
bool valid_output_id(const MuxOutputId& output_id) const;
bool valid_level(const size_t& level) const;
/* validate/invalidate node lookup */
bool valid_node_lookup() const;
void invalidate_node_lookup();

View File

@ -150,6 +150,34 @@ size_t find_multilevel_mux_branch_num_inputs(const size_t& mux_size,
return num_input_per_unit;
}
/**************************************************
* Find if there is an intermediate buffer
* locating at the multiplexing structure of a LUT
*************************************************/
bool require_intermediate_buffer_at_mux_level(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model,
const size_t& node_level) {
std::string intermediate_buffer_location_map;
/* ONLY for LUTs: intermediate buffers may exist if specified */
if (SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model)) {
intermediate_buffer_location_map = circuit_lib.lut_intermediate_buffer_location_map(circuit_model);
}
/* If no location map is specified, we can return here */
if (intermediate_buffer_location_map.empty()) {
return false;
}
/* We have a location map. Make sure we are in the range */
if (node_level >= intermediate_buffer_location_map.length()) {
return false;
}
/* '1' indicates that the location is needed */
if ('1' == intermediate_buffer_location_map[node_level]) {
return true;
}
return false;
}
/**************************************************
* Convert a linked list of MUX architecture to MuxLibrary
* TODO: this function will be deleted when MUXLibrary fully

View File

@ -29,6 +29,10 @@ size_t find_treelike_mux_num_levels(const size_t& mux_size);
size_t find_multilevel_mux_branch_num_inputs(const size_t& mux_size,
const size_t& mux_level);
bool require_intermediate_buffer_at_mux_level(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model,
const size_t& node_level);
MuxLibrary convert_mux_arch_to_library(const CircuitLibrary& circuit_lib, t_llist* muxes_head);
#endif

View File

@ -7,6 +7,27 @@
#include "fpga_x2p_naming.h"
/************************************************
* 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_verilog_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 module name for a multiplexer in Verilog format
* Different circuit model requires different names:

View File

@ -11,6 +11,9 @@
#include "circuit_library.h"
std::string generate_verilog_mux_node_name(const size_t& node_level,
const bool& add_buffer_postfix);
std::string generate_verilog_mux_subckt_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model,
const size_t& mux_size,

View File

@ -50,6 +50,29 @@ std::vector<BasicPort> ModuleManager::module_ports_by_type(const ModuleId& modul
return ports;
}
/* Find a port of a module by a given name */
ModulePortId ModuleManager::find_module_port(const ModuleId& module_id, const std::string& port_name) const {
/* Validate the module id */
VTR_ASSERT(valid_module_id(module_id));
/* Iterate over the ports of the module */
for (const auto& port : port_ids_[module_id]) {
if (0 == port_name.compare(ports_[module_id][port].get_name())) {
/* Find it, return the id */
return port;
}
}
/* Not found, return an invalid id */
return ModulePortId::INVALID();
}
/* Find the Port information with a given port id */
BasicPort ModuleManager::module_port(const ModuleId& module_id, const ModulePortId& port_id) const {
/* Validate the module and port id */
VTR_ASSERT(valid_module_port_id(module_id, port_id));
return ports_[module_id][port_id];
}
/* Find the module id by a given name, return invalid if not found */
ModuleId ModuleManager::find_module(const std::string& name) const {
if (name_id_map_.find(name) != name_id_map_.end()) {

View File

@ -37,6 +37,11 @@ class ModuleManager {
std::string module_name(const ModuleId& module_id) const;
std::string module_port_type_str(const enum e_module_port_type& port_type) const;
std::vector<BasicPort> module_ports_by_type(const ModuleId& module_id, const enum e_module_port_type& port_type) const;
/* Find a port of a module by a given name */
ModulePortId find_module_port(const ModuleId& module_id, const std::string& port_name) const;
/* Find the Port information with a given port id */
BasicPort module_port(const ModuleId& module_id, const ModulePortId& port_id) const;
/* Find a module by a given name */
ModuleId find_module(const std::string& name) const;
/* Find the number of instances of a child module in the parent module */
size_t num_instance(const ModuleId& parent_module, const ModuleId& child_module) const;

View File

@ -6,6 +6,7 @@
* and the full multiplexer
**********************************************/
#include <string>
#include <algorithm>
#include "util.h"
#include "vtr_assert.h"
@ -74,7 +75,7 @@ void generate_verilog_cmos_mux_branch_body_structural(ModuleManager& module_mana
if (0 == edges.size()) {
continue;
}
/* TODO: Output a tgate use a module manager */
/* Output a tgate use a module manager */
/* Create a port-to-port name map */
std::map<std::string, BasicPort> port2port_name_map;
/* input port */
@ -693,6 +694,213 @@ void generate_verilog_mux_branch_module(ModuleManager& module_manager,
}
}
/********************************************************************
* Generate the internal logic (multiplexing structure) for
* a multiplexer or LUT in Verilog codes
* This function will :
* 1. build a multiplexing structure by instanciating the branch circuits
* generated before or standard cells MUX2
* 2. add intermediate buffers between multiplexing stages if specified.
*******************************************************************/
static
void generate_verilog_cmos_mux_module_multiplexing_structure(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
std::fstream& fp,
const ModuleId& module_id,
const CircuitModelId& circuit_model,
const MuxGraph& mux_graph) {
/* Make sure we have a valid file handler*/
check_file_handler(fp);
/* Find the actual mux size */
size_t mux_size = find_mux_num_datapath_inputs(circuit_lib, circuit_model, mux_graph.num_inputs());
/* TODO: these are duplicated codes, find a way to simplify it!!!
* Get the regular (non-mode-select) sram ports from the mux
*/
std::vector<CircuitPortId> mux_regular_sram_ports;
for (const auto& port : circuit_lib.model_ports_by_type(circuit_model, SPICE_MODEL_PORT_SRAM, true)) {
/* Multiplexing structure does not mode_sram_ports, they are handled in LUT modules
* Here we just bypass it.
*/
if (true == circuit_lib.port_is_mode_select(port)) {
continue;
}
mux_regular_sram_ports.push_back(port);
}
VTR_ASSERT(1 == mux_regular_sram_ports.size());
print_verilog_comment(fp, std::string("---- BEGIN Internal wires of a CMOS MUX module -----"));
/* Print local wires which are the nodes in the mux graph */
for (size_t level = 0; level < mux_graph.num_levels(); ++level) {
/* Print the internal wires located at this level */
BasicPort internal_wire_port(generate_verilog_mux_node_name(level, false), mux_graph.num_nodes_at_level(level));
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, internal_wire_port) << ";" << std::endl;
/* Identify if an intermediate buffer is needed */
if (false == require_intermediate_buffer_at_mux_level(circuit_lib, circuit_model, level)) {
continue;
}
BasicPort internal_wire_buffered_port(generate_verilog_mux_node_name(level, true), mux_graph.num_nodes_at_level(level));
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, internal_wire_buffered_port) << std::endl;
}
print_verilog_comment(fp, std::string("---- END Internal wires of a CMOS MUX module -----"));
print_verilog_comment(fp, std::string("---- BEGIN Instanciation of a branch CMOS MUX modules -----"));
/* Iterate over all the internal nodes and output nodes in the mux graph */
for (const auto& node : mux_graph.non_input_nodes()) {
/* Get the size of branch circuit
* Instanciate an branch circuit by the size (fan-in) of the node
*/
size_t branch_size = mux_graph.node_in_edges(node).size();
/* Instanciate the branch module:
* Case 1: the branch module is a standard cell MUX2
* Case 2: the branch module is a tgate-based module
*/
std::string branch_module_name = generate_verilog_mux_branch_subckt_name(circuit_lib, circuit_model, mux_size, branch_size, verilog_mux_basis_posfix);
/* Get the moduleId for the submodule */
ModuleId branch_module_id = module_manager.find_module(branch_module_name);
/* We must have one */
VTR_ASSERT(ModuleId::INVALID() != branch_module_id);
/* Get the node level and index in the current level */
size_t output_node_level = mux_graph.node_level(node);
size_t output_node_index_at_level = mux_graph.node_index_at_level(node);
/* Get the nodes which drive the root_node */
std::vector<MuxNodeId> input_nodes;
for (const auto& edge : mux_graph.node_in_edges(node)) {
/* Get the nodes drive the edge */
for (const auto& src_node : mux_graph.edge_src_nodes(edge)) {
input_nodes.push_back(src_node);
}
}
/* Number of inputs should match the branch_input_size!!! */
VTR_ASSERT(input_nodes.size() == branch_size);
/* Get the mems in the branch circuits */
std::vector<MuxMemId> mems;
for (const auto& edge : mux_graph.node_in_edges(node)) {
/* Get the mem control the edge */
MuxMemId mem = mux_graph.find_edge_mem(edge);
/* Add the mem if it is not in the list */
if (mems.end() == std::find(mems.begin(), mems.end(), mem)) {
mems.push_back(mem);
}
}
/* Create a port-to-port map */
std::map<std::string, BasicPort> port2port_name_map;
/* TODO: the branch module name should NOT be hard-coded. Use the port lib_name given by users! */
/* TODO: for clean representation, need to merge the node names in [a:b] format, if possible!!!
* All the input node names organized in bus
*/
std::vector<BasicPort> branch_node_input_ports;
for (const auto& input_node : input_nodes) {
/* Generate the port info of each input node */
size_t input_node_level = mux_graph.node_level(input_node);
size_t input_node_index_at_level = mux_graph.node_index_at_level(input_node);
BasicPort branch_node_input_port(generate_verilog_mux_node_name(input_node_level, require_intermediate_buffer_at_mux_level(circuit_lib, circuit_model, input_node_level)), input_node_index_at_level, input_node_index_at_level);
branch_node_input_ports.push_back(branch_node_input_port);
}
/* Try to combine the ports */
std::vector<BasicPort> combined_branch_node_input_ports = combine_verilog_ports(branch_node_input_ports);
/* If we have more than 1 port in the combined ports ,
*
* output a local wire */
VTR_ASSERT(0 < combined_branch_node_input_ports.size());
/* Create the port info for the input */
BasicPort instance_input_port;
if (1 == combined_branch_node_input_ports.size()) {
instance_input_port = combined_branch_node_input_ports[0];
} else {
/* TODO: the naming could be more flexible? */
instance_input_port.set_name(generate_verilog_mux_node_name(output_node_level, false) + "_in");
/* Deposite a [0:0] port */
instance_input_port.set_width(1);
for (const auto& port : combined_branch_node_input_ports) {
instance_input_port.combine(port);
}
/* Print a local wire for the merged ports */
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, instance_input_port);
fp << " = " << generate_verilog_ports(combined_branch_node_input_ports);
fp << ";" << std::endl;
}
/* Link nodes to input ports for the branch module */
/* TODO: the naming could be more flexible? */
ModulePortId module_input_port_id = module_manager.find_module_port(branch_module_id, "in");
VTR_ASSERT(ModulePortId::INVALID() != module_input_port_id);
/* Get the port from module */
BasicPort module_input_port = module_manager.module_port(branch_module_id, module_input_port_id);
/* Double check: Port width should match the number of input nodes */
VTR_ASSERT(module_input_port.get_width() == instance_input_port.get_width());
port2port_name_map[module_input_port.get_name()] = instance_input_port;
/* Link nodes to output ports for the branch module */
BasicPort instance_output_port(generate_verilog_mux_node_name(output_node_level, false), output_node_index_at_level, output_node_index_at_level);
ModulePortId module_output_port_id = module_manager.find_module_port(branch_module_id, "out");
VTR_ASSERT(ModulePortId::INVALID() != module_output_port_id);
/* Get the port from module */
BasicPort module_output_port = module_manager.module_port(branch_module_id, module_output_port_id);
/* Double check: Port width should match the number of output nodes */
VTR_ASSERT(module_output_port.get_width() == instance_output_port.get_width());
port2port_name_map[module_output_port.get_name()] = module_output_port;
/* All the mem node names organized in bus */
std::vector<BasicPort> branch_node_mem_ports;
for (const auto& mem : mems) {
/* Generate the port info of each mem node */
BasicPort branch_node_mem_port(circuit_lib.port_lib_name(mux_regular_sram_ports[0]), size_t(mem), size_t(mem));
branch_node_mem_ports.push_back(branch_node_mem_port);
}
/* Try to combine the ports */
std::vector<BasicPort> combined_branch_node_mem_ports = combine_verilog_ports(branch_node_mem_ports);
/* If we have more than 1 port in the combined ports ,
*
* output a local wire */
VTR_ASSERT(0 < combined_branch_node_mem_ports.size());
/* Create the port info for the input */
BasicPort instance_mem_port;
if (1 == combined_branch_node_mem_ports.size()) {
instance_mem_port = combined_branch_node_mem_ports[0];
} else {
/* TODO: the naming could be more flexible? */
instance_mem_port.set_name(generate_verilog_mux_node_name(output_node_level, false) + "_mem");
/* Deposite a [0:0] port */
instance_mem_port.set_width(1);
/* TODO: combine the ports could be a function? */
for (const auto& port : combined_branch_node_mem_ports) {
instance_mem_port.combine(port);
}
/* Print a local wire for the merged ports */
fp << "\t" << generate_verilog_port(VERILOG_PORT_WIRE, instance_mem_port);
fp << " = " << generate_verilog_ports(combined_branch_node_mem_ports);
fp << ";" << std::endl;
}
/* Link nodes to input ports for the branch module */
/* TODO: the naming could be more flexible? */
ModulePortId module_mem_port_id = module_manager.find_module_port(branch_module_id, "mem");
VTR_ASSERT(ModulePortId::INVALID() != module_mem_port_id);
/* Get the port from module */
BasicPort module_mem_port = module_manager.module_port(branch_module_id, module_mem_port_id);
/* Double check: Port width should match the number of input nodes */
VTR_ASSERT(module_mem_port.get_width() == instance_mem_port.get_width());
port2port_name_map[module_mem_port.get_name()] = instance_mem_port;
/* Output an instance of the module */
print_verilog_module_instance(fp, module_manager, module_id, branch_module_id, port2port_name_map, circuit_lib.dump_explicit_port_map(circuit_model));
/* IMPORTANT: this update MUST be called after the instance outputting!!!!
* update the module manager with the relationship between the parent and child modules
*/
module_manager.add_child_module(module_id, branch_module_id);
/* TODO: Now we need to add intermediate buffers by instanciating the modules */
}
print_verilog_comment(fp, std::string("---- END Instanciation of a branch CMOS MUX modules -----"));
}
/*********************************************************************
* Generate Verilog codes modeling a CMOS multiplexer with the given size
* The Verilog module will consist of three parts:
@ -731,7 +939,6 @@ void generate_verilog_cmos_mux_module(ModuleManager& module_manager,
/* Check codes to ensure the port of Verilog netlists will match */
/* MUX graph must have only 1 output */
VTR_ASSERT(1 == mux_input_ports.size());
VTR_ASSERT(1 == mux_input_ports.size());
/* A quick check on the model ports */
if ((SPICE_MODEL_MUX == circuit_lib.model_type(circuit_model))
|| ((SPICE_MODEL_LUT == circuit_lib.model_type(circuit_model))
@ -802,6 +1009,7 @@ void generate_verilog_cmos_mux_module(ModuleManager& module_manager,
/* TODO: Print the internal logic in Verilog codes */
/* TODO: Print the Multiplexing structure in Verilog codes */
generate_verilog_cmos_mux_module_multiplexing_structure(module_manager, circuit_lib, fp, module_id, circuit_model, mux_graph);
/* TODO: Print the input buffers in Verilog codes */
/* TODO: Print the output buffers in Verilog codes */

View File

@ -128,6 +128,25 @@ void print_verilog_module_declaration(std::fstream& fp,
/************************************************
* Print an instance for a Verilog module
* This function will output the port map
* by referring to a port-to-port mapping:
* <module_port_name> -> <instance_port_name>
* The key of the port-to-port mapping is the
* port name of the module:
* The value of the port-to-port mapping is the
* port information of the instance
* With link between module and instance, the function
* can output a Verilog instance easily, supporting
* both explicit port mapping:
* .<module_port_name>(<instance_port_name>)
* and inexplicit port mapping
* <instance_port_name>
*
* Note that, it is not necessary that
* the port-to-port mapping covers all the module ports.
* Any instance/module port which are not specified in the
* port-to-port mapping will be output by the module
* port name.
***********************************************/
void print_verilog_module_instance(std::fstream& fp,
const ModuleManager& module_manager,
@ -168,6 +187,11 @@ void print_verilog_module_instance(std::fstream& fp,
/* Try to find the instanced port name in the name map */
if (port2port_name_map.find(port.get_name()) != port2port_name_map.end()) {
/* Found it, we assign the port name */
/* TODO: make sure the port width matches! */
ModulePortId module_port_id = module_manager.find_module_port(child_module_id, port.get_name());
/* Get the port from module */
BasicPort module_port = module_manager.module_port(child_module_id, module_port_id);
VTR_ASSERT(module_port.get_width() == port2port_name_map.at(port.get_name()).get_width());
fp << generate_verilog_port(kv.second, port2port_name_map.at(port.get_name()));
} else {
/* Not found, we give the default port name */
@ -197,7 +221,9 @@ void print_verilog_module_end(std::fstream& fp,
fp << std::endl;
}
/* Generate a string of a Verilog port */
/************************************************
* Generate a string of a Verilog port
***********************************************/
std::string generate_verilog_port(const enum e_dump_verilog_port_type& verilog_port_type,
const BasicPort& port_info) {
std::string verilog_line;
@ -224,4 +250,86 @@ std::string generate_verilog_port(const enum e_dump_verilog_port_type& verilog_p
return verilog_line;
}
/************************************************
* This function takes a list of ports and
* combine the port string by comparing the name
* and width of ports.
* For example, two ports A and B share the same name is
* mergable as long as A's MSB + 1 == B's LSB
* Note that the port sequence really matters!
* This function will NOT change the sequence
* of ports in the list port_info
***********************************************/
std::vector<BasicPort> combine_verilog_ports(const std::vector<BasicPort>& ports) {
std::vector<BasicPort> merged_ports;
/* Directly return if there are no ports */
if (0 == ports.size()) {
return merged_ports;
}
/* Push the first port to the merged ports */
merged_ports.push_back(ports[0]);
/* Iterate over ports */
for (const auto& port : ports) {
/* Bypass the first port, it is already in the list */
if (&port == &ports[0]) {
continue;
}
/* Identify if the port name can be potentially merged: if the port name is already in the merged port list, it may be merged */
for (auto& merged_port : merged_ports) {
if (0 != port.get_name().compare(merged_port.get_name())) {
/* Unable to merge, add the port to merged port list */
merged_ports.push_back(port);
/* Go to next */
break;
}
/* May be merged, check LSB of port and MSB of merged_port */
if (merged_port.get_msb() + 1 != port.get_lsb()) {
/* Unable to merge, add the port to merged port list */
merged_ports.push_back(port);
/* Go to next */
break;
}
/* Reach here, we should merge the ports,
* LSB of merged_port remains the same,
* MSB of merged_port will be updated
* to the MSB of port
*/
merged_port.set_msb(port.get_msb());
break;
}
}
return merged_ports;
}
/************************************************
* Generate the string of a list of verilog ports
***********************************************/
std::string generate_verilog_ports(const std::vector<BasicPort>& merged_ports) {
/* Output the string of ports:
* If there is only one port in the merged_port list
* we only output the port.
* If there are more than one port in the merged port list, we output an concatenated port:
* {<port1>, <port2>, ... <last_port>}
*/
VTR_ASSERT(0 < merged_ports.size());
if ( 1 == merged_ports.size()) {
/* Use connection type of verilog port */
return generate_verilog_port(VERILOG_PORT_CONKT, merged_ports[0]);
}
std::string verilog_line = "{";
for (const auto& port : merged_ports) {
/* The first port does not need a comma */
if (&port != &merged_ports[0]) {
verilog_line += ", ";
}
verilog_line += generate_verilog_port(VERILOG_PORT_CONKT, merged_ports[0]);
}
verilog_line += "}";
return verilog_line;
}

View File

@ -40,4 +40,8 @@ void print_verilog_module_end(std::fstream& fp,
std::string generate_verilog_port(const enum e_dump_verilog_port_type& dump_port_type,
const BasicPort& port_info);
std::vector<BasicPort> combine_verilog_ports(const std::vector<BasicPort>& ports);
std::string generate_verilog_ports(const std::vector<BasicPort>& merged_ports);
#endif