added pin duplication support to grid module builder

This commit is contained in:
tangxifan 2019-12-25 22:24:44 -07:00
parent 72d2fc6d69
commit 2306b17d9f
6 changed files with 353 additions and 94 deletions

View File

@ -469,6 +469,36 @@ std::string generate_grid_port_name(const vtr::Point<size_t>& coordinate,
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& height,
const e_side& side,
const size_t& pin_id,
const bool& upper_port) {
/* For non-top netlist */
Side side_manager(side);
std::string port_name = std::string(side_manager.to_string());
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("_");
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

View File

@ -121,6 +121,11 @@ std::string generate_grid_port_name(const vtr::Point<size_t>& coordinate,
const size_t& pin_id,
const bool& for_top_netlist);
std::string generate_grid_duplicated_port_name(const size_t& height,
const e_side& side,
const size_t& pin_id,
const bool& upper_port);
std::string generate_grid_module_port_name(const size_t& pin_id);
std::string generate_sb_module_grid_port_name(const e_side& sb_side,

View File

@ -8,8 +8,19 @@
*
* Please follow this rules when creating new features!
*******************************************************************/
/* External library headers */
#include "vtr_assert.h"
/* FPGA-X2P headers */
#include "fpga_x2p_naming.h"
/* Module builder headers */
#include "build_grid_module_utils.h"
#include "build_grid_module_duplicated_pins.h"
/* Global variables should be the last to include */
#include "globals.h"
/********************************************************************
* This function adds pb_type ports to top-level grid module with duplication
* For each pin at each side, we create two pins which are short-wired
@ -40,12 +51,190 @@ void add_grid_module_duplicated_pb_type_ports(ModuleManager& module_manager,
const ModuleId& grid_module,
t_type_ptr grid_type_descriptor,
const e_side& border_side) {
/* Ensure that we have a valid grid_type_descriptor */
VTR_ASSERT(NULL != grid_type_descriptor);
/* Find the pin side for I/O grids*/
std::vector<e_side> grid_pin_sides;
/* For I/O grids, we care only one side
* Otherwise, we will iterate all the 4 sides
*/
if (IO_TYPE == grid_type_descriptor) {
grid_pin_sides.push_back(find_grid_module_pin_side(grid_type_descriptor, border_side));
} else {
grid_pin_sides = {TOP, RIGHT, BOTTOM, LEFT};
}
/* Create a map between pin class type and grid pin direction */
std::map<e_pin_type, ModuleManager::e_module_port_type> pin_type2type_map;
pin_type2type_map[RECEIVER] = ModuleManager::MODULE_INPUT_PORT;
pin_type2type_map[DRIVER] = ModuleManager::MODULE_OUTPUT_PORT;
/* Iterate over sides, height and pins */
for (const e_side& side : grid_pin_sides) {
for (int iheight = 0; iheight < grid_type_descriptor->height; ++iheight) {
for (int ipin = 0; ipin < grid_type_descriptor->num_pins; ++ipin) {
if (1 != grid_type_descriptor->pinloc[iheight][side][ipin]) {
continue;
}
/* Reach here, it means this pin is on this side */
int class_id = grid_type_descriptor->pin_class[ipin];
e_pin_type pin_class_type = grid_type_descriptor->class_inf[class_id].type;
/* Generate the pin name */
if (RECEIVER == pin_class_type) {
/* For each RECEIVER PIN, we do not duplicate */
vtr::Point<size_t> dummy_coordinate;
std::string port_name = generate_grid_port_name(dummy_coordinate, iheight, side, ipin, false);
BasicPort grid_port(port_name, 0, 0);
/* Add the port to the module */
module_manager.add_port(grid_module, grid_port, pin_type2type_map[pin_class_type]);
} else {
/* For each DRIVER pin, we create two copies.
* One with a postfix of upper, indicating it is located on the upper part of a side
* The other with a postfix of lower, indicating it is located on the lower part of a side
*/
VTR_ASSERT(DRIVER == pin_class_type);
std::string upper_port_name = generate_grid_duplicated_port_name(iheight, side, ipin, true);
BasicPort grid_upper_port(upper_port_name, 0, 0);
/* Add the port to the module */
module_manager.add_port(grid_module, grid_upper_port, pin_type2type_map[pin_class_type]);
std::string lower_port_name = generate_grid_duplicated_port_name(iheight, side, ipin, false);
BasicPort grid_lower_port(upper_port_name, 0, 0);
/* Add the port to the module */
module_manager.add_port(grid_module, grid_lower_port, pin_type2type_map[pin_class_type]);
}
}
}
}
}
/********************************************************************
* Add module nets to connect a port of child pb_module
* to the duplicated pins of grid module
* Note: This function SHOULD be ONLY applied to pb_graph output pins
* of the child module.
* For each such pin, we connect it to two outputs of the grid module
* one is named after "upper", and the other is named after "lower"
*******************************************************************/
static
void add_grid_module_net_connect_duplicated_pb_graph_pin(ModuleManager& module_manager,
const ModuleId& grid_module,
const ModuleId& child_module,
const size_t& child_instance,
t_type_ptr grid_type_descriptor,
t_pb_graph_pin* pb_graph_pin,
const e_side& border_side,
const enum e_spice_pin2pin_interc_type& pin2pin_interc_type) {
/* Make sure this is ONLY applied to output pins */
VTR_ASSERT(OUTPUT2OUTPUT_INTERC == pin2pin_interc_type);
/* Find the pin side for I/O grids*/
std::vector<e_side> grid_pin_sides;
/* For I/O grids, we care only one side
* Otherwise, we will iterate all the 4 sides
*/
if (IO_TYPE == grid_type_descriptor) {
grid_pin_sides.push_back(find_grid_module_pin_side(grid_type_descriptor, border_side));
} else {
grid_pin_sides.push_back(TOP);
grid_pin_sides.push_back(RIGHT);
grid_pin_sides.push_back(BOTTOM);
grid_pin_sides.push_back(LEFT);
}
/* num_pins/capacity = the number of pins that each type_descriptor has.
* Capacity defines the number of type_descriptors in each grid
* so the pin index at grid level = pin_index_in_type_descriptor
* + type_descriptor_index_in_capacity * num_pins_per_type_descriptor
*/
size_t grid_pin_index = pb_graph_pin->pin_count_in_cluster
+ child_instance * grid_type_descriptor->num_pins / grid_type_descriptor->capacity;
int pin_height = grid_type_descriptor->pin_height[grid_pin_index];
for (const e_side& side : grid_pin_sides) {
if (1 != grid_type_descriptor->pinloc[pin_height][side][grid_pin_index]) {
continue;
}
/* Reach here, it means this pin is on this side */
/* Create a net to connect the grid pin to child module pin */
ModuleNetId net = module_manager.create_module_net(grid_module);
/* Find the upper port in grid_module */
std::string grid_upper_port_name = generate_grid_duplicated_port_name(pin_height, side, grid_pin_index, true);
ModulePortId grid_module_upper_port_id = module_manager.find_module_port(grid_module, grid_upper_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(grid_module, grid_module_upper_port_id));
/* Find the lower port in grid_module */
std::string grid_lower_port_name = generate_grid_duplicated_port_name(pin_height, side, grid_pin_index, false);
ModulePortId grid_module_lower_port_id = module_manager.find_module_port(grid_module, grid_lower_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(grid_module, grid_module_lower_port_id));
/* Grid port always has only 1 pin, it is assumed when adding these ports to the module
* if you need a change, please also change the port adding codes
*/
size_t grid_module_pin_id = 0;
/* Find the port in child module */
std::string child_module_port_name = generate_pb_type_port_name(pb_graph_pin->port);
ModulePortId child_module_port_id = module_manager.find_module_port(child_module, child_module_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(child_module, child_module_port_id));
size_t child_module_pin_id = pb_graph_pin->pin_number;
/* Add net sources and sinks:
* For output-to-output connection,
* net_source is pb_graph_pin,
* while net_sinks are grid upper pin and grid lower pin
*/
module_manager.add_module_net_source(grid_module, net, child_module, child_instance, child_module_port_id, child_module_pin_id);
module_manager.add_module_net_sink(grid_module, net, grid_module, 0, grid_module_upper_port_id, grid_module_pin_id);
module_manager.add_module_net_sink(grid_module, net, grid_module, 0, grid_module_lower_port_id, grid_module_pin_id);
}
}
/********************************************************************
* Add module nets to connect a port of child pb_module
* to the duplicated ports of grid module
*******************************************************************/
void add_grid_module_nets_connect_duplicated_pb_type_ports(ModuleManager& module_manager,
const ModuleId& grid_module,
const ModuleId& child_module,
const size_t& child_instance,
t_type_ptr grid_type_descriptor,
const e_side& border_side) {
/* Ensure that we have a valid grid_type_descriptor */
VTR_ASSERT(NULL != grid_type_descriptor);
t_pb_graph_node* top_pb_graph_node = grid_type_descriptor->pb_graph_head;
VTR_ASSERT(NULL != top_pb_graph_node);
for (int iport = 0; iport < top_pb_graph_node->num_input_ports; ++iport) {
for (int ipin = 0; ipin < top_pb_graph_node->num_input_pins[iport]; ++ipin) {
add_grid_module_net_connect_pb_graph_pin(module_manager, grid_module,
child_module, child_instance,
grid_type_descriptor,
&(top_pb_graph_node->input_pins[iport][ipin]),
border_side,
INPUT2INPUT_INTERC);
}
}
for (int iport = 0; iport < top_pb_graph_node->num_output_ports; ++iport) {
for (int ipin = 0; ipin < top_pb_graph_node->num_output_pins[iport]; ++ipin) {
add_grid_module_net_connect_duplicated_pb_graph_pin(module_manager, grid_module,
child_module, child_instance,
grid_type_descriptor,
&(top_pb_graph_node->output_pins[iport][ipin]),
border_side,
OUTPUT2OUTPUT_INTERC);
}
}
for (int iport = 0; iport < top_pb_graph_node->num_clock_ports; ++iport) {
for (int ipin = 0; ipin < top_pb_graph_node->num_clock_pins[iport]; ++ipin) {
add_grid_module_net_connect_pb_graph_pin(module_manager, grid_module,
child_module, child_instance,
grid_type_descriptor,
&(top_pb_graph_node->clock_pins[iport][ipin]),
border_side,
INPUT2INPUT_INTERC);
}
}
}

View File

@ -0,0 +1,106 @@
/********************************************************************
* This file includes most utilized functions for grid module builders
*******************************************************************/
/* External library headers */
#include "vtr_assert.h"
/* FPGA-X2P headers */
#include "fpga_x2p_naming.h"
/* Module builder headers */
#include "build_grid_module_utils.h"
/* Global variables should be the last to include */
#include "globals.h"
/********************************************************************
* Find the side where I/O pins locate on a grid I/O block
* 1. I/O grids on the top side of FPGA only have ports on its bottom side
* 2. I/O grids on the right side of FPGA only have ports on its left side
* 3. I/O grids on the bottom side of FPGA only have ports on its top side
* 4. I/O grids on the left side of FPGA only have ports on its right side
*******************************************************************/
e_side find_grid_module_pin_side(t_type_ptr grid_type_descriptor,
const e_side& border_side) {
VTR_ASSERT(IO_TYPE == grid_type_descriptor);
Side side_manager(border_side);
return side_manager.get_opposite();
}
/********************************************************************
* Add module nets to connect a port of child pb_module
* to the grid module
*******************************************************************/
void add_grid_module_net_connect_pb_graph_pin(ModuleManager& module_manager,
const ModuleId& grid_module,
const ModuleId& child_module,
const size_t& child_instance,
t_type_ptr grid_type_descriptor,
t_pb_graph_pin* pb_graph_pin,
const e_side& border_side,
const enum e_spice_pin2pin_interc_type& pin2pin_interc_type) {
/* Find the pin side for I/O grids*/
std::vector<e_side> grid_pin_sides;
/* For I/O grids, we care only one side
* Otherwise, we will iterate all the 4 sides
*/
if (IO_TYPE == grid_type_descriptor) {
grid_pin_sides.push_back(find_grid_module_pin_side(grid_type_descriptor, border_side));
} else {
grid_pin_sides.push_back(TOP);
grid_pin_sides.push_back(RIGHT);
grid_pin_sides.push_back(BOTTOM);
grid_pin_sides.push_back(LEFT);
}
/* num_pins/capacity = the number of pins that each type_descriptor has.
* Capacity defines the number of type_descriptors in each grid
* so the pin index at grid level = pin_index_in_type_descriptor
* + type_descriptor_index_in_capacity * num_pins_per_type_descriptor
*/
size_t grid_pin_index = pb_graph_pin->pin_count_in_cluster
+ child_instance * grid_type_descriptor->num_pins / grid_type_descriptor->capacity;
int pin_height = grid_type_descriptor->pin_height[grid_pin_index];
for (const e_side& side : grid_pin_sides) {
if (1 != grid_type_descriptor->pinloc[pin_height][side][grid_pin_index]) {
continue;
}
/* Reach here, it means this pin is on this side */
/* Create a net to connect the grid pin to child module pin */
ModuleNetId net = module_manager.create_module_net(grid_module);
/* Find the port in grid_module */
vtr::Point<size_t> dummy_coordinate;
std::string grid_port_name = generate_grid_port_name(dummy_coordinate, pin_height, side, grid_pin_index, false);
ModulePortId grid_module_port_id = module_manager.find_module_port(grid_module, grid_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(grid_module, grid_module_port_id));
/* Grid port always has only 1 pin, it is assumed when adding these ports to the module
* if you need a change, please also change the port adding codes
*/
size_t grid_module_pin_id = 0;
/* Find the port in child module */
std::string child_module_port_name = generate_pb_type_port_name(pb_graph_pin->port);
ModulePortId child_module_port_id = module_manager.find_module_port(child_module, child_module_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(child_module, child_module_port_id));
size_t child_module_pin_id = pb_graph_pin->pin_number;
/* Add net sources and sinks:
* For input-to-input connection, net_source is grid pin, while net_sink is pb_graph_pin
* For output-to-output connection, net_source is pb_graph_pin, while net_sink is grid pin
*/
switch (pin2pin_interc_type) {
case INPUT2INPUT_INTERC:
module_manager.add_module_net_source(grid_module, net, grid_module, 0, grid_module_port_id, grid_module_pin_id);
module_manager.add_module_net_sink(grid_module, net, child_module, child_instance, child_module_port_id, child_module_pin_id);
break;
case OUTPUT2OUTPUT_INTERC:
module_manager.add_module_net_source(grid_module, net, child_module, child_instance, child_module_port_id, child_module_pin_id);
module_manager.add_module_net_sink(grid_module, net, grid_module, 0, grid_module_port_id, grid_module_pin_id);
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d]) Invalid pin-to-pin interconnection type!\n",
__FILE__, __LINE__);
exit(1);
}
}
}

