2020-02-14 11:45:24 -06:00
/********************************************************************
2022-10-06 19:08:50 -05:00
* This file include most utilized functions for building connections
2020-02-14 11:45:24 -06:00
* inside the module graph for FPGA fabric
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Headers from vtrutil library */
# include "vtr_assert.h"
2020-06-30 00:17:03 -05:00
# include "vtr_time.h"
2020-02-14 11:45:24 -06:00
2020-11-10 17:59:00 -06:00
/* Headers from openfpgashell library */
# include "command_exit_codes.h"
2020-02-14 11:45:24 -06:00
/* Headers from openfpgautil library */
# include "openfpga_side_manager.h"
2020-11-10 17:59:00 -06:00
/* Headers from vpr library */
2022-10-06 19:08:50 -05:00
# include "build_routing_module_utils.h"
# include "build_top_module_connection.h"
# include "build_top_module_utils.h"
# include "module_manager_utils.h"
# include "openfpga_device_grid_utils.h"
2020-02-14 11:45:24 -06:00
# include "openfpga_naming.h"
2020-03-21 22:02:47 -05:00
# include "openfpga_physical_tile_utils.h"
2022-10-06 19:08:50 -05:00
# include "openfpga_reserved_words.h"
2022-08-17 18:25:12 -05:00
# include "openfpga_rr_graph_utils.h"
2022-10-06 19:08:50 -05:00
# include "pb_type_utils.h"
# include "rr_gsb_utils.h"
# include "vpr_utils.h"
2020-02-14 11:45:24 -06:00
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
2022-10-06 19:08:50 -05:00
* Add module nets to connect a GSB to adjacent grid ports / pins
2020-02-14 11:45:24 -06:00
* as well as connection blocks
* This function will create nets for the following types of connections
* between grid output pins of Switch block and adjacent grids
* In this case , the net source is the grid pin , while the net sink
* is the switch block pin
2022-10-06 19:08:50 -05:00
*
2020-02-14 11:45:24 -06:00
* + - - - - - - - - - - - - + + - - - - - - - - - - - - +
* | | | |
* | Grid | | Grid |
* | [ x ] [ y + 1 ] | | [ x + 1 ] [ y + 1 ] |
* | | - - - - + + - - - - | |
* + - - - - - - - - - - - - + | | + - - - - - - - - - - - - +
* | v v |
* | + - - - - - - - - - - - - + |
* + - - - - - - > | | < - - - - - +
* | Switch |
* | Block |
* + - - - - - - > | [ x ] [ y ] | < - - - - - +
* | + - - - - - - - - - - - - + |
* | ^ ^ |
* | | | |
* + - - - - - - - - - - - - + | | + - - - - - - - - - - - - +
* | | - - - - + + - - - - - | |
* | Grid | | Grid |
* | [ x ] [ y ] | | [ x + 1 ] [ y ] |
* | | | |
* + - - - - - - - - - - - - + + - - - - - - - - - - - - +
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-10-06 19:08:50 -05:00
static void add_top_module_nets_connect_grids_and_sb (
ModuleManager & module_manager , const ModuleId & top_module ,
const VprDeviceAnnotation & vpr_device_annotation , const DeviceGrid & grids ,
const vtr : : Matrix < size_t > & grid_instance_ids , const RRGraphView & rr_graph ,
const DeviceRRGSB & device_rr_gsb , const RRGSB & rr_gsb ,
const vtr : : Matrix < size_t > & sb_instance_ids ,
const bool & compact_routing_hierarchy ) {
2020-03-24 18:39:26 -05:00
/* Skip those Switch blocks that do not exist */
if ( false = = rr_gsb . is_sb_exist ( ) ) {
return ;
}
2022-10-06 19:08:50 -05:00
/* We could have two different coordinators, one is the instance, the other is
* the module */
vtr : : Point < size_t > instance_sb_coordinate ( rr_gsb . get_sb_x ( ) ,
rr_gsb . get_sb_y ( ) ) ;
2020-02-14 11:45:24 -06:00
vtr : : Point < size_t > module_gsb_coordinate ( rr_gsb . get_x ( ) , rr_gsb . get_y ( ) ) ;
2022-10-06 19:08:50 -05:00
/* If we use compact routing hierarchy, we should find the unique module of
* CB , which is added to the top module */
2020-02-14 11:45:24 -06:00
if ( true = = compact_routing_hierarchy ) {
vtr : : Point < size_t > gsb_coord ( rr_gsb . get_x ( ) , rr_gsb . get_y ( ) ) ;
const RRGSB & unique_mirror = device_rr_gsb . get_sb_unique_module ( gsb_coord ) ;
2022-10-06 19:08:50 -05:00
module_gsb_coordinate . set_x ( unique_mirror . get_x ( ) ) ;
module_gsb_coordinate . set_y ( unique_mirror . get_y ( ) ) ;
}
2020-02-14 11:45:24 -06:00
/* This is the source cb that is added to the top module */
const RRGSB & module_sb = device_rr_gsb . get_gsb ( module_gsb_coordinate ) ;
2022-10-06 19:08:50 -05:00
vtr : : Point < size_t > module_sb_coordinate ( module_sb . get_sb_x ( ) ,
module_sb . get_sb_y ( ) ) ;
2020-02-14 11:45:24 -06:00
/* Collect sink-related information */
2022-10-06 19:08:50 -05:00
std : : string sink_sb_module_name =
generate_switch_block_module_name ( module_sb_coordinate ) ;
2020-02-14 11:45:24 -06:00
ModuleId sink_sb_module = module_manager . find_module ( sink_sb_module_name ) ;
VTR_ASSERT ( true = = module_manager . valid_module_id ( sink_sb_module ) ) ;
2022-10-06 19:08:50 -05:00
size_t sink_sb_instance =
sb_instance_ids [ instance_sb_coordinate . x ( ) ] [ instance_sb_coordinate . y ( ) ] ;
2020-02-14 11:45:24 -06:00
/* Connect grid output pins (OPIN) to switch block grid pins */
for ( size_t side = 0 ; side < module_sb . get_num_sides ( ) ; + + side ) {
SideManager side_manager ( side ) ;
2022-10-06 19:08:50 -05:00
for ( size_t inode = 0 ;
inode < module_sb . get_num_opin_nodes ( side_manager . get_side ( ) ) ;
+ + inode ) {
2020-02-14 11:45:24 -06:00
/* Collect source-related information */
2022-10-06 19:08:50 -05:00
/* Generate the grid module name by considering if it locates on the
* border */
vtr : : Point < size_t > grid_coordinate (
rr_graph . node_xlow (
rr_gsb . get_opin_node ( side_manager . get_side ( ) , inode ) ) ,
rr_graph . node_ylow (
rr_gsb . get_opin_node ( side_manager . get_side ( ) , inode ) ) ) ;
std : : string src_grid_module_name =
generate_grid_block_module_name_in_top_module (
std : : string ( GRID_MODULE_NAME_PREFIX ) , grids , grid_coordinate ) ;
ModuleId src_grid_module =
module_manager . find_module ( src_grid_module_name ) ;
2020-02-14 11:45:24 -06:00
VTR_ASSERT ( true = = module_manager . valid_module_id ( src_grid_module ) ) ;
2022-10-06 19:08:50 -05:00
size_t src_grid_instance =
grid_instance_ids [ grid_coordinate . x ( ) ] [ grid_coordinate . y ( ) ] ;
size_t src_grid_pin_index = rr_graph . node_pin_num (
rr_gsb . get_opin_node ( side_manager . get_side ( ) , inode ) ) ;
t_physical_tile_type_ptr grid_type_descriptor =
grids [ grid_coordinate . x ( ) ] [ grid_coordinate . y ( ) ] . type ;
size_t src_grid_pin_width =
grid_type_descriptor - > pin_width_offset [ src_grid_pin_index ] ;
size_t src_grid_pin_height =
grid_type_descriptor - > pin_height_offset [ src_grid_pin_index ] ;
BasicPort src_grid_pin_info =
vpr_device_annotation . physical_tile_pin_port_info ( grid_type_descriptor ,
src_grid_pin_index ) ;
2021-03-13 21:05:18 -06:00
VTR_ASSERT ( true = = src_grid_pin_info . is_valid ( ) ) ;
2022-10-06 19:08:50 -05:00
int subtile_index = vpr_device_annotation . physical_tile_pin_subtile_index (
grid_type_descriptor , src_grid_pin_index ) ;
VTR_ASSERT ( OPEN ! = subtile_index & &
subtile_index < grid_type_descriptor - > capacity ) ;
std : : string src_grid_port_name = generate_grid_port_name (
src_grid_pin_width , src_grid_pin_height , subtile_index ,
get_rr_graph_single_node_side (
rr_graph , rr_gsb . get_opin_node ( side_manager . get_side ( ) , inode ) ) ,
src_grid_pin_info ) ;
ModulePortId src_grid_port_id =
module_manager . find_module_port ( src_grid_module , src_grid_port_name ) ;
VTR_ASSERT ( true = = module_manager . valid_module_port_id ( src_grid_module ,
src_grid_port_id ) ) ;
BasicPort src_grid_port =
module_manager . module_port ( src_grid_module , src_grid_port_id ) ;
2020-02-14 11:45:24 -06:00
/* Collect sink-related information */
2022-10-06 19:08:50 -05:00
vtr : : Point < size_t > sink_sb_port_coord (
rr_graph . node_xlow (
module_sb . get_opin_node ( side_manager . get_side ( ) , inode ) ) ,
rr_graph . node_ylow (
module_sb . get_opin_node ( side_manager . get_side ( ) , inode ) ) ) ;
std : : string sink_sb_port_name = generate_sb_module_grid_port_name (
side_manager . get_side ( ) ,
get_rr_graph_single_node_side (
rr_graph , module_sb . get_opin_node ( side_manager . get_side ( ) , inode ) ) ,
grids , vpr_device_annotation , rr_graph ,
module_sb . get_opin_node ( side_manager . get_side ( ) , inode ) ) ;
ModulePortId sink_sb_port_id =
module_manager . find_module_port ( sink_sb_module , sink_sb_port_name ) ;
VTR_ASSERT ( true = = module_manager . valid_module_port_id ( sink_sb_module ,
sink_sb_port_id ) ) ;
BasicPort sink_sb_port =
module_manager . module_port ( sink_sb_module , sink_sb_port_id ) ;
2020-02-14 11:45:24 -06:00
/* Source and sink port should match in size */
VTR_ASSERT ( src_grid_port . get_width ( ) = = sink_sb_port . get_width ( ) ) ;
2022-10-06 19:08:50 -05:00
2020-02-14 11:45:24 -06:00
/* Create a net for each pin */
for ( size_t pin_id = 0 ; pin_id < src_grid_port . pins ( ) . size ( ) ; + + pin_id ) {
2022-10-06 19:08:50 -05:00
ModuleNetId net = create_module_source_pin_net (
module_manager , top_module , src_grid_module , src_grid_instance ,
src_grid_port_id , src_grid_port . pins ( ) [ pin_id ] ) ;
2020-02-14 11:45:24 -06:00
/* Configure the net sink */
2022-10-06 19:08:50 -05:00
module_manager . add_module_net_sink ( top_module , net , sink_sb_module ,
sink_sb_instance , sink_sb_port_id ,
sink_sb_port . pins ( ) [ pin_id ] ) ;
2020-02-14 11:45:24 -06:00
}
2022-10-06 19:08:50 -05:00
}
2020-02-14 11:45:24 -06:00
}
}
/********************************************************************
2022-10-06 19:08:50 -05:00
* Add module nets to connect a GSB to adjacent grid ports / pins
2020-02-14 11:45:24 -06:00
* as well as connection blocks
* This function will create nets for the following types of connections
* between grid output pins of Switch block and adjacent grids
* In this case , the net source is the grid pin , while the net sink
* is the switch block pin
*
* In particular , this function considers the duplicated output pins of grids
* when creating the connecting nets .
* The follow figure shows the different pin postfix to be considered when
* connecting the grid pins to SB inputs
2022-10-06 19:08:50 -05:00
*
2020-02-14 11:45:24 -06:00
* + - - - - - - - - - - - - + + - - - - - - - - - - - - +
* | | | |
* | Grid | | Grid |
* | [ x ] [ y + 1 ] | lower lower | [ x + 1 ] [ y + 1 ] |
* | | - - - - + + - - - - | |
* + - - - - - - - - - - - - + | | + - - - - - - - - - - - - +
* | lower v v | upper
* | + - - - - - - - - - - - - + |
* + - - - - - - > | | < - - - - - +
* | Switch |
* | Block |
* + - - - - - - > | [ x ] [ y ] | < - - - - - +
* | + - - - - - - - - - - - - + |
* | ^ ^ |
* | lower | | | upper
* + - - - - - - - - - - - - + | | + - - - - - - - - - - - - +
* | | - - - - + + - - - - - | |
* | Grid | upper upper | Grid |
* | [ x ] [ y ] | | [ x + 1 ] [ y ] |
* | | | |
* + - - - - - - - - - - - - + + - - - - - - - - - - - - +
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-10-06 19:08:50 -05:00
static void add_top_module_nets_connect_grids_and_sb_with_duplicated_pins (
ModuleManager & module_manager , const ModuleId & top_module ,
const VprDeviceAnnotation & vpr_device_annotation , const DeviceGrid & grids ,
const vtr : : Matrix < size_t > & grid_instance_ids , const RRGraphView & rr_graph ,
const DeviceRRGSB & device_rr_gsb , const RRGSB & rr_gsb ,
const vtr : : Matrix < size_t > & sb_instance_ids ,
const bool & compact_routing_hierarchy ) {
2020-03-24 18:39:26 -05:00
/* Skip those Switch blocks that do not exist */
if ( false = = rr_gsb . is_sb_exist ( ) ) {
return ;
}
2022-10-06 19:08:50 -05:00
/* We could have two different coordinators, one is the instance, the other is
* the module */
vtr : : Point < size_t > instance_sb_coordinate ( rr_gsb . get_sb_x ( ) ,
rr_gsb . get_sb_y ( ) ) ;
2020-02-14 11:45:24 -06:00
vtr : : Point < size_t > module_gsb_coordinate ( rr_gsb . get_x ( ) , rr_gsb . get_y ( ) ) ;
2022-10-06 19:08:50 -05:00
/* If we use compact routing hierarchy, we should find the unique module of
* CB , which is added to the top module */
2020-02-14 11:45:24 -06:00
if ( true = = compact_routing_hierarchy ) {
vtr : : Point < size_t > gsb_coord ( rr_gsb . get_x ( ) , rr_gsb . get_y ( ) ) ;
const RRGSB & unique_mirror = device_rr_gsb . get_sb_unique_module ( gsb_coord ) ;
2022-10-06 19:08:50 -05:00
module_gsb_coordinate . set_x ( unique_mirror . get_x ( ) ) ;
module_gsb_coordinate . set_y ( unique_mirror . get_y ( ) ) ;
}
2020-02-14 11:45:24 -06:00
/* This is the source cb that is added to the top module */
const RRGSB & module_sb = device_rr_gsb . get_gsb ( module_gsb_coordinate ) ;
2022-10-06 19:08:50 -05:00
vtr : : Point < size_t > module_sb_coordinate ( module_sb . get_sb_x ( ) ,
module_sb . get_sb_y ( ) ) ;
2020-02-14 11:45:24 -06:00
/* Collect sink-related information */
2022-10-06 19:08:50 -05:00
std : : string sink_sb_module_name =
generate_switch_block_module_name ( module_sb_coordinate ) ;
2020-02-14 11:45:24 -06:00
ModuleId sink_sb_module = module_manager . find_module ( sink_sb_module_name ) ;
VTR_ASSERT ( true = = module_manager . valid_module_id ( sink_sb_module ) ) ;
2022-10-06 19:08:50 -05:00
size_t sink_sb_instance =
sb_instance_ids [ instance_sb_coordinate . x ( ) ] [ instance_sb_coordinate . y ( ) ] ;
2020-02-14 11:45:24 -06:00
2022-10-06 19:08:50 -05:00
/* Create a truth table for the postfix to be used regarding to the different
* side of switch blocks */
2020-02-14 11:45:24 -06:00
std : : map < e_side , bool > sb_side2postfix_map ;
2022-10-06 19:08:50 -05:00
/* Boolean variable "true" indicates the upper postfix in naming functions
* Boolean variable " false " indicates the lower postfix in naming functions
2020-02-14 11:45:24 -06:00
*/
sb_side2postfix_map [ TOP ] = false ;
sb_side2postfix_map [ RIGHT ] = true ;
sb_side2postfix_map [ BOTTOM ] = true ;
sb_side2postfix_map [ LEFT ] = false ;
/* Connect grid output pins (OPIN) to switch block grid pins */
for ( size_t side = 0 ; side < module_sb . get_num_sides ( ) ; + + side ) {
SideManager side_manager ( side ) ;
2022-10-06 19:08:50 -05:00
for ( size_t inode = 0 ;
inode < module_sb . get_num_opin_nodes ( side_manager . get_side ( ) ) ;
+ + inode ) {
2020-02-14 11:45:24 -06:00
/* Collect source-related information */
2022-10-06 19:08:50 -05:00
/* Generate the grid module name by considering if it locates on the
* border */
vtr : : Point < size_t > grid_coordinate (
rr_graph . node_xlow (
rr_gsb . get_opin_node ( side_manager . get_side ( ) , inode ) ) ,
rr_graph . node_ylow (
rr_gsb . get_opin_node ( side_manager . get_side ( ) , inode ) ) ) ;
std : : string src_grid_module_name =
generate_grid_block_module_name_in_top_module (
std : : string ( GRID_MODULE_NAME_PREFIX ) , grids , grid_coordinate ) ;
ModuleId src_grid_module =
module_manager . find_module ( src_grid_module_name ) ;
2020-02-14 11:45:24 -06:00
VTR_ASSERT ( true = = module_manager . valid_module_id ( src_grid_module ) ) ;
2022-10-06 19:08:50 -05:00
size_t src_grid_instance =
grid_instance_ids [ grid_coordinate . x ( ) ] [ grid_coordinate . y ( ) ] ;
size_t src_grid_pin_index = rr_graph . node_pin_num (
rr_gsb . get_opin_node ( side_manager . get_side ( ) , inode ) ) ;
t_physical_tile_type_ptr grid_type_descriptor =
grids [ grid_coordinate . x ( ) ] [ grid_coordinate . y ( ) ] . type ;
size_t src_grid_pin_width =
grid_type_descriptor - > pin_width_offset [ src_grid_pin_index ] ;
size_t src_grid_pin_height =
grid_type_descriptor - > pin_height_offset [ src_grid_pin_index ] ;
BasicPort src_grid_pin_info =
vpr_device_annotation . physical_tile_pin_port_info ( grid_type_descriptor ,
src_grid_pin_index ) ;
2021-03-13 21:05:18 -06:00
VTR_ASSERT ( true = = src_grid_pin_info . is_valid ( ) ) ;
2022-10-06 19:08:50 -05:00
int subtile_index = vpr_device_annotation . physical_tile_pin_subtile_index (
grid_type_descriptor , src_grid_pin_index ) ;
VTR_ASSERT ( OPEN ! = subtile_index & &
subtile_index < grid_type_descriptor - > capacity ) ;
2020-02-14 11:45:24 -06:00
/* Pins for direct connection are NOT duplicated.
2022-10-06 19:08:50 -05:00
* Follow the traditional recipe when adding nets !
* Xifan : I assume that each direct connection pin must have Fc = 0.
2020-02-14 11:45:24 -06:00
* For other duplicated pins , we follow the new naming
*/
std : : string src_grid_port_name ;
2022-10-06 19:08:50 -05:00
if ( 0. = =
find_physical_tile_pin_Fc ( grid_type_descriptor , src_grid_pin_index ) ) {
src_grid_port_name = generate_grid_port_name (
src_grid_pin_width , src_grid_pin_height , subtile_index ,
get_rr_graph_single_node_side (
rr_graph , rr_gsb . get_opin_node ( side_manager . get_side ( ) , inode ) ) ,
src_grid_pin_info ) ;
2020-02-14 11:45:24 -06:00
} else {
2022-10-06 19:08:50 -05:00
src_grid_port_name = generate_grid_duplicated_port_name (
src_grid_pin_width , src_grid_pin_height , subtile_index ,
get_rr_graph_single_node_side (
rr_graph , rr_gsb . get_opin_node ( side_manager . get_side ( ) , inode ) ) ,
src_grid_pin_info , sb_side2postfix_map [ side_manager . get_side ( ) ] ) ;
2020-02-14 11:45:24 -06:00
}
2022-10-06 19:08:50 -05:00
ModulePortId src_grid_port_id =
module_manager . find_module_port ( src_grid_module , src_grid_port_name ) ;
VTR_ASSERT ( true = = module_manager . valid_module_port_id ( src_grid_module ,
src_grid_port_id ) ) ;
BasicPort src_grid_port =
module_manager . module_port ( src_grid_module , src_grid_port_id ) ;
2020-02-14 11:45:24 -06:00
/* Collect sink-related information */
2022-10-06 19:08:50 -05:00
vtr : : Point < size_t > sink_sb_port_coord (
rr_graph . node_xlow (
module_sb . get_opin_node ( side_manager . get_side ( ) , inode ) ) ,
rr_graph . node_ylow (
module_sb . get_opin_node ( side_manager . get_side ( ) , inode ) ) ) ;
std : : string sink_sb_port_name = generate_sb_module_grid_port_name (
side_manager . get_side ( ) ,
get_rr_graph_single_node_side (
rr_graph , module_sb . get_opin_node ( side_manager . get_side ( ) , inode ) ) ,
grids , vpr_device_annotation , rr_graph ,
module_sb . get_opin_node ( side_manager . get_side ( ) , inode ) ) ;
ModulePortId sink_sb_port_id =
module_manager . find_module_port ( sink_sb_module , sink_sb_port_name ) ;
VTR_ASSERT ( true = = module_manager . valid_module_port_id ( sink_sb_module ,
sink_sb_port_id ) ) ;
BasicPort sink_sb_port =
module_manager . module_port ( sink_sb_module , sink_sb_port_id ) ;
2020-02-14 11:45:24 -06:00
/* Source and sink port should match in size */
VTR_ASSERT ( src_grid_port . get_width ( ) = = sink_sb_port . get_width ( ) ) ;
2022-10-06 19:08:50 -05:00
2020-02-14 11:45:24 -06:00
/* Create a net for each pin */
for ( size_t pin_id = 0 ; pin_id < src_grid_port . pins ( ) . size ( ) ; + + pin_id ) {
2022-10-06 19:08:50 -05:00
ModuleNetId net = create_module_source_pin_net (
module_manager , top_module , src_grid_module , src_grid_instance ,
src_grid_port_id , src_grid_port . pins ( ) [ pin_id ] ) ;
2020-02-14 11:45:24 -06:00
/* Configure the net sink */
2022-10-06 19:08:50 -05:00
module_manager . add_module_net_sink ( top_module , net , sink_sb_module ,
sink_sb_instance , sink_sb_port_id ,
sink_sb_port . pins ( ) [ pin_id ] ) ;
2020-02-14 11:45:24 -06:00
}
2022-10-06 19:08:50 -05:00
}
2020-02-14 11:45:24 -06:00
}
}
/********************************************************************
* This function will create nets for the connections
* between grid input pins and connection blocks
2022-10-06 19:08:50 -05:00
* In this case , the net source is the connection block pin ,
2020-02-14 11:45:24 -06:00
* while the net sink is the grid input
*
* + - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - +
* | | | | | |
* | Grid | < - - - - - | Connection Block | - - - - - > | Grid |
2022-10-06 19:08:50 -05:00
* | [ x ] [ y + 1 ] | | Y - direction | | [ x + 1 ] [ y + 1 ] |
2020-02-14 11:45:24 -06:00
* | | | [ x ] [ y + 1 ] | | |
* + - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - +
2022-10-06 19:08:50 -05:00
* ^
* |
* + - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - +
* | Connection | | |
* | Block | | Switch Block |
* | X - direction | | [ x ] [ y ] |
* | [ x ] [ y ] | | |
* + - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - +
* |
* v
* + - - - - - - - - - - - - +
* | |
* | Grid |
* | [ x ] [ y ] |
* | |
* + - - - - - - - - - - - - +
2020-02-14 11:45:24 -06:00
*
*
2022-10-06 19:08:50 -05:00
* Relationship between source connection block and its unique module
2020-02-14 11:45:24 -06:00
* Take an example of a CBY
*
* grid_pin name should follow unique module of Grid [ x ] [ y + 1 ]
* cb_pin name should follow unique module of CBY [ x ] [ y + 1 ]
2022-10-06 19:08:50 -05:00
*
* However , instace id should follow the origin Grid and Connection block
*
*
* + - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - +
* | | | |
2020-02-14 11:45:24 -06:00
* | Grid | < - - - - - - - - - - - - | Connection Block |
2022-10-06 19:08:50 -05:00
* | [ x ] [ y + 1 ] | | Y - direction |
2020-02-14 11:45:24 -06:00
* | | | [ x ] [ y + 1 ] |
* + - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - +
* ^
* | | unique mirror
2022-10-06 19:08:50 -05:00
* + - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - +
* | | | |
2020-02-14 11:45:24 -06:00
* | Grid | < - - - - - - - - - - - - | Connection Block |
2022-10-06 19:08:50 -05:00
* | [ i ] [ j + 1 ] | | Y - direction |
2020-02-14 11:45:24 -06:00
* | | | [ i ] [ j + 1 ] |
* + - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - +
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-10-06 19:08:50 -05:00
static void add_top_module_nets_connect_grids_and_cb (
ModuleManager & module_manager , const ModuleId & top_module ,
const VprDeviceAnnotation & vpr_device_annotation , const DeviceGrid & grids ,
const vtr : : Matrix < size_t > & grid_instance_ids , const RRGraphView & rr_graph ,
const DeviceRRGSB & device_rr_gsb , const RRGSB & rr_gsb ,
const t_rr_type & cb_type , const vtr : : Matrix < size_t > & cb_instance_ids ,
const bool & compact_routing_hierarchy ) {
/* We could have two different coordinators, one is the instance, the other is
* the module */
vtr : : Point < size_t > instance_cb_coordinate ( rr_gsb . get_cb_x ( cb_type ) ,
rr_gsb . get_cb_y ( cb_type ) ) ;
2020-02-14 11:45:24 -06:00
vtr : : Point < size_t > module_gsb_coordinate ( rr_gsb . get_x ( ) , rr_gsb . get_y ( ) ) ;
/* Skip those Connection blocks that do not exist */
if ( false = = rr_gsb . is_cb_exist ( cb_type ) ) {
return ;
}
/* Skip if the cb does not contain any configuration bits! */
if ( true = = connection_block_contain_only_routing_tracks ( rr_gsb , cb_type ) ) {
return ;
}
2022-10-06 19:08:50 -05:00
/* If we use compact routing hierarchy, we should find the unique module of
* CB , which is added to the top module */
2020-02-14 11:45:24 -06:00
if ( true = = compact_routing_hierarchy ) {
vtr : : Point < size_t > gsb_coord ( rr_gsb . get_x ( ) , rr_gsb . get_y ( ) ) ;
2022-10-06 19:08:50 -05:00
const RRGSB & unique_mirror =
device_rr_gsb . get_cb_unique_module ( cb_type , gsb_coord ) ;
module_gsb_coordinate . set_x ( unique_mirror . get_x ( ) ) ;
module_gsb_coordinate . set_y ( unique_mirror . get_y ( ) ) ;
}
2020-02-14 11:45:24 -06:00
/* This is the source cb that is added to the top module */
const RRGSB & module_cb = device_rr_gsb . get_gsb ( module_gsb_coordinate ) ;
2022-10-06 19:08:50 -05:00
vtr : : Point < size_t > module_cb_coordinate ( module_cb . get_cb_x ( cb_type ) ,
module_cb . get_cb_y ( cb_type ) ) ;
2020-02-14 11:45:24 -06:00
/* Collect source-related information */
2022-10-06 19:08:50 -05:00
std : : string src_cb_module_name =
generate_connection_block_module_name ( cb_type , module_cb_coordinate ) ;
2020-02-14 11:45:24 -06:00
ModuleId src_cb_module = module_manager . find_module ( src_cb_module_name ) ;
VTR_ASSERT ( true = = module_manager . valid_module_id ( src_cb_module ) ) ;
/* Instance id should follow the instance cb coordinate */
2022-10-06 19:08:50 -05:00
size_t src_cb_instance =
cb_instance_ids [ instance_cb_coordinate . x ( ) ] [ instance_cb_coordinate . y ( ) ] ;
2020-02-14 11:45:24 -06:00
/* Iterate over the output pins of the Connection Block */
std : : vector < enum e_side > cb_ipin_sides = module_cb . get_cb_ipin_sides ( cb_type ) ;
for ( size_t iside = 0 ; iside < cb_ipin_sides . size ( ) ; + + iside ) {
enum e_side cb_ipin_side = cb_ipin_sides [ iside ] ;
2022-10-06 19:08:50 -05:00
for ( size_t inode = 0 ; inode < module_cb . get_num_ipin_nodes ( cb_ipin_side ) ;
+ + inode ) {
2020-02-14 11:45:24 -06:00
/* Collect source-related information */
RRNodeId module_ipin_node = module_cb . get_ipin_node ( cb_ipin_side , inode ) ;
2022-10-06 19:08:50 -05:00
vtr : : Point < size_t > cb_src_port_coord (
rr_graph . node_xlow ( module_ipin_node ) ,
rr_graph . node_ylow ( module_ipin_node ) ) ;
std : : string src_cb_port_name = generate_cb_module_grid_port_name (
cb_ipin_side , grids , vpr_device_annotation , rr_graph , module_ipin_node ) ;
ModulePortId src_cb_port_id =
module_manager . find_module_port ( src_cb_module , src_cb_port_name ) ;
VTR_ASSERT ( true = = module_manager . valid_module_port_id ( src_cb_module ,
src_cb_port_id ) ) ;
BasicPort src_cb_port =
module_manager . module_port ( src_cb_module , src_cb_port_id ) ;
2020-02-14 11:45:24 -06:00
/* Collect sink-related information */
/* Note that we use the instance cb pin here!!!
2022-10-06 19:08:50 -05:00
* because it has the correct coordinator for the grid ! ! !
2020-02-14 11:45:24 -06:00
*/
RRNodeId instance_ipin_node = rr_gsb . get_ipin_node ( cb_ipin_side , inode ) ;
2022-10-06 19:08:50 -05:00
vtr : : Point < size_t > grid_coordinate (
rr_graph . node_xlow ( instance_ipin_node ) ,
rr_graph . node_ylow ( instance_ipin_node ) ) ;
std : : string sink_grid_module_name =
generate_grid_block_module_name_in_top_module (
std : : string ( GRID_MODULE_NAME_PREFIX ) , grids , grid_coordinate ) ;
ModuleId sink_grid_module =
module_manager . find_module ( sink_grid_module_name ) ;
2020-02-14 11:45:24 -06:00
VTR_ASSERT ( true = = module_manager . valid_module_id ( sink_grid_module ) ) ;
2022-10-06 19:08:50 -05:00
size_t sink_grid_instance =
grid_instance_ids [ grid_coordinate . x ( ) ] [ grid_coordinate . y ( ) ] ;
2020-02-14 11:45:24 -06:00
size_t sink_grid_pin_index = rr_graph . node_pin_num ( instance_ipin_node ) ;
2021-03-13 21:05:18 -06:00
2022-10-06 19:08:50 -05:00
t_physical_tile_type_ptr grid_type_descriptor =
grids [ grid_coordinate . x ( ) ] [ grid_coordinate . y ( ) ] . type ;
size_t sink_grid_pin_width =
grid_type_descriptor - > pin_width_offset [ sink_grid_pin_index ] ;
size_t sink_grid_pin_height =
grid_type_descriptor - > pin_height_offset [ sink_grid_pin_index ] ;
BasicPort sink_grid_pin_info =
vpr_device_annotation . physical_tile_pin_port_info ( grid_type_descriptor ,
sink_grid_pin_index ) ;
2021-03-13 21:05:18 -06:00
VTR_ASSERT ( true = = sink_grid_pin_info . is_valid ( ) ) ;
2022-10-06 19:08:50 -05:00
int subtile_index = vpr_device_annotation . physical_tile_pin_subtile_index (
grid_type_descriptor , sink_grid_pin_index ) ;
VTR_ASSERT ( OPEN ! = subtile_index & &
subtile_index < grid_type_descriptor - > capacity ) ;
std : : string sink_grid_port_name = generate_grid_port_name (
sink_grid_pin_width , sink_grid_pin_height , subtile_index ,
get_rr_graph_single_node_side (
rr_graph , rr_gsb . get_ipin_node ( cb_ipin_side , inode ) ) ,
sink_grid_pin_info ) ;
ModulePortId sink_grid_port_id =
module_manager . find_module_port ( sink_grid_module , sink_grid_port_name ) ;
VTR_ASSERT ( true = = module_manager . valid_module_port_id (
sink_grid_module , sink_grid_port_id ) ) ;
BasicPort sink_grid_port =
module_manager . module_port ( sink_grid_module , sink_grid_port_id ) ;
2020-02-14 11:45:24 -06:00
/* Source and sink port should match in size */
VTR_ASSERT ( src_cb_port . get_width ( ) = = sink_grid_port . get_width ( ) ) ;
2022-10-06 19:08:50 -05:00
2020-02-14 11:45:24 -06:00
/* Create a net for each pin */
for ( size_t pin_id = 0 ; pin_id < src_cb_port . pins ( ) . size ( ) ; + + pin_id ) {
2022-10-06 19:08:50 -05:00
ModuleNetId net = create_module_source_pin_net (
module_manager , top_module , src_cb_module , src_cb_instance ,
src_cb_port_id , src_cb_port . pins ( ) [ pin_id ] ) ;
2020-02-14 11:45:24 -06:00
/* Configure the net sink */
2022-10-06 19:08:50 -05:00
module_manager . add_module_net_sink (
top_module , net , sink_grid_module , sink_grid_instance ,
sink_grid_port_id , sink_grid_port . pins ( ) [ pin_id ] ) ;
2020-02-14 11:45:24 -06:00
}
}
}
}
/********************************************************************
* This function will create nets for the connections
* between connection block and switch block pins
* Two cases should be considered :
* a . The switch block pin denotes an input of a routing track
* The net source is an output of a routing track of connection block
* while the net sink is an input of a routing track of switch block
* b . The switch block pin denotes an output of a routing track
2022-10-06 19:08:50 -05:00
* The net source is an output of routing track of switch block
2020-02-14 11:45:24 -06:00
* while the net sink is an input of a routing track of connection block
*
* + - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - +
* | | | | | |
* | Grid | | Connection Block | | Grid |
2022-10-06 19:08:50 -05:00
* | [ x ] [ y + 1 ] | | Y - direction | | [ x + 1 ] [ y + 1 ] |
2020-02-14 11:45:24 -06:00
* | | | [ x ] [ y + 1 ] | | |
* + - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - +
* | ^
* v |
* + - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - +
* | Connection | - - - - - > | | - - - - - > | Connection |
* | Block | | Switch Block | | Block |
* | X - direction | < - - - - - | [ x ] [ y ] | < - - - - - | X - direction |
* | [ x ] [ y ] | | | | [ x + 1 ] [ y ] |
* + - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - +
* | ^
* v |
* + - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - +
* | | | | | |
* | Grid | | Connection Block | | Grid |
* | [ x ] [ y ] | | Y - direction | | [ x ] [ y + 1 ] |
* | | | [ x ] [ y ] | | |
* + - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - +
*
2022-10-06 19:08:50 -05:00
* Here , to achieve the purpose , we can simply iterate over the
* four sides of switch block and make connections to adjancent
2020-02-14 11:45:24 -06:00
* connection blocks
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-10-06 19:08:50 -05:00
static void add_top_module_nets_connect_sb_and_cb (
ModuleManager & module_manager , const ModuleId & top_module ,
const RRGraphView & rr_graph , const DeviceRRGSB & device_rr_gsb ,
const RRGSB & rr_gsb , const vtr : : Matrix < size_t > & sb_instance_ids ,
const std : : map < t_rr_type , vtr : : Matrix < size_t > > & cb_instance_ids ,
const bool & compact_routing_hierarchy ) {
/* We could have two different coordinators, one is the instance, the other is
* the module */
vtr : : Point < size_t > instance_sb_coordinate ( rr_gsb . get_sb_x ( ) ,
rr_gsb . get_sb_y ( ) ) ;
2020-02-14 11:45:24 -06:00
vtr : : Point < size_t > module_gsb_sb_coordinate ( rr_gsb . get_x ( ) , rr_gsb . get_y ( ) ) ;
/* Skip those Switch blocks that do not exist */
if ( false = = rr_gsb . is_sb_exist ( ) ) {
return ;
}
2022-10-06 19:08:50 -05:00
/* If we use compact routing hierarchy, we should find the unique module of
* CB , which is added to the top module */
2020-02-14 11:45:24 -06:00
if ( true = = compact_routing_hierarchy ) {
vtr : : Point < size_t > gsb_coord ( rr_gsb . get_x ( ) , rr_gsb . get_y ( ) ) ;
const RRGSB & unique_mirror = device_rr_gsb . get_sb_unique_module ( gsb_coord ) ;
2022-10-06 19:08:50 -05:00
module_gsb_sb_coordinate . set_x ( unique_mirror . get_x ( ) ) ;
module_gsb_sb_coordinate . set_y ( unique_mirror . get_y ( ) ) ;
}
2020-02-14 11:45:24 -06:00
/* This is the source cb that is added to the top module */
const RRGSB & module_sb = device_rr_gsb . get_gsb ( module_gsb_sb_coordinate ) ;
2022-10-06 19:08:50 -05:00
vtr : : Point < size_t > module_sb_coordinate ( module_sb . get_sb_x ( ) ,
module_sb . get_sb_y ( ) ) ;
std : : string sb_module_name =
generate_switch_block_module_name ( module_sb_coordinate ) ;
2020-02-14 11:45:24 -06:00
ModuleId sb_module_id = module_manager . find_module ( sb_module_name ) ;
VTR_ASSERT ( true = = module_manager . valid_module_id ( sb_module_id ) ) ;
2022-10-06 19:08:50 -05:00
size_t sb_instance =
sb_instance_ids [ instance_sb_coordinate . x ( ) ] [ instance_sb_coordinate . y ( ) ] ;
2020-02-14 11:45:24 -06:00
/* Connect grid output pins (OPIN) to switch block grid pins */
for ( size_t side = 0 ; side < module_sb . get_num_sides ( ) ; + + side ) {
SideManager side_manager ( side ) ;
/* Iterate over the routing tracks on this side */
/* Early skip: if there is no routing tracks at this side */
if ( 0 = = module_sb . get_chan_width ( side_manager . get_side ( ) ) ) {
continue ;
}
/* Find the Connection Block module */
2022-10-06 19:08:50 -05:00
/* We find the original connection block and then spot its unique mirror!
2020-02-14 11:45:24 -06:00
* Do NOT use module_sb here ! ! !
*/
2022-10-06 19:08:50 -05:00
t_rr_type cb_type =
find_top_module_cb_type_by_sb_side ( side_manager . get_side ( ) ) ;
vtr : : Point < size_t > instance_gsb_cb_coordinate =
find_top_module_gsb_coordinate_by_sb_side ( rr_gsb ,
side_manager . get_side ( ) ) ;
vtr : : Point < size_t > module_gsb_cb_coordinate =
find_top_module_gsb_coordinate_by_sb_side ( rr_gsb ,
side_manager . get_side ( ) ) ;
2020-02-14 11:45:24 -06:00
/* Skip those Connection blocks that do not exist:
2022-10-06 19:08:50 -05:00
* 1. The CB does not exist in the device level ! We should skip !
* 2. The CB does exist but we need to make sure if the GSB includes such
* CBs For TOP and LEFT side , check the existence using RRGSB method
* is_cb_exist ( ) FOr RIGHT and BOTTOM side , find the adjacent RRGSB and then
* use is_cb_exist ( )
2020-02-14 11:45:24 -06:00
*/
2022-10-06 19:08:50 -05:00
if ( TOP = = side_manager . get_side ( ) | | LEFT = = side_manager . get_side ( ) ) {
if ( false = = rr_gsb . is_cb_exist ( cb_type ) ) {
2020-02-14 11:45:24 -06:00
continue ;
}
}
2022-10-06 19:08:50 -05:00
if ( RIGHT = = side_manager . get_side ( ) | | BOTTOM = = side_manager . get_side ( ) ) {
const RRGSB & adjacent_gsb =
device_rr_gsb . get_gsb ( module_gsb_cb_coordinate ) ;
if ( false = = adjacent_gsb . is_cb_exist ( cb_type ) ) {
2020-02-14 11:45:24 -06:00
continue ;
}
}
2022-10-06 19:08:50 -05:00
/* If we use compact routing hierarchy, we should find the unique module of
* CB , which is added to the top module */
2020-02-14 11:45:24 -06:00
if ( true = = compact_routing_hierarchy ) {
2022-10-06 19:08:50 -05:00
const RRGSB & unique_mirror =
device_rr_gsb . get_cb_unique_module ( cb_type , module_gsb_cb_coordinate ) ;
module_gsb_cb_coordinate . set_x ( unique_mirror . get_x ( ) ) ;
module_gsb_cb_coordinate . set_y ( unique_mirror . get_y ( ) ) ;
}
2020-02-14 11:45:24 -06:00
const RRGSB & module_cb = device_rr_gsb . get_gsb ( module_gsb_cb_coordinate ) ;
2022-10-06 19:08:50 -05:00
vtr : : Point < size_t > module_cb_coordinate ( module_cb . get_cb_x ( cb_type ) ,
module_cb . get_cb_y ( cb_type ) ) ;
std : : string cb_module_name =
generate_connection_block_module_name ( cb_type , module_cb_coordinate ) ;
2020-02-14 11:45:24 -06:00
ModuleId cb_module_id = module_manager . find_module ( cb_module_name ) ;
VTR_ASSERT ( true = = module_manager . valid_module_id ( cb_module_id ) ) ;
2022-10-06 19:08:50 -05:00
const RRGSB & instance_cb =
device_rr_gsb . get_gsb ( instance_gsb_cb_coordinate ) ;
vtr : : Point < size_t > instance_cb_coordinate ( instance_cb . get_cb_x ( cb_type ) ,
instance_cb . get_cb_y ( cb_type ) ) ;
size_t cb_instance = cb_instance_ids . at (
cb_type ) [ instance_cb_coordinate . x ( ) ] [ instance_cb_coordinate . y ( ) ] ;
for ( size_t itrack = 0 ;
itrack < module_sb . get_chan_width ( side_manager . get_side ( ) ) ; + + itrack ) {
std : : string sb_port_name = generate_sb_module_track_port_name (
rr_graph . node_type (
module_sb . get_chan_node ( side_manager . get_side ( ) , itrack ) ) ,
side_manager . get_side ( ) ,
module_sb . get_chan_node_direction ( side_manager . get_side ( ) , itrack ) ) ;
2020-02-14 11:45:24 -06:00
/* Prepare SB-related port information */
2022-10-06 19:08:50 -05:00
ModulePortId sb_port_id =
module_manager . find_module_port ( sb_module_id , sb_port_name ) ;
VTR_ASSERT ( true = =
module_manager . valid_module_port_id ( sb_module_id , sb_port_id ) ) ;
2020-02-14 11:45:24 -06:00
BasicPort sb_port = module_manager . module_port ( sb_module_id , sb_port_id ) ;
2022-10-06 19:08:50 -05:00
/* Prepare CB-related port information */
2020-02-14 11:45:24 -06:00
PORTS cb_port_direction = OUT_PORT ;
/* The cb port direction should be opposite to the sb port !!! */
2022-10-06 19:08:50 -05:00
if ( OUT_PORT = =
module_sb . get_chan_node_direction ( side_manager . get_side ( ) , itrack ) ) {
2020-02-14 11:45:24 -06:00
cb_port_direction = IN_PORT ;
} else {
2022-10-06 19:08:50 -05:00
VTR_ASSERT ( IN_PORT = = module_sb . get_chan_node_direction (
side_manager . get_side ( ) , itrack ) ) ;
}
/* Upper CB port is required if the routing tracks are on the top or right
* sides of the switch block , which indicated bottom and left sides of the
* connection blocks
2020-07-01 15:44:40 -05:00
*/
2022-10-06 19:08:50 -05:00
bool use_cb_upper_port =
( TOP = = side_manager . get_side ( ) ) | | ( RIGHT = = side_manager . get_side ( ) ) ;
std : : string cb_port_name = generate_cb_module_track_port_name (
cb_type , cb_port_direction , use_cb_upper_port ) ;
ModulePortId cb_port_id =
module_manager . find_module_port ( cb_module_id , cb_port_name ) ;
VTR_ASSERT ( true = =
module_manager . valid_module_port_id ( cb_module_id , cb_port_id ) ) ;
2020-02-14 11:45:24 -06:00
BasicPort cb_port = module_manager . module_port ( cb_module_id , cb_port_id ) ;
2020-06-30 18:50:53 -05:00
/* Configure the net source and sink:
2022-10-06 19:08:50 -05:00
* If sb port is an output ( source ) , cb port is an input ( sink )
* If sb port is an input ( sink ) , cb port is an output ( source )
2020-06-30 18:50:53 -05:00
*/
2022-10-06 19:08:50 -05:00
if ( OUT_PORT = =
module_sb . get_chan_node_direction ( side_manager . get_side ( ) , itrack ) ) {
ModuleNetId net =
create_module_source_pin_net ( module_manager , top_module , sb_module_id ,
sb_instance , sb_port_id , itrack / 2 ) ;
module_manager . add_module_net_sink ( top_module , net , cb_module_id ,
cb_instance , cb_port_id , itrack / 2 ) ;
2020-06-30 18:50:53 -05:00
} else {
2022-10-06 19:08:50 -05:00
VTR_ASSERT ( IN_PORT = = module_sb . get_chan_node_direction (
side_manager . get_side ( ) , itrack ) ) ;
ModuleNetId net =
create_module_source_pin_net ( module_manager , top_module , cb_module_id ,
cb_instance , cb_port_id , itrack / 2 ) ;
module_manager . add_module_net_sink ( top_module , net , sb_module_id ,
sb_instance , sb_port_id , itrack / 2 ) ;
2020-02-14 11:45:24 -06:00
}
}
}
}
/********************************************************************
* Add module nets to connect the grid ports / pins to Connection Blocks
* and Switch Blocks
* To make it easy , this function will iterate over all the General
* Switch Blocks ( GSBs ) , through which we can obtain the coordinates
2022-10-06 19:08:50 -05:00
* of all the grids , connection blocks and switch blocks that are
2020-02-14 11:45:24 -06:00
* supposed to be connected tightly .
*
* As such , we have completed all the connection for each grid .
* There is no need to iterate over the grids
*
* + - - - - - - - - - - - - - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
* | | | Y - direction CB |
* | Grid [ x ] [ y + 1 ] | | [ x ] [ y + 1 ] |
* | | + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
* + - - - - - - - - - - - - - - - - - - - - - - - - - +
* TOP SIDE
* + - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
* | | | OPIN_NODE CHAN_NODES OPIN_NODES |
* | | | |
* | | | OPIN_NODES OPIN_NODES |
* | X - direction | | |
* | CB | LEFT SIDE | Switch Block | RIGHT SIDE
* | [ x ] [ y ] | | [ x ] [ y ] |
* | | | |
* | | | CHAN_NODES CHAN_NODES |
* | | | |
* | | | OPIN_NODES OPIN_NODES |
* | | | |
* | | | OPIN_NODE CHAN_NODES OPIN_NODES |
* + - - - - - - - - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
* BOTTOM SIDE
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-10-06 19:08:50 -05:00
void add_top_module_nets_connect_grids_and_gsbs (
ModuleManager & module_manager , const ModuleId & top_module ,
const VprDeviceAnnotation & vpr_device_annotation , const DeviceGrid & grids ,
const vtr : : Matrix < size_t > & grid_instance_ids , const RRGraphView & rr_graph ,
const DeviceRRGSB & device_rr_gsb , const vtr : : Matrix < size_t > & sb_instance_ids ,
const std : : map < t_rr_type , vtr : : Matrix < size_t > > & cb_instance_ids ,
const bool & compact_routing_hierarchy , const bool & duplicate_grid_pin ) {
2020-06-30 00:17:03 -05:00
vtr : : ScopedStartFinishTimer timer ( " Add module nets between grids and GSBs " ) ;
2020-02-14 11:45:24 -06:00
vtr : : Point < size_t > gsb_range = device_rr_gsb . get_gsb_range ( ) ;
for ( size_t ix = 0 ; ix < gsb_range . x ( ) ; + + ix ) {
for ( size_t iy = 0 ; iy < gsb_range . y ( ) ; + + iy ) {
vtr : : Point < size_t > gsb_coordinate ( ix , iy ) ;
const RRGSB & rr_gsb = device_rr_gsb . get_gsb ( ix , iy ) ;
2020-03-24 18:39:26 -05:00
2020-02-14 11:45:24 -06:00
/* Connect the grid pins of the GSB to adjacent grids */
if ( false = = duplicate_grid_pin ) {
2022-10-06 19:08:50 -05:00
add_top_module_nets_connect_grids_and_sb (
module_manager , top_module , vpr_device_annotation , grids ,
grid_instance_ids , rr_graph , device_rr_gsb , rr_gsb , sb_instance_ids ,
compact_routing_hierarchy ) ;
2020-02-14 11:45:24 -06:00
} else {
VTR_ASSERT_SAFE ( true = = duplicate_grid_pin ) ;
2022-10-06 19:08:50 -05:00
add_top_module_nets_connect_grids_and_sb_with_duplicated_pins (
module_manager , top_module , vpr_device_annotation , grids ,
grid_instance_ids , rr_graph , device_rr_gsb , rr_gsb , sb_instance_ids ,
compact_routing_hierarchy ) ;
2020-02-14 11:45:24 -06:00
}
2022-10-06 19:08:50 -05:00
add_top_module_nets_connect_grids_and_cb (
module_manager , top_module , vpr_device_annotation , grids ,
grid_instance_ids , rr_graph , device_rr_gsb , rr_gsb , CHANX ,
cb_instance_ids . at ( CHANX ) , compact_routing_hierarchy ) ;
2020-02-14 11:45:24 -06:00
2022-10-06 19:08:50 -05:00
add_top_module_nets_connect_grids_and_cb (
module_manager , top_module , vpr_device_annotation , grids ,
grid_instance_ids , rr_graph , device_rr_gsb , rr_gsb , CHANY ,
cb_instance_ids . at ( CHANY ) , compact_routing_hierarchy ) ;
2020-02-14 11:45:24 -06:00
2022-10-06 19:08:50 -05:00
add_top_module_nets_connect_sb_and_cb (
module_manager , top_module , rr_graph , device_rr_gsb , rr_gsb ,
sb_instance_ids , cb_instance_ids , compact_routing_hierarchy ) ;
2020-02-14 11:45:24 -06:00
}
}
}
2020-11-11 16:09:40 -06:00
/********************************************************************
* Add global port connection for a given port of a physical tile
2022-10-06 19:08:50 -05:00
* that are defined as global in tile annotation
2020-11-11 16:09:40 -06:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-10-06 19:08:50 -05:00
static int build_top_module_global_net_for_given_grid_module (
ModuleManager & module_manager , const ModuleId & top_module ,
const ModulePortId & top_module_port , const TileAnnotation & tile_annotation ,
const TileGlobalPortId & tile_global_port ,
const BasicPort & tile_port_to_connect ,
const VprDeviceAnnotation & vpr_device_annotation , const DeviceGrid & grids ,
const vtr : : Point < size_t > & grid_coordinate , const e_side & border_side ,
const vtr : : Matrix < size_t > & grid_instance_ids ) {
t_physical_tile_type_ptr physical_tile =
grids [ grid_coordinate . x ( ) ] [ grid_coordinate . y ( ) ] . type ;
/* Find the module name for this type of grid */
std : : string grid_module_name_prefix ( GRID_MODULE_NAME_PREFIX ) ;
std : : string grid_module_name = generate_grid_block_module_name (
grid_module_name_prefix , std : : string ( physical_tile - > name ) ,
is_io_type ( physical_tile ) , border_side ) ;
ModuleId grid_module = module_manager . find_module ( grid_module_name ) ;
VTR_ASSERT ( true = = module_manager . valid_module_id ( grid_module ) ) ;
size_t grid_instance =
grid_instance_ids [ grid_coordinate . x ( ) ] [ grid_coordinate . y ( ) ] ;
/* Find the source port at the top-level module */
BasicPort src_port = module_manager . module_port ( top_module , top_module_port ) ;
/* Walk through each instance considering the unique sub tile and capacity
* range , each instance may have an independent pin to be driven by a global
* net ! */
2022-08-17 18:25:12 -05:00
for ( const t_sub_tile & sub_tile : physical_tile - > sub_tiles ) {
2022-08-23 13:58:44 -05:00
VTR_ASSERT ( 1 = = sub_tile . equivalent_sites . size ( ) ) ;
int grid_pin_start_index = physical_tile - > num_pins ;
t_physical_tile_port physical_tile_port ;
physical_tile_port . num_pins = 0 ;
/* Count the total number of pins for this type of sub tile */
2022-08-23 14:35:04 -05:00
int sub_tile_num_pins = sub_tile . num_phy_pins / sub_tile . capacity . total ( ) ;
2022-08-23 13:58:44 -05:00
2022-10-06 19:08:50 -05:00
/* For each instance of the same sub tile type, find the port of the grid
* module according to the tile annotation A tile may consist of multiple
* subtile , connect to all the pins from sub tiles */
for ( int subtile_index = sub_tile . capacity . low ;
subtile_index < = sub_tile . capacity . high ; subtile_index + + ) {
for ( const t_physical_tile_port & tile_port : sub_tile . ports ) {
2022-08-23 13:58:44 -05:00
if ( std : : string ( tile_port . name ) = = tile_port_to_connect . get_name ( ) ) {
BasicPort ref_tile_port ( tile_port . name , tile_port . num_pins ) ;
/* Port size must match!!! */
if ( false = = ref_tile_port . contained ( tile_port_to_connect ) ) {
2022-10-06 19:08:50 -05:00
VTR_LOG_ERROR (
" Tile annotation '%s' port '%s[%lu:%lu]' is out of the range of "
" physical tile port '%s[%lu:%lu]'! " ,
tile_annotation . global_port_name ( tile_global_port ) . c_str ( ) ,
tile_port_to_connect . get_name ( ) . c_str ( ) ,
tile_port_to_connect . get_lsb ( ) , tile_port_to_connect . get_msb ( ) ,
ref_tile_port . get_name ( ) . c_str ( ) , ref_tile_port . get_lsb ( ) ,
ref_tile_port . get_msb ( ) ) ;
2022-08-23 13:58:44 -05:00
return CMD_EXEC_FATAL_ERROR ;
}
2022-10-06 19:08:50 -05:00
grid_pin_start_index =
( subtile_index - sub_tile . capacity . low ) * sub_tile_num_pins +
tile_port . absolute_first_pin_index ;
2022-08-23 13:58:44 -05:00
physical_tile_port = tile_port ;
break ;
2022-08-17 18:25:12 -05:00
}
2021-01-09 19:47:12 -06:00
}
2022-08-23 13:58:44 -05:00
/* Ensure the pin index is valid */
VTR_ASSERT ( grid_pin_start_index < physical_tile - > num_pins ) ;
/* Ensure port width is in range */
VTR_ASSERT ( src_port . get_width ( ) = = tile_port_to_connect . get_width ( ) ) ;
2022-10-06 19:08:50 -05:00
/* Create a pin id mapping between the source port (top module) and the
* sink port ( grid module ) */
2022-08-23 13:58:44 -05:00
std : : map < size_t , size_t > sink2src_pin_map ;
for ( size_t ipin = 0 ; ipin < tile_port_to_connect . get_width ( ) ; + + ipin ) {
size_t sink_pin = tile_port_to_connect . pins ( ) [ ipin ] ;
size_t src_pin = src_port . pins ( ) [ ipin ] ;
sink2src_pin_map [ sink_pin ] = src_pin ;
}
2021-01-12 19:38:00 -06:00
2022-08-23 13:58:44 -05:00
/* Create the connections */
2022-10-06 19:08:50 -05:00
for ( size_t pin_id = tile_port_to_connect . get_lsb ( ) ;
pin_id < tile_port_to_connect . get_msb ( ) + 1 ; + + pin_id ) {
2022-08-23 13:58:44 -05:00
int grid_pin_index = grid_pin_start_index + pin_id ;
2022-08-17 18:25:12 -05:00
/* Find the module pin */
size_t grid_pin_width = physical_tile - > pin_width_offset [ grid_pin_index ] ;
2022-10-06 19:08:50 -05:00
size_t grid_pin_height =
physical_tile - > pin_height_offset [ grid_pin_index ] ;
std : : vector < e_side > pin_sides = find_physical_tile_pin_side (
physical_tile , grid_pin_index , border_side ) ;
BasicPort grid_pin_info =
vpr_device_annotation . physical_tile_pin_port_info ( physical_tile ,
grid_pin_index ) ;
2022-08-17 18:25:12 -05:00
VTR_ASSERT ( true = = grid_pin_info . is_valid ( ) ) ;
/* Build nets */
for ( const e_side & pin_side : pin_sides ) {
2022-10-06 19:08:50 -05:00
std : : string grid_port_name =
generate_grid_port_name ( grid_pin_width , grid_pin_height ,
subtile_index , pin_side , grid_pin_info ) ;
ModulePortId grid_port_id =
module_manager . find_module_port ( grid_module , grid_port_name ) ;
VTR_ASSERT ( true = = module_manager . valid_module_port_id ( grid_module ,
grid_port_id ) ) ;
VTR_ASSERT (
1 = =
module_manager . module_port ( grid_module , grid_port_id ) . get_width ( ) ) ;
ModuleNetId net = create_module_source_pin_net (
module_manager , top_module , top_module , 0 , top_module_port ,
src_port . pins ( ) [ sink2src_pin_map [ pin_id ] ] ) ;
2022-08-17 18:25:12 -05:00
VTR_ASSERT ( ModuleNetId : : INVALID ( ) ! = net ) ;
2022-10-06 19:08:50 -05:00
2022-08-17 18:25:12 -05:00
/* Configure the net sink */
2022-10-06 19:08:50 -05:00
BasicPort sink_port =
module_manager . module_port ( grid_module , grid_port_id ) ;
module_manager . add_module_net_sink ( top_module , net , grid_module ,
grid_instance , grid_port_id ,
sink_port . pins ( ) [ 0 ] ) ;
2022-08-17 18:25:12 -05:00
}
2021-01-10 12:52:38 -06:00
}
2021-01-09 19:47:12 -06:00
}
2020-11-11 16:09:40 -06:00
}
2021-01-09 19:47:12 -06:00
return CMD_EXEC_SUCCESS ;
2020-11-11 16:09:40 -06:00
}
2023-03-01 18:08:15 -06:00
/********************************************************************
* Add nets between a global port and its sinks at each grid modules
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static
int build_top_module_global_net_from_grid_modules (
ModuleManager & module_manager , const ModuleId & top_module , const ModulePortId & top_module_port ,
const TileAnnotation & tile_annotation , const TileGlobalPortId & tile_global_port ,
const VprDeviceAnnotation & vpr_device_annotation , const DeviceGrid & grids ,
const vtr : : Matrix < size_t > & grid_instance_ids ) {
int status = CMD_EXEC_SUCCESS ;
for ( size_t tile_info_id = 0 ;
tile_info_id <
tile_annotation . global_port_tile_names ( tile_global_port ) . size ( ) ;
+ + tile_info_id ) {
std : : string tile_name =
tile_annotation . global_port_tile_names ( tile_global_port ) [ tile_info_id ] ;
BasicPort tile_port =
tile_annotation . global_port_tile_ports ( tile_global_port ) [ tile_info_id ] ;
/* Find the coordinates for the wanted tiles */
vtr : : Point < size_t > start_coord ( 1 , 1 ) ;
vtr : : Point < size_t > end_coord ( grids . width ( ) - 1 , grids . height ( ) - 1 ) ;
vtr : : Point < size_t > range = tile_annotation . global_port_tile_coordinates (
tile_global_port ) [ tile_info_id ] ;
bool out_of_range = false ;
/* -1 means all the x should be considered */
if ( size_t ( - 1 ) ! = range . x ( ) ) {
if ( ( range . x ( ) < start_coord . x ( ) ) | | ( range . x ( ) > end_coord . x ( ) ) ) {
out_of_range = true ;
} else {
/* Set the range */
start_coord . set_x ( range . x ( ) ) ;
end_coord . set_x ( range . x ( ) ) ;
}
}
/* -1 means all the y should be considered */
if ( size_t ( - 1 ) ! = range . y ( ) ) {
if ( ( range . y ( ) < start_coord . y ( ) ) | | ( range . y ( ) > end_coord . y ( ) ) ) {
out_of_range = true ;
} else {
/* Set the range */
start_coord . set_y ( range . y ( ) ) ;
end_coord . set_y ( range . y ( ) ) ;
}
}
/* Error out immediately if the coordinate is not valid! */
if ( true = = out_of_range ) {
VTR_LOG_ERROR (
" Coordinate (%lu, %lu) in tile annotation for tile '%s' is out of "
" range (%lu:%lu, %lu:%lu)! " ,
range . x ( ) , range . y ( ) , tile_name . c_str ( ) , start_coord . x ( ) ,
end_coord . x ( ) , start_coord . y ( ) , end_coord . y ( ) ) ;
return CMD_EXEC_FATAL_ERROR ;
}
/* Spot the port from child modules from core grids */
for ( size_t ix = start_coord . x ( ) ; ix < end_coord . x ( ) ; + + ix ) {
for ( size_t iy = start_coord . y ( ) ; iy < end_coord . y ( ) ; + + iy ) {
/* Bypass EMPTY tiles */
if ( true = = is_empty_type ( grids [ ix ] [ iy ] . type ) ) {
continue ;
}
/* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
if ( ( 0 < grids [ ix ] [ iy ] . width_offset ) | |
( 0 < grids [ ix ] [ iy ] . height_offset ) ) {
continue ;
}
/* Bypass the tiles whose names do not match */
if ( std : : string ( grids [ ix ] [ iy ] . type - > name ) ! = tile_name ) {
continue ;
}
/* Create nets and finish connection build-up */
status = build_top_module_global_net_for_given_grid_module (
module_manager , top_module , top_module_port , tile_annotation ,
tile_global_port , tile_port , vpr_device_annotation , grids ,
vtr : : Point < size_t > ( ix , iy ) , NUM_SIDES , grid_instance_ids ) ;
if ( CMD_EXEC_FATAL_ERROR = = status ) {
return status ;
}
}
}
/* Walk through all the grids on the perimeter, which are I/O grids */
for ( const e_side & io_side : FPGA_SIDES_CLOCKWISE ) {
for ( const vtr : : Point < size_t > & io_coordinate :
io_coordinates [ io_side ] ) {
/* Bypass EMPTY grid */
if ( true = =
is_empty_type ( grids [ io_coordinate . x ( ) ] [ io_coordinate . y ( ) ] . type ) ) {
continue ;
}
/* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
if ( ( 0 < grids [ io_coordinate . x ( ) ] [ io_coordinate . y ( ) ] . width_offset ) | |
( 0 < grids [ io_coordinate . x ( ) ] [ io_coordinate . y ( ) ] . height_offset ) ) {
continue ;
}
/* Bypass the tiles whose names do not match */
if ( std : : string (
grids [ io_coordinate . x ( ) ] [ io_coordinate . y ( ) ] . type - > name ) ! =
tile_name ) {
continue ;
}
/* Check if the coordinate satisfy the tile coordinate defintion
* - Bypass if the x is a specific number ( ! = - 1 ) , and io_coordinate
* is different
* - Bypass if the y is a specific number ( ! = - 1 ) , and io_coordinate
* is different
*/
if ( ( size_t ( - 1 ) ! = range . x ( ) ) & & ( range . x ( ) ! = io_coordinate . x ( ) ) ) {
continue ;
}
if ( ( size_t ( - 1 ) ! = range . y ( ) ) & & ( range . y ( ) ! = io_coordinate . y ( ) ) ) {
continue ;
}
/* Create nets and finish connection build-up */
status = build_top_module_global_net_for_given_grid_module (
module_manager , top_module , top_module_port , tile_annotation ,
tile_global_port , tile_port , vpr_device_annotation , grids ,
io_coordinate , io_side , grid_instance_ids ) ;
if ( CMD_EXEC_FATAL_ERROR = = status ) {
return status ;
}
}
}
}
return status ;
}
/********************************************************************
* Add nets between a global port and its sinks at an entry point of clock tree
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int build_top_module_global_net_from_clock_arch_tree (
ModuleManager & module_manager , const ModuleId & top_module , const ModulePortId & top_module_port ,
const ClockNetwork & clk_ntwk , const std : : string & clk_tree_name , const RRClockSpatialLookup & rr_clock_lookup ) {
int status = CMD_EXEC_SUCCESS ;
/* Ensure the clock arch tree name is valid */
ClockTreeId clk_tree = clk_ntwk . find_tree ( clk_tree_name ) ;
if ( ! clk_ntwk . valid_tree_id ( clk_tree ) ) {
VTR_LOG ( " Fail to find a matched clock tree '%s' in the clock architecture definition " , clk_tree_name . c_str ( ) ) ;
return CMD_EXEC_FATAL_ERROR ;
}
/* Ensure the clock tree width matches the global port size */
if ( clk_ntwk . tree_width ( clk_tree ) ! = module_manager . module_port ( top_module , top_module_port ) . get_width ( ) ) {
VTR_LOG ( " Clock tree '%s' does not have the same width '%lu' as the port '%'s of FPGA top module " , clk_tree_name . c_str ( ) , clk_ntwk . tree_width ( clk_tree ) , module_manager . module_port ( top_module , top_module_port ) . get_name ( ) . c_str ( ) ) ;
return CMD_EXEC_FATAL_ERROR ;
}
for ( ClockTreePinId pin : clk_ntwk . pins ( clk_tree ) ) {
/* TODO: Find the routing resource node of the entry point */
/* TODO: Get the connection block module and instance at the entry point */
/* TODO: Add the module net */
}
return status ;
}
2020-11-10 17:59:00 -06:00
/********************************************************************
2022-10-06 19:08:50 -05:00
* Add global ports from grid ports that are defined as global in tile
* annotation
2020-11-10 17:59:00 -06:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-10-06 19:08:50 -05:00
int add_top_module_global_ports_from_grid_modules (
ModuleManager & module_manager , const ModuleId & top_module ,
const TileAnnotation & tile_annotation ,
const VprDeviceAnnotation & vpr_device_annotation , const DeviceGrid & grids ,
const vtr : : Matrix < size_t > & grid_instance_ids ) {
2021-01-09 19:47:12 -06:00
int status = CMD_EXEC_SUCCESS ;
2020-11-10 17:59:00 -06:00
2022-10-06 19:08:50 -05:00
/* Add the global ports which are NOT yet added to the top-level module
2020-11-10 17:59:00 -06:00
* ( in different names than the global ports defined in circuit library
*/
std : : vector < BasicPort > global_ports_to_add ;
2022-10-06 19:08:50 -05:00
for ( const TileGlobalPortId & tile_global_port :
tile_annotation . global_ports ( ) ) {
ModulePortId module_port = module_manager . find_module_port (
top_module , tile_annotation . global_port_name ( tile_global_port ) ) ;
/* The global port size is derived from the maximum port size among all the
* tile port defintion */
2020-11-10 17:59:00 -06:00
if ( ModulePortId : : INVALID ( ) = = module_port ) {
2022-10-06 19:08:50 -05:00
BasicPort global_port_to_add ;
global_port_to_add . set_name (
tile_annotation . global_port_name ( tile_global_port ) ) ;
2021-01-09 19:47:12 -06:00
size_t max_port_size = 0 ;
2022-10-06 19:08:50 -05:00
for ( const BasicPort & tile_port :
tile_annotation . global_port_tile_ports ( tile_global_port ) ) {
2021-01-09 19:47:12 -06:00
max_port_size = std : : max ( tile_port . get_width ( ) , max_port_size ) ;
}
global_port_to_add . set_width ( max_port_size ) ;
2020-11-10 17:59:00 -06:00
global_ports_to_add . push_back ( global_port_to_add ) ;
}
}
for ( const BasicPort & global_port_to_add : global_ports_to_add ) {
2022-10-06 19:08:50 -05:00
module_manager . add_port ( top_module , global_port_to_add ,
ModuleManager : : MODULE_GLOBAL_PORT ) ;
2020-11-10 17:59:00 -06:00
}
/* Add module nets */
2022-10-06 19:08:50 -05:00
std : : map < e_side , std : : vector < vtr : : Point < size_t > > > io_coordinates =
generate_perimeter_grid_coordinates ( grids ) ;
2020-11-11 16:09:40 -06:00
2022-10-06 19:08:50 -05:00
for ( const TileGlobalPortId & tile_global_port :
tile_annotation . global_ports ( ) ) {
2020-11-10 17:59:00 -06:00
/* Must found one valid port! */
2022-10-06 19:08:50 -05:00
ModulePortId top_module_port = module_manager . find_module_port (
top_module , tile_annotation . global_port_name ( tile_global_port ) ) ;
2020-11-10 21:31:14 -06:00
VTR_ASSERT ( ModulePortId : : INVALID ( ) ! = top_module_port ) ;
2020-11-11 16:09:40 -06:00
2023-03-01 18:08:15 -06:00
/* There are two cases when building the nets:
* - If the net will go through a dedicated clock tree network , the net will drive an input of a routing block
* - If the net will be directly wired to tiles , the net will drive an input of a tile
*/
if ( ! tile_annotation . global_port_clock_arch_tree_name ( tile_global_port ) . empty ( ) ) {
status = build_top_module_global_net_from_clock_arch_tree ( module_manager , top_module , top_module_port ) ;
} else {
status = build_top_module_global_net_from_grid_modules ( module_manager , top_module , top_module_port , tile_annotation , tile_global_port , vpr_device_annotation , grids , grid_instance_ids ) ;
}
if ( status = = CMD_EXEC_FATAL_ERROR ) {
return status ;
2020-11-10 17:59:00 -06:00
}
}
2021-01-09 19:47:12 -06:00
return status ;
2020-11-10 17:59:00 -06:00
}
2020-02-14 11:45:24 -06:00
} /* end namespace openfpga */