diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp index 40d99b7e6..3e1e14c57 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.cpp @@ -669,6 +669,23 @@ std::string generate_mux_sram_port_name(const CircuitLibrary& circuit_lib, return generate_local_sram_port_name(prefix, mux_instance_id, port_type); } +/********************************************************************* + * Generate the prefix for naming a grid block netlist or a grid module + * This function will consider the io side and add it to the prefix + **********************************************************************/ +std::string generate_grid_block_prefix(const std::string& prefix, + const e_side& io_side) { + std::string block_prefix(prefix); + + if (NUM_SIDES != io_side) { + Side side_manager(io_side); + block_prefix += std::string("_"); + block_prefix += std::string(side_manager.to_string()); + } + + return block_prefix; +} + /********************************************************************* * Generate the netlist name of a grid block **********************************************************************/ @@ -680,9 +697,7 @@ std::string generate_grid_block_netlist_name(const std::string& block_name, std::string module_name(block_name); if (true == is_block_io) { - Side side_manager(io_side); - module_name += std::string("_"); - module_name += std::string(side_manager.to_string()); + module_name = generate_grid_block_prefix(block_name, io_side); } module_name += postfix; @@ -704,6 +719,7 @@ std::string generate_grid_block_module_name(const std::string& prefix, return module_name; } + /********************************************************************* * Generate the module name of a physical block * To ensure a unique name for each physical block inside the graph of complex blocks @@ -758,6 +774,65 @@ std::string generate_physical_block_module_name(const std::string& prefix, return module_name; } +/********************************************************************* + * This function is a wrapper for the function generate_physical_block_module_name() + * which can automatically decode the io_side and add a prefix + **********************************************************************/ +std::string generate_grid_physical_block_module_name(const std::string& prefix, + t_pb_type* pb_type, + const e_side& border_side) { + std::string module_name_prefix = generate_grid_block_prefix(prefix, border_side); + return generate_physical_block_module_name(module_name_prefix, pb_type); +} + +/******************************************************************** + * This function try to infer if a grid locates at the border of a + * FPGA fabric, i.e., TOP/RIGHT/BOTTOM/LEFT sides + * 1. if this grid is on the border, it will return the side it locates, + * 2. if this grid is in the center, it will return an valid value NUM_SIDES + * + * In this function, we assume that the corner grids are actually empty! + * + * +-------+ +----------------------------+ +-------+ + * | EMPTY | | TOP side I/O | | EMPTY | + * +-------+ +----------------------------+ +-------+ + * + * +-------+ +----------------------------+ +-------+ + * | | | | | | + * | | | | | | + * | | | | | | + * | LEFT | | | | RIGHT | + * | side | | Core grids | | side | + * | I/O | | | | I/O | + * | | | | | | + * | | | | | | + * | | | | | | + * | | | | | | + * +-------+ +----------------------------+ +-------+ + * + * +-------+ +----------------------------+ +-------+ + * | EMPTY | | BOTTOM side I/O | | EMPTY | + * +-------+ +----------------------------+ +-------+ + *******************************************************************/ +e_side find_grid_border_side(const vtr::Point& device_size, + const vtr::Point& grid_coordinate) { + e_side grid_side = NUM_SIDES; + + if (device_size.y() - 1 == grid_coordinate.y()) { + return TOP; + } + if (device_size.x() - 1 == grid_coordinate.x()) { + return RIGHT; + } + if (0 == grid_coordinate.y()) { + return BOTTOM; + } + if (0 == grid_coordinate.x()) { + return LEFT; + } + + return grid_side; +} /********************************************************************* * Generate the port name of a Verilog module describing a pb_type diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h index 33bad6e40..b40a6e095 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_naming.h @@ -128,6 +128,9 @@ std::string generate_mux_sram_port_name(const CircuitLibrary& circuit_lib, const size_t& mux_instance_id, const e_spice_model_port_type& port_type); +std::string generate_grid_block_prefix(const std::string& prefix, + const e_side& io_side); + std::string generate_grid_block_netlist_name(const std::string& block_name, const bool& is_block_io, const e_side& io_side, @@ -141,6 +144,13 @@ std::string generate_grid_block_module_name(const std::string& prefix, std::string generate_physical_block_module_name(const std::string& prefix, t_pb_type* physical_pb_type); +std::string generate_grid_physical_block_module_name(const std::string& prefix, + t_pb_type* pb_type, + const e_side& border_side); + +e_side find_grid_border_side(const vtr::Point& device_size, + const vtr::Point& grid_coordinate); + std::string generate_pb_type_port_name(t_port* pb_type_port); std::string generate_fpga_global_io_port_name(const std::string& prefix, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_pbtypes_utils.c b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_pbtypes_utils.c index a202513eb..45844dd75 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_pbtypes_utils.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_pbtypes_utils.c @@ -2136,6 +2136,27 @@ t_pb* get_hardlogic_child_pb(t_pb* cur_hardlogic_pb, return (&(cur_hardlogic_pb->child_pbs[0][0])); } +/******************************************************************** + * Find the height of a pin in a grid definition + *******************************************************************/ +size_t find_grid_pin_height(const std::vector>& grids, + const vtr::Point& grid_coordinate, + const size_t& pin_index) { + t_type_ptr grid_type = grids[grid_coordinate.x()][grid_coordinate.y()].type; + + /* Return if this is an empty type */ + if ( (NULL == grid_type) + || (EMPTY_TYPE == grid_type)) { + return size_t(-1); + } + + /* Check if the pin index is in the range */ + VTR_ASSERT(pin_index < size_t(grid_type->num_pins)); + + /* Find the pin_height */ + return grid_type->pin_height[pin_index]; +} + int get_grid_pin_height(int grid_x, int grid_y, int pin_index) { int pin_height; t_type_ptr grid_type = NULL; diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_pbtypes_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_pbtypes_utils.h index 954984e89..19c1e72f7 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_pbtypes_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/fpga_x2p_pbtypes_utils.h @@ -4,7 +4,9 @@ /* Only include header files those are required by the data types in the following function declaration */ #include #include +#include "vtr_geometry.h" #include "device_port.h" +#include "vpr_types.h" #include "circuit_library.h" #include "fpga_x2p_types.h" #include "fpga_x2p_bitstream_utils.h" @@ -165,6 +167,10 @@ t_phy_pb* get_lut_child_phy_pb(t_phy_pb* cur_lut_pb, t_pb* get_hardlogic_child_pb(t_pb* cur_hardlogic_pb, int mode_index); +size_t find_grid_pin_height(const std::vector>& grids, + const vtr::Point& grid_coordinate, + const size_t& pin_index); + int get_grid_pin_height(int grid_x, int grid_y, int pin_index); int get_grid_pin_side(int grid_x, int grid_y, int pin_index); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_grid.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_grid.cpp index 0e736121d..4d377a115 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_grid.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_grid.cpp @@ -70,10 +70,7 @@ void add_grid_module_pb_type_ports(ModuleManager& module_manager, 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); + grid_pin_sides = {TOP, RIGHT, BOTTOM, LEFT}; } /* Create a map between pin class type and grid pin direction */ @@ -286,13 +283,7 @@ void print_verilog_primitive_block(std::fstream& fp, CircuitModelId& primitive_model = primitive_pb_graph_node->pb_type->circuit_model; /* Generate the module name for this primitive pb_graph_node*/ - std::string primitive_module_name_prefix(grid_verilog_file_name_prefix); - /* Add side string to the name if it is valid, this is mainly for I/O block */ - if (NUM_SIDES != io_side) { - Side side_manager(io_side); - primitive_module_name_prefix += std::string(side_manager.to_string()); - primitive_module_name_prefix += std::string("_"); - } + std::string primitive_module_name_prefix = generate_grid_block_prefix(std::string(grid_verilog_file_name_prefix), io_side); std::string primitive_module_name = generate_physical_block_module_name(primitive_module_name_prefix, primitive_pb_graph_node->pb_type); /* Create a module of the primitive LUT and register it to module manager */ @@ -901,13 +892,7 @@ void print_verilog_physical_blocks_rec(std::fstream& fp, } /* Generate the name of the Verilog module for this pb_type */ - std::string pb_module_name_prefix(grid_verilog_file_name_prefix); - /* Add side string to the name if it is valid */ - if (NUM_SIDES != io_side) { - Side side_manager(io_side); - pb_module_name_prefix += std::string(side_manager.to_string()); - pb_module_name_prefix += std::string("_"); - } + std::string pb_module_name_prefix = generate_grid_block_prefix(std::string(grid_verilog_file_name_prefix), io_side); std::string pb_module_name = generate_physical_block_module_name(pb_module_name_prefix, physical_pb_type); /* Register the Verilog module in module manager */ @@ -1096,7 +1081,7 @@ void print_verilog_grid(ModuleManager& module_manager, print_verilog_comment(fp, std::string("---- END Sub-module of physical block:" + std::string(phy_block_type->name) + " ----")); /* Create a Verilog Module for the top-level physical block, and add to module manager */ - std::string grid_module_name = generate_grid_block_module_name(std::string(grid_verilog_file_name_prefix), phy_block_type->name, IO_TYPE == phy_block_type, border_side); + std::string grid_module_name = generate_grid_block_module_name(std::string(grid_verilog_file_name_prefix), std::string(phy_block_type->name), IO_TYPE == phy_block_type, border_side); ModuleId grid_module = module_manager.add_module(grid_module_name); VTR_ASSERT(true == module_manager.valid_module_id(grid_module)); @@ -1114,13 +1099,7 @@ void print_verilog_grid(ModuleManager& module_manager, /* Generate the name of the Verilog module for this pb_type */ std::string pb_module_name_prefix(grid_verilog_file_name_prefix); - /* Add side string to the name if it is valid */ - if (NUM_SIDES != border_side) { - Side side_manager(border_side); - pb_module_name_prefix += std::string(side_manager.to_string()); - pb_module_name_prefix += std::string("_"); - } - std::string pb_module_name = generate_physical_block_module_name(pb_module_name_prefix, phy_block_type->pb_graph_head->pb_type); + std::string pb_module_name = generate_grid_physical_block_module_name(pb_module_name_prefix, phy_block_type->pb_graph_head->pb_type, border_side); ModuleId pb_module = module_manager.find_module(pb_module_name); VTR_ASSERT(true == module_manager.valid_module_id(pb_module)); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c index 8c92880d6..13dc670f0 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.c @@ -5186,6 +5186,11 @@ void dump_verilog_routing_connection_box_subckt(t_sram_orgz_info* cur_sram_orgz_ /********************************************************************* * Generate the port name for a Grid + * This is a wrapper function for generate_port_name() + * which can automatically decode the port name by the pin side and height + * + * TODO: This function is dependent on the global variable: grid + * This should be replaced by a local variable!!! *********************************************************************/ std::string generate_grid_side_port_name(const vtr::Point& coordinate, const e_side& side, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.h b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.h index 1e12d0b45..8cb8b8ecf 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_routing.h @@ -7,6 +7,7 @@ /* Include other header files which are dependency on the function declared below */ #include "mux_library.h" #include "module_manager.h" +#include "rr_blocks.h" void dump_verilog_routing_chan_subckt(t_sram_orgz_info* cur_sram_orgz_info, char* verilog_dir, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_module.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_module.cpp index 60f347048..d9091e9f1 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_module.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/verilog/verilog_top_module.cpp @@ -12,35 +12,56 @@ #include "fpga_x2p_naming.h" #include "fpga_x2p_utils.h" +#include "fpga_x2p_pbtypes_utils.h" #include "module_manager_utils.h" #include "verilog_global.h" +#include "verilog_routing.h" #include "verilog_writer_utils.h" #include "verilog_module_writer.h" #include "verilog_top_module.h" +/******************************************************************** + * Generate the name for a grid block, by considering + * 1. if it locates on the border with given device size + * 2. its type + * + * This function is mainly used in the top-level module generation + *******************************************************************/ +static +std::string generate_grid_block_module_name_in_top_module(const std::string& prefix, + const vtr::Point& device_size, + const std::vector>& grids, + const vtr::Point& grid_coordinate) { + /* Determine if the grid locates at the border */ + e_side border_side = find_grid_border_side(device_size, grid_coordinate); + + return generate_grid_block_module_name(prefix, std::string(grids[grid_coordinate.x()][grid_coordinate.y()].type->name), + IO_TYPE == grids[grid_coordinate.x()][grid_coordinate.y()].type, border_side); +} + /******************************************************************** * Add a instance of a grid module to the top module *******************************************************************/ static -void add_top_module_grid_instance(ModuleManager& module_manager, - const ModuleId& top_module, - t_type_ptr grid_type, - const e_side& border_side) { +size_t add_top_module_grid_instance(ModuleManager& module_manager, + const ModuleId& top_module, + t_type_ptr grid_type, + const e_side& border_side) { /* Find the module name for this type of grid */ std::string grid_module_name_prefix(grid_verilog_file_name_prefix); - /* Add side string to the name if it is valid */ - if (NUM_SIDES != border_side) { - Side side_manager(border_side); - grid_module_name_prefix += std::string(side_manager.to_string()); - grid_module_name_prefix += std::string("_"); - } - std::string grid_module_name = generate_physical_block_module_name(grid_module_name_prefix, grid_type->pb_graph_head->pb_type); + std::string grid_module_name = generate_grid_block_module_name(grid_module_name_prefix, std::string(grid_type->name), IO_TYPE == grid_type, border_side); ModuleId grid_module = module_manager.find_module(grid_module_name); VTR_ASSERT(true == module_manager.valid_module_id(grid_module)); + /* Record the instance id */ + size_t grid_instance = module_manager.num_instance(top_module, grid_module); /* Add the module to top_module */ module_manager.add_child_module(top_module, grid_module); + + printf("Added grid module %s to top-level module\n", grid_module_name.c_str()); + + return grid_instance; } /******************************************************************** @@ -50,8 +71,12 @@ void add_top_module_grid_instance(ModuleManager& module_manager, * Here, we will iterate over the full fabric (coordinates) * and instanciate the grid modules * + * Return an 2-D array of instance ids of the grid modules that + * have been added + * * This function assumes an island-style floorplanning for FPGA fabric * + * * +-----------------------------------+ * | I/O grids | * | TOP side | @@ -71,10 +96,18 @@ void add_top_module_grid_instance(ModuleManager& module_manager, * *******************************************************************/ static -void add_top_module_grid_instances(ModuleManager& module_manager, - const ModuleId& top_module, - const vtr::Point& device_size, - const std::vector>& grids) { +std::vector> add_top_module_grid_instances(ModuleManager& module_manager, + const ModuleId& top_module, + const vtr::Point& device_size, + const std::vector>& grids) { + /* Reserve an array for the instance ids */ + std::vector> grid_instance_ids; + grid_instance_ids.resize(grids.size()); + for (size_t x = 0; x < grids.size(); ++x) { + /* Deposite an invalid value */ + grid_instance_ids[x].resize(grids[x].size(), size_t(-1)); + } + /* Instanciate core grids */ for (size_t ix = 1; ix < device_size.x() - 1; ++ix) { for (size_t iy = 1; iy < device_size.y() - 1; ++iy) { @@ -89,9 +122,9 @@ void add_top_module_grid_instances(ModuleManager& module_manager, /* We should not meet any I/O grid */ VTR_ASSERT(IO_TYPE != grids[ix][iy].type); /* Add a grid module to top_module*/ - add_top_module_grid_instance(module_manager, top_module, - grids[ix][iy].type, - NUM_SIDES); + grid_instance_ids[ix][iy] = add_top_module_grid_instance(module_manager, top_module, + grids[ix][iy].type, + NUM_SIDES); } } @@ -134,22 +167,33 @@ void add_top_module_grid_instances(ModuleManager& module_manager, /* We should not meet any I/O grid */ VTR_ASSERT(IO_TYPE == grids[io_coordinate.x()][io_coordinate.y()].type); /* Add a grid module to top_module*/ - add_top_module_grid_instance(module_manager, top_module, - grids[io_coordinate.x()][io_coordinate.y()].type, - io_side); + grid_instance_ids[io_coordinate.x()][io_coordinate.y()] = add_top_module_grid_instance(module_manager, top_module, grids[io_coordinate.x()][io_coordinate.y()].type, io_side); } } + + return grid_instance_ids; } /******************************************************************** * Add switch blocks across the FPGA fabric to the top-level module + * Return an 2-D array of instance ids of the switch blocks that + * have been added *******************************************************************/ static -void add_top_module_switch_block_instances(ModuleManager& module_manager, - const ModuleId& top_module, - const DeviceRRGSB& L_device_rr_gsb, - const bool& compact_routing_hierarchy) { +std::vector> add_top_module_switch_block_instances(ModuleManager& module_manager, + const ModuleId& top_module, + const DeviceRRGSB& L_device_rr_gsb, + const bool& compact_routing_hierarchy) { DeviceCoordinator sb_range = L_device_rr_gsb.get_gsb_range(); + + /* Reserve an array for the instance ids */ + std::vector> sb_instance_ids; + sb_instance_ids.resize(sb_range.get_x()); + for (size_t x = 0; x < sb_range.get_x(); ++x) { + /* Deposite an invalid value */ + sb_instance_ids[x].resize(sb_range.get_y(), size_t(-1)); + } + for (size_t ix = 0; ix < sb_range.get_x(); ++ix) { for (size_t iy = 0; iy < sb_range.get_y(); ++iy) { vtr::Point sb_coordinate(ix, iy); @@ -163,22 +207,35 @@ void add_top_module_switch_block_instances(ModuleManager& module_manager, std::string sb_module_name = generate_switch_block_module_name(sb_coordinate); ModuleId sb_module = module_manager.find_module(sb_module_name); VTR_ASSERT(true == module_manager.valid_module_id(sb_module)); + /* Record the instance id */ + sb_instance_ids[ix][iy] = module_manager.num_instance(top_module, sb_module); /* Add the module to top_module */ module_manager.add_child_module(top_module, sb_module); } } + + return sb_instance_ids; } /******************************************************************** * Add switch blocks across the FPGA fabric to the top-level module *******************************************************************/ static -void add_top_module_connection_block_instances(ModuleManager& module_manager, - const ModuleId& top_module, - const DeviceRRGSB& L_device_rr_gsb, - const t_rr_type& cb_type, - const bool& compact_routing_hierarchy) { +std::vector> add_top_module_connection_block_instances(ModuleManager& module_manager, + const ModuleId& top_module, + const DeviceRRGSB& L_device_rr_gsb, + const t_rr_type& cb_type, + const bool& compact_routing_hierarchy) { DeviceCoordinator cb_range = L_device_rr_gsb.get_gsb_range(); + + /* Reserve an array for the instance ids */ + std::vector> cb_instance_ids; + cb_instance_ids.resize(cb_range.get_x()); + for (size_t x = 0; x < cb_range.get_x(); ++x) { + /* Deposite an invalid value */ + cb_instance_ids[x].resize(cb_range.get_y(), size_t(-1)); + } + for (size_t ix = 0; ix < cb_range.get_x(); ++ix) { for (size_t iy = 0; iy < cb_range.get_y(); ++iy) { vtr::Point cb_coordinate(ix, iy); @@ -202,10 +259,254 @@ void add_top_module_connection_block_instances(ModuleManager& module_manager, std::string cb_module_name = generate_connection_block_module_name(cb_type, cb_coordinate); ModuleId cb_module = module_manager.find_module(cb_module_name); VTR_ASSERT(true == module_manager.valid_module_id(cb_module)); + /* Record the instance id */ + cb_instance_ids[ix][iy] = module_manager.num_instance(top_module, cb_module); /* Add the module to top_module */ module_manager.add_child_module(top_module, cb_module); } } + + return cb_instance_ids; +} + +/******************************************************************** + * Add module nets to connect a GSB to adjacent grid ports/pins + * 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 + * + * +------------+ +------------+ + * | | | | + * | Grid | | Grid | + * | [x][y+1] | | [x+1][y+1] | + * | | | | + * +------------+ +------------+ + * | | + * | +------------+ | + * +------>| |<-----+ + * | Switch | + * | Block | + * +------>| [x][y] |<-----+ + * | +------------+ | + * | | + * | | + * +------------+ +------------+ + * | | | | + * | Grid | | Grid | + * | [x][y] | | [x+1][y] | + * | | | | + * +------------+ +------------+ + * + *******************************************************************/ +static +void add_top_module_nets_connect_grids_and_sb(ModuleManager& module_manager, + const ModuleId& top_module, + const vtr::Point& device_size, + const std::vector>& grids, + const std::vector>& grid_instance_ids, + const RRGSB& rr_gsb, + const std::vector>& sb_instance_ids) { + vtr::Point sb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y()); + /* Connect grid output pins (OPIN) to switch block grid pins */ + for (size_t side = 0; side < rr_gsb.get_num_sides(); ++side) { + Side side_manager(side); + for (size_t inode = 0; inode < rr_gsb.get_num_opin_nodes(side_manager.get_side()); ++inode) { + /* Collect source-related information */ + /* Generate the grid module name by considering if it locates on the border */ + vtr::Point grid_coordinate(rr_gsb.get_opin_node(side_manager.get_side(), inode)->xlow, (rr_gsb.get_opin_node(side_manager.get_side(), inode)->ylow)); + std::string src_grid_module_name = generate_grid_block_module_name_in_top_module(std::string(grid_verilog_file_name_prefix), device_size, grids, grid_coordinate); + ModuleId src_grid_module = module_manager.find_module(src_grid_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(src_grid_module)); + size_t src_grid_instance = grid_instance_ids[grid_coordinate.x()][grid_coordinate.y()]; + size_t src_grid_pin_index = rr_gsb.get_opin_node(side_manager.get_side(), inode)->ptc_num; + size_t src_grid_pin_height = find_grid_pin_height(grids, grid_coordinate, src_grid_pin_index); + std::string src_grid_port_name = generate_grid_port_name(grid_coordinate, src_grid_pin_height, rr_gsb.get_opin_node_grid_side(side_manager.get_side(), inode), src_grid_pin_index, false); + 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); + + /* Collect sink-related information */ + std::string sink_sb_module_name = generate_switch_block_module_name(sb_coordinate); + ModuleId sink_sb_module = module_manager.find_module(sink_sb_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(sink_sb_module)); + size_t sink_sb_instance = sb_instance_ids[sb_coordinate.x()][sb_coordinate.y()]; + vtr::Point sink_sb_port_coord(rr_gsb.get_opin_node(side_manager.get_side(), inode)->xlow, + rr_gsb.get_opin_node(side_manager.get_side(), inode)->ylow); + std::string sink_sb_port_name = generate_grid_side_port_name(sink_sb_port_coord, + rr_gsb.get_opin_node_grid_side(side_manager.get_side(), inode), + src_grid_pin_index); + 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); + + /* Source and sink port should match in size */ + VTR_ASSERT(src_grid_port.get_width() == sink_sb_port.get_width()); + + /* Create a net for each pin */ + for (size_t pin_id = 0; pin_id < src_grid_port.pins().size(); ++pin_id) { + ModuleNetId net = module_manager.create_module_net(top_module); + /* Configure the net source */ + printf("src_grid_module_name: %s[%lu][%lu], src_grid_instance_id: %lu (%lu)\n", + src_grid_module_name.c_str(), + grid_coordinate.x(),grid_coordinate.y(), + src_grid_instance, module_manager.num_instance(top_module, src_grid_module)); + module_manager.add_module_net_source(top_module, net, src_grid_module, src_grid_instance, src_grid_port_id, src_grid_port.pins()[pin_id]); + /* Configure the net sink */ + 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]); + } + } + } +} + +/******************************************************************** + * TODO: This function will create nets for the connections + * between grid input pins and connection blocks + * In this case, the net source is the connection block pin, + * while the net sink is the grid input + * + * +------------+ +------------------+ +------------+ + * | | | | | | + * | Grid |<-----| Connection Block |----->| Grid | + * | [x][y+1] | | Y-direction | | [x+1][y+1] | + * | | | [x][y+1] | | | + * +------------+ +------------------+ +------------+ + * ^ + * | + * +------------+ +------------------+ + * | Connection | | | + * | Block | | Switch Block | + * | X-direction| | [x][y] | + * | [x][y] | | | + * +------------+ +------------------+ + * | + * v + * +------------+ + * | | + * | Grid | + * | [x][y] | + * | | + * +------------+ + * + *******************************************************************/ +static +void add_top_module_nets_connect_grids_and_cb(ModuleManager& module_manager, + const ModuleId& top_module, + const vtr::Point& device_size, + const std::vector>& grids, + const std::vector>& grid_instance_ids, + const RRGSB& rr_gsb, + const std::vector>& cbx_instance_ids, + const std::vector>& cby_instance_ids) { +} + +/******************************************************************** + * TODO: 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 + * The net source is an output of routing track of switch block + * while the net sink is an input of a routing track of connection block + * + * +------------+ +------------------+ +------------+ + * | | | | | | + * | Grid | | Connection Block | | Grid | + * | [x][y+1] | | Y-direction | | [x+1][y+1] | + * | | | [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 | + * | [x][y] | | Y-direction | + * | | | [x][y] | + * +------------+ +------------------+ + + *******************************************************************/ +static +void add_top_module_nets_connect_sb_and_cb(ModuleManager& module_manager, + const ModuleId& top_module, + const RRGSB& rr_gsb, + const std::vector>& sb_instance_ids, + const std::vector>& cbx_instance_ids, + const std::vector>& cby_instance_ids) { +} + + +/******************************************************************** + * 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 + * of all the grids, connection blocks and switch blocks that are + * 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 + *******************************************************************/ +static +void add_top_module_nets_connect_grids_and_gsbs(ModuleManager& module_manager, + const ModuleId& top_module, + const vtr::Point& device_size, + const std::vector>& grids, + const std::vector>& grid_instance_ids, + const DeviceRRGSB& L_device_rr_gsb, + const std::vector>& sb_instance_ids, + const std::vector>& cbx_instance_ids, + const std::vector>& cby_instance_ids) { + DeviceCoordinator gsb_range = L_device_rr_gsb.get_gsb_range(); + for (size_t ix = 0; ix < gsb_range.get_x(); ++ix) { + for (size_t iy = 0; iy < gsb_range.get_y(); ++iy) { + vtr::Point gsb_coordinate(ix, iy); + const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(ix, iy); + /* Connect the grid pins of the GSB to adjacent grids */ + add_top_module_nets_connect_grids_and_sb(module_manager, top_module, + device_size, grids, grid_instance_ids, + rr_gsb, sb_instance_ids); + + add_top_module_nets_connect_grids_and_cb(module_manager, top_module, + device_size, grids, grid_instance_ids, + rr_gsb, cbx_instance_ids, cby_instance_ids); + + add_top_module_nets_connect_sb_and_cb(module_manager, top_module, + rr_gsb, sb_instance_ids, cbx_instance_ids, cby_instance_ids); + } + } } /******************************************************************** @@ -235,33 +536,36 @@ void print_verilog_top_module(ModuleManager& module_manager, /* Add sub modules, which are grid, SB and CBX/CBY modules as instances */ /* Add all the grids across the fabric */ - add_top_module_grid_instances(module_manager, top_module, device_size, grids); + std::vector> grid_instance_ids = add_top_module_grid_instances(module_manager, top_module, device_size, grids); /* Add all the SBs across the fabric */ - add_top_module_switch_block_instances(module_manager, top_module, L_device_rr_gsb, compact_routing_hierarchy); + std::vector> sb_instance_ids = add_top_module_switch_block_instances(module_manager, top_module, L_device_rr_gsb, compact_routing_hierarchy); /* Add all the CBX and CBYs across the fabric */ - add_top_module_connection_block_instances(module_manager, top_module, L_device_rr_gsb, CHANX, compact_routing_hierarchy); - add_top_module_connection_block_instances(module_manager, top_module, L_device_rr_gsb, CHANY, compact_routing_hierarchy); + std::vector> cbx_instance_ids = add_top_module_connection_block_instances(module_manager, top_module, L_device_rr_gsb, CHANX, compact_routing_hierarchy); + std::vector> cby_instance_ids = add_top_module_connection_block_instances(module_manager, top_module, L_device_rr_gsb, CHANY, compact_routing_hierarchy); /* TODO: Add module nets to connect the sub modules */ + add_top_module_nets_connect_grids_and_gsbs(module_manager, top_module, + device_size, grids, grid_instance_ids, + L_device_rr_gsb, sb_instance_ids, cbx_instance_ids, cby_instance_ids); /* TODO: Add inter-CLB direct connections */ - /* TODO: Add global ports to the top-level module */ + /* TODO: Add ports to the top-level module */ /* TODO: Add module nets to connect the top-level ports to sub modules */ - /* TODO: Add global ports to the pb_module: + /* Add global ports to the pb_module: * This is a much easier job after adding sub modules (instances), * we just need to find all the global ports from the child modules and build a list of it */ add_module_global_ports_from_child_modules(module_manager, top_module); - /* TODO: Count GPIO ports from the sub-modules under this Verilog module + /* Add GPIO ports from the sub-modules under this Verilog module * This is a much easier job after adding sub modules (instances), * we just need to find all the I/O ports from the child modules and build a list of it */ add_module_gpio_ports_from_child_modules(module_manager, top_module); - /* TODO: Count shared SRAM ports from the sub-modules under this Verilog module + /* Add shared SRAM ports from the sub-modules under this Verilog module * This is a much easier job after adding sub modules (instances), * we just need to find all the I/O ports from the child modules and build a list of it */ @@ -276,7 +580,7 @@ void print_verilog_top_module(ModuleManager& module_manager, CircuitModelId sram_model = circuit_lib.model(mem_model->name); VTR_ASSERT(CircuitModelId::INVALID() != sram_model); - /* TODO: Count SRAM ports from the sub-modules under this Verilog module + /* Add SRAM ports from the sub-modules under this Verilog module * This is a much easier job after adding sub modules (instances), * we just need to find all the I/O ports from the child modules and build a list of it */