View File

@ -0,0 +1,22 @@
#ifndef BUILD_GRID_MODULE_UTILS_H
#define BUILD_GRID_MODULE_UTILS_H
#include "vpr_types.h"
#include "sides.h"
#include "spice_types.h"
#include "module_manager.h"
e_side find_grid_module_pin_side(t_type_ptr grid_type_descriptor,
const e_side& border_side);
void add_grid_module_net_connect_pb_graph_pin(ModuleManager& module_manager,
const ModuleId& grid_module,
const ModuleId& child_module,
const size_t& child_instance,
t_type_ptr grid_type_descriptor,
t_pb_graph_pin* pb_graph_pin,
const e_side& border_side,
const enum e_spice_pin2pin_interc_type& pin2pin_interc_type);
#endif

View File

@ -27,24 +27,10 @@
/* Header files for Verilog generator */
#include "verilog_global.h"
#include "build_grid_module_utils.h"
#include "build_grid_module_duplicated_pins.h"
#include "build_grid_modules.h"
/********************************************************************
* Find the side where I/O pins locate on a grid I/O block
* 1. I/O grids on the top side of FPGA only have ports on its bottom side
* 2. I/O grids on the right side of FPGA only have ports on its left side
* 3. I/O grids on the bottom side of FPGA only have ports on its top side
* 4. I/O grids on the left side of FPGA only have ports on its right side
*******************************************************************/
static
e_side find_grid_module_pin_side(t_type_ptr grid_type_descriptor,
const e_side& border_side) {
VTR_ASSERT(IO_TYPE == grid_type_descriptor);
Side side_manager(border_side);
return side_manager.get_opposite();
}
/********************************************************************
* Add ports/pins to a grid module
* This function will iterate over all the pins that are defined
@ -100,85 +86,6 @@ void add_grid_module_pb_type_ports(ModuleManager& module_manager,
}
}
/********************************************************************
* Add module nets to connect a port of child pb_module
* to the grid module
*******************************************************************/
static
void add_grid_module_net_connect_pb_graph_pin(ModuleManager& module_manager,
const ModuleId& grid_module,
const ModuleId& child_module,
const size_t& child_instance,
t_type_ptr grid_type_descriptor,
t_pb_graph_pin* pb_graph_pin,
const e_side& border_side,
const enum e_spice_pin2pin_interc_type& pin2pin_interc_type) {
/* Find the pin side for I/O grids*/
std::vector<e_side> grid_pin_sides;
/* For I/O grids, we care only one side
* Otherwise, we will iterate all the 4 sides
*/
if (IO_TYPE == grid_type_descriptor) {
grid_pin_sides.push_back(find_grid_module_pin_side(grid_type_descriptor, border_side));
} else {
grid_pin_sides.push_back(TOP);
grid_pin_sides.push_back(RIGHT);
grid_pin_sides.push_back(BOTTOM);
grid_pin_sides.push_back(LEFT);
}
/* num_pins/capacity = the number of pins that each type_descriptor has.
* Capacity defines the number of type_descriptors in each grid
* so the pin index at grid level = pin_index_in_type_descriptor
* + type_descriptor_index_in_capacity * num_pins_per_type_descriptor
*/
size_t grid_pin_index = pb_graph_pin->pin_count_in_cluster
+ child_instance * grid_type_descriptor->num_pins / grid_type_descriptor->capacity;
int pin_height = grid_type_descriptor->pin_height[grid_pin_index];
for (const e_side& side : grid_pin_sides) {
if (1 != grid_type_descriptor->pinloc[pin_height][side][grid_pin_index]) {
continue;
}
/* Reach here, it means this pin is on this side */
/* Create a net to connect the grid pin to child module pin */
ModuleNetId net = module_manager.create_module_net(grid_module);
/* Find the port in grid_module */
vtr::Point<size_t> dummy_coordinate;
std::string grid_port_name = generate_grid_port_name(dummy_coordinate, pin_height, side, grid_pin_index, false);
ModulePortId grid_module_port_id = module_manager.find_module_port(grid_module, grid_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(grid_module, grid_module_port_id));
/* Grid port always has only 1 pin, it is assumed when adding these ports to the module
* if you need a change, please also change the port adding codes
*/
size_t grid_module_pin_id = 0;
/* Find the port in child module */
std::string child_module_port_name = generate_pb_type_port_name(pb_graph_pin->port);
ModulePortId child_module_port_id = module_manager.find_module_port(child_module, child_module_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(child_module, child_module_port_id));
size_t child_module_pin_id = pb_graph_pin->pin_number;
/* Add net sources and sinks:
* For input-to-input connection, net_source is grid pin, while net_sink is pb_graph_pin
* For output-to-output connection, net_source is pb_graph_pin, while net_sink is grid pin
*/
switch (pin2pin_interc_type) {
case INPUT2INPUT_INTERC:
module_manager.add_module_net_source(grid_module, net, grid_module, 0, grid_module_port_id, grid_module_pin_id);
module_manager.add_module_net_sink(grid_module, net, child_module, child_instance, child_module_port_id, child_module_pin_id);
break;
case OUTPUT2OUTPUT_INTERC:
module_manager.add_module_net_source(grid_module, net, child_module, child_instance, child_module_port_id, child_module_pin_id);
module_manager.add_module_net_sink(grid_module, net, grid_module, 0, grid_module_port_id, grid_module_pin_id);
break;
default:
vpr_printf(TIO_MESSAGE_ERROR,
"(File:%s, [LINE%d]) Invalid pin-to-pin interconnection type!\n",
__FILE__, __LINE__);
exit(1);
}
}
}
/********************************************************************
* Add module nets to connect ports/pins of a grid module
* to its child modules