diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/build_top_module_directs.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/build_top_module_directs.cpp new file mode 100644 index 000000000..536ab15c8 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/build_top_module_directs.cpp @@ -0,0 +1,563 @@ +/******************************************************************** + * This file includes functions that are used to add module nets + * for direct connections between CLBs/heterogeneous blocks + * in the top-level module of a FPGA fabric + *******************************************************************/ +#include + +#include "vtr_assert.h" +#include "util.h" +#include "device_port.h" + +#include "fpga_x2p_naming.h" +#include "fpga_x2p_pbtypes_utils.h" +#include "module_manager_utils.h" + +#include "globals.h" +#include "verilog_global.h" + +#include "build_top_module_directs.h" + +/******************************************************************** + * Check if the grid coorindate given is in the device grid range + *******************************************************************/ +static +bool is_grid_coordinate_exist_in_device(const vtr::Point& device_size, + const vtr::Point& grid_coordinate) { + return (grid_coordinate < device_size); +} + +/******************************************************************** + * Add module net for one direction connection between two CLBs or + * two grids + * This function will + * 1. find the pin id and port id of the source clb port in module manager + * 2. find the pin id and port id of the destination clb port in module manager + * 3. add a direct connection module to the top module + * 4. add a first module net and configure its source and sink, + * in order to connect the source pin to the input of the top module + * 4. add a second module net and configure its source and sink, + * in order to connect the sink pin to the output of the top module + *******************************************************************/ +static +void add_module_nets_clb2clb_direct_connection(ModuleManager& module_manager, + const ModuleId& top_module, + const CircuitLibrary& circuit_lib, + const vtr::Point& device_size, + const std::vector>& grids, + const std::vector>& grid_instance_ids, + const vtr::Point& src_clb_coord, + const vtr::Point& des_clb_coord, + const t_clb_to_clb_directs& direct) { + /* Find the source port and destination port on the CLBs */ + BasicPort src_clb_port; + BasicPort des_clb_port; + + src_clb_port.set_width(direct.from_clb_pin_start_index, direct.from_clb_pin_end_index); + des_clb_port.set_width(direct.to_clb_pin_start_index, direct.to_clb_pin_end_index); + + /* Check bandwidth match between from_clb and to_clb pins */ + if (src_clb_port.get_width() != des_clb_port.get_width()) { + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s, [LINE%d]) Unmatch pin bandwidth in direct connection (name=%s)!\n", + __FILE__, __LINE__, direct.name); + exit(1); + } + + /* Find the module name of source clb */ + t_type_ptr src_grid_type = grids[src_clb_coord.x()][src_clb_coord.y()].type; + e_side src_grid_border_side = find_grid_border_side(device_size, src_clb_coord); + std::string src_module_name_prefix(grid_verilog_file_name_prefix); + std::string src_module_name = generate_grid_block_module_name(src_module_name_prefix, std::string(src_grid_type->name), IO_TYPE == src_grid_type, src_grid_border_side); + ModuleId src_grid_module = module_manager.find_module(src_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(src_grid_module)); + /* Record the instance id */ + size_t src_grid_instance = grid_instance_ids[src_clb_coord.x()][src_clb_coord.y()]; + + /* Find the module name of sink clb */ + t_type_ptr sink_grid_type = grids[des_clb_coord.x()][des_clb_coord.y()].type; + e_side sink_grid_border_side = find_grid_border_side(device_size, des_clb_coord); + std::string sink_module_name_prefix(grid_verilog_file_name_prefix); + std::string sink_module_name = generate_grid_block_module_name(sink_module_name_prefix, std::string(sink_grid_type->name), IO_TYPE == sink_grid_type, sink_grid_border_side); + ModuleId sink_grid_module = module_manager.find_module(sink_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(sink_grid_module)); + /* Record the instance id */ + size_t sink_grid_instance = grid_instance_ids[des_clb_coord.x()][des_clb_coord.y()]; + + /* Find the module id of a direct connection module */ + std::string direct_module_name = circuit_lib.model_name(direct.circuit_model); + ModuleId direct_module = module_manager.find_module(direct_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(direct_module)); + + /* Find inputs and outputs of the direct circuit module */ + std::vector direct_input_ports = circuit_lib.model_ports_by_type(direct.circuit_model, SPICE_MODEL_PORT_INPUT, true); + VTR_ASSERT(1 == direct_input_ports.size()); + ModulePortId direct_input_port_id = module_manager.find_module_port(direct_module, circuit_lib.port_lib_name(direct_input_ports[0])); + VTR_ASSERT(true == module_manager.valid_module_port_id(direct_module, direct_input_port_id)); + VTR_ASSERT(1 == module_manager.module_port(direct_module, direct_input_port_id).get_width()); + + std::vector direct_output_ports = circuit_lib.model_ports_by_type(direct.circuit_model, SPICE_MODEL_PORT_OUTPUT, true); + VTR_ASSERT(1 == direct_output_ports.size()); + ModulePortId direct_output_port_id = module_manager.find_module_port(direct_module, circuit_lib.port_lib_name(direct_output_ports[0])); + VTR_ASSERT(true == module_manager.valid_module_port_id(direct_module, direct_output_port_id)); + VTR_ASSERT(1 == module_manager.module_port(direct_module, direct_output_port_id).get_width()); + + for (size_t pin_id : src_clb_port.pins()) { + /* Generate the pin name of source port/pin in the grid */ + size_t src_pin_height = find_grid_pin_height(grids, src_clb_coord, src_clb_port.pins()[pin_id]); + e_side src_pin_grid_side = find_grid_pin_side(device_size, grids, src_clb_coord, src_pin_height, src_clb_port.pins()[pin_id]); + std::string src_port_name = generate_grid_port_name(src_clb_coord, src_pin_height, src_pin_grid_side, src_clb_port.pins()[pin_id], false); + ModulePortId src_port_id = module_manager.find_module_port(src_grid_module, src_port_name); + VTR_ASSERT(true == module_manager.valid_module_port_id(src_grid_module, src_port_id)); + VTR_ASSERT(1 == module_manager.module_port(src_grid_module, src_port_id).get_width()); + + /* Generate the pin name of sink port/pin in the grid */ + size_t sink_pin_height = find_grid_pin_height(grids, des_clb_coord, des_clb_port.pins()[pin_id]); + e_side sink_pin_grid_side = find_grid_pin_side(device_size, grids, des_clb_coord, sink_pin_height, des_clb_port.pins()[pin_id]); + std::string sink_port_name = generate_grid_port_name(des_clb_coord, sink_pin_height, sink_pin_grid_side, des_clb_port.pins()[pin_id], false); + ModulePortId sink_port_id = module_manager.find_module_port(sink_grid_module, sink_port_name); + VTR_ASSERT(true == module_manager.valid_module_port_id(sink_grid_module, sink_port_id)); + VTR_ASSERT(1 == module_manager.module_port(sink_grid_module, sink_port_id).get_width()); + + /* Add a submodule of direct connection module to the top-level module */ + size_t direct_instance_id = module_manager.num_instance(top_module, direct_module); + module_manager.add_child_module(top_module, direct_module); + + /* Create the 1st module net */ + ModuleNetId net_direct_src = module_manager.create_module_net(top_module); + /* Connect the wire between src_pin of clb and direct_instance input*/ + module_manager.add_module_net_source(top_module, net_direct_src, src_grid_module, src_grid_instance, src_port_id, 0); + module_manager.add_module_net_sink(top_module, net_direct_src, direct_module, direct_instance_id, direct_input_port_id, 0); + + /* Create the 2nd module net */ + ModuleNetId net_direct_sink = module_manager.create_module_net(top_module); + /* Connect the wire between direct_instance output and sink_pin of clb */ + module_manager.add_module_net_source(top_module, net_direct_sink, direct_module, direct_instance_id, direct_output_port_id, 0); + module_manager.add_module_net_sink(top_module, net_direct_sink, sink_grid_module, sink_grid_instance, sink_port_id, 0); + } +} + + +/******************************************************************** + * Add module net of clb-to-clb direct connections to module manager + * Note that the direct connections are not limited to CLBs only. + * It can be more generic and thus cover all the grid types, + * such as heterogeneous blocks + * + * This function supports the following type of direct connection: + * 1. Direct connection between grids in the same column or row + * +------+ +------+ + * | | | | + * | Grid |----->| Grid | + * | | | | + * +------+ +------+ + * | direction connection + * v + * +------+ + * | | + * | Grid | + * | | + * +------+ + * + *******************************************************************/ +static +void add_top_module_nets_intra_clb2clb_direct_connections(ModuleManager& module_manager, + const ModuleId& top_module, + const CircuitLibrary& circuit_lib, + const vtr::Point& device_size, + const std::vector>& grids, + const std::vector>& grid_instance_ids, + const std::vector& clb2clb_directs) { + /* Scan the grid, visit each grid and apply direct connections */ + for (size_t ix = 0; ix < device_size.x(); ++ix) { + for (size_t iy = 0; iy < device_size.y(); ++iy) { + /* Bypass EMPTY_TYPE*/ + if ( (NULL == grids[ix][iy].type) + || (EMPTY_TYPE == grids[ix][iy].type)) { + continue; + } + /* Bypass any grid with a non-zero offset! They have been visited in the offset=0 case */ + if (0 != grids[ix][iy].offset) { + continue; + } + /* Check each clb2clb directs by comparing the source and destination clb types + * Direct connections are made only for those matched clbs + */ + for (const t_clb_to_clb_directs& direct : clb2clb_directs) { + /* Bypass unmatched clb type */ + if (grids[ix][iy].type != direct.from_clb_type) { + continue; + } + + /* See if the destination CLB is in the bound */ + vtr::Point src_clb_coord(ix, iy); + vtr::Point des_clb_coord(ix + direct.x_offset, iy + direct.y_offset); + if (false == is_grid_coordinate_exist_in_device(device_size, des_clb_coord)) { + continue; + } + + /* Check if the destination clb_type matches */ + if (grids[des_clb_coord.x()][des_clb_coord.y()].type == direct.to_clb_type) { + /* Add a module net for a direct connection with the two grids in top_model */ + add_module_nets_clb2clb_direct_connection(module_manager, top_module, circuit_lib, + device_size, grids, grid_instance_ids, + src_clb_coord, des_clb_coord, + direct); + } + } + } + } +} + +/******************************************************************** + * Find the coordinate of a grid in a specific column + * with a given type + * This function will return the coordinate of the grid that satifies + * the type requirement + *******************************************************************/ +static +vtr::Point find_grid_coordinate_given_type(const vtr::Point& device_size, + const std::vector>& grids, + const std::vector>& candidate_coords, + t_type_ptr wanted_grid_type) { + for (vtr::Point coord : candidate_coords) { + /* If the next column is not longer in device range, we can return */ + if (false == is_grid_coordinate_exist_in_device(device_size, coord)) { + continue; + } + if (wanted_grid_type == grids[coord.x()][coord.y()].type) { + return coord; + } + } + /* Return an valid coordinate */ + return vtr::Point(size_t(-1), size_t(-1)); +} + +/******************************************************************** + * Find the coordinate of the destination clb/heterogeneous block + * considering intra column/row direct connections in core grids + *******************************************************************/ +static +vtr::Point find_intra_direct_destination_coordinate(const vtr::Point& device_size, + const std::vector>& grids, + const vtr::Point src_coord, + const t_clb_to_clb_directs& direct) { + vtr::Point des_coord(size_t(-1), size_t(-1)); + t_type_ptr src_grid_type = grids[src_coord.x()][src_coord.y()].type; + + std::vector first_search_space; + std::vector second_search_space; + + /* Cross column connection from Bottom to Top on Right + * The next column may NOT have the grid type we want! + * Think about heterogeneous architecture! + * Our search space will start from the next column + * and ends at the RIGHT side of fabric + */ + if (P2P_DIRECT_COLUMN == direct.interconnection_type) { + if (POSITIVE_DIR == direct.x_dir) { + /* Our first search space will be in x-direction: + * + * x ... nx + * +-----+ + * |Grid | -----> + * +-----+ + */ + for (size_t ix = src_coord.x() + 1; ix < device_size.x() - 1; ++ix) { + first_search_space.push_back(ix); + } + } else { + VTR_ASSERT(NEGATIVE_DIR == direct.x_dir); + /* Our first search space will be in x-direction: + * + * 1 ... x + * +-----+ + * < -------|Grid | + * +-----+ + */ + for (size_t ix = src_coord.x() - 1; ix >= 1; --ix) { + first_search_space.push_back(ix); + } + } + + /* Our second search space will be in y-direction: + * + * +------+ + * | Grid | ny + * +------+ + * | . + * | . + * v . + * +------+ + * | Grid | 1 + * +------+ + */ + for (size_t iy = 1 ; iy < device_size.y() - 1; ++iy) { + second_search_space.push_back(iy); + } + + /* For negative direction, our second search space will be in y-direction: + * + * +------+ + * | Grid | ny + * +------+ + * ^ . + * | . + * | . + * +------+ + * | Grid | 1 + * +------+ + */ + if (NEGATIVE_DIR == direct.y_dir) { + std::reverse(second_search_space.begin(), second_search_space.end()); + } + } + + + /* Cross row connection from Bottom to Top on Right + * The next column may NOT have the grid type we want! + * Think about heterogeneous architecture! + * Our search space will start from the next column + * and ends at the RIGHT side of fabric + */ + if (P2P_DIRECT_ROW == direct.interconnection_type) { + if (POSITIVE_DIR == direct.y_dir) { + /* Our first search space will be in y-direction: + * + * +------+ + * | Grid | ny + * +------+ + * ^ . + * | . + * | . + * +------+ + * | Grid | y + * +------+ + */ + for (size_t iy = src_coord.y() + 1; iy < device_size.y() - 1; ++iy) { + first_search_space.push_back(iy); + } + } else { + VTR_ASSERT(NEGATIVE_DIR == direct.y_dir); + /* For negative y-direction, + * Our first search space will be in y-direction: + * + * +------+ + * | Grid | ny + * +------+ + * | . + * | . + * v . + * +------+ + * | Grid | y + * +------+ + */ + for (size_t iy = src_coord.y() - 1; iy >= 1; --iy) { + first_search_space.push_back(iy); + } + } + + /* Our second search space will be in x-direction: + * + * 1 ... nx + * +------+ +------+ + * | Grid |------>| Grid | + * +------+ +------+ + */ + for (size_t ix = 1 ; ix < device_size.x() - 1; ++ix) { + second_search_space.push_back(ix); + } + + /* For negative direction, + * our second search space will be in x-direction: + * + * 1 ... nx + * +------+ +------+ + * | Grid |<------| Grid | + * +------+ +------+ + */ + if (NEGATIVE_DIR == direct.x_dir) { + std::reverse(second_search_space.begin(), second_search_space.end()); + } + } + + for (size_t ix : first_search_space) { + std::vector> next_col_row_coords; + for (size_t iy : second_search_space) { + if (P2P_DIRECT_COLUMN == direct.interconnection_type) { + next_col_row_coords.push_back(vtr::Point(ix, iy)); + } else { + VTR_ASSERT(P2P_DIRECT_ROW == direct.interconnection_type); + /* For cross-row connection, our search space is flipped */ + next_col_row_coords.push_back(vtr::Point(iy, ix)); + } + } + vtr::Point des_coord_cand = find_grid_coordinate_given_type(device_size, grids, next_col_row_coords, src_grid_type); + /* For a valid coordinate, we can return */ + if ( (size_t(-1) != des_coord_cand.x()) + && (size_t(-1) != des_coord_cand.y()) ) { + return des_coord_cand; + } + } + return des_coord; +} + +/******************************************************************** + * Add module net of clb-to-clb direct connections to module manager + * Note that the direct connections are not limited to CLBs only. + * It can be more generic and thus cover all the grid types, + * such as heterogeneous blocks + * + * This function supports the following type of direct connection: + * + * 1. Direct connections across columns and rows + * +------+ + * | | + * | v + * +------+ | +------+ + * | | | | | + * | Grid | | | Grid | + * | | | | | + * +------+ | +------+ + * | + * +------+ | +------+ + * | | | | | + * | Grid | | | Grid | + * | | | | | + * +------+ | +------+ + * | | + * +------+ + * + * Note that: this will only apply to the core grids! + * I/Os or any blocks on the border of fabric are NOT supported! + * + *******************************************************************/ +static +void add_top_module_nets_inter_clb2clb_direct_connections(ModuleManager& module_manager, + const ModuleId& top_module, + const CircuitLibrary& circuit_lib, + const vtr::Point& device_size, + const std::vector>& grids, + const std::vector>& grid_instance_ids, + const std::vector& clb2clb_directs) { + + std::vector border_sides = {TOP, RIGHT, BOTTOM, LEFT}; + + /* Go through the direct connection list, see if we need intra-column/row connection here */ + for (const t_clb_to_clb_directs& direct: clb2clb_directs) { + if ( (P2P_DIRECT_COLUMN != direct.interconnection_type) + && (P2P_DIRECT_ROW != direct.interconnection_type)) { + continue; + } + /* For cross-column connection, we will search the first valid grid in each column + * from y = 1 to y = ny + * + * +------+ + * | Grid | y=ny + * +------+ + * ^ + * | search direction (when y_dir is negative) + * ... + * | + * +------+ + * | Grid | y=1 + * +------+ + * + */ + if (P2P_DIRECT_COLUMN == direct.interconnection_type) { + for (size_t ix = 1; ix < device_size.x() - 1; ++ix) { + std::vector> next_col_src_grid_coords; + /* For negative y- direction, we should start from y = ny */ + for (size_t iy = 1; iy < device_size.y() - 1; ++iy) { + next_col_src_grid_coords.push_back(vtr::Point(ix, iy)); + } + /* For positive y- direction, we should start from y = 1 */ + if (POSITIVE_DIR == direct.y_dir) { + std::reverse(next_col_src_grid_coords.begin(), next_col_src_grid_coords.end()); + } + vtr::Point src_clb_coord = find_grid_coordinate_given_type(device_size, grids, next_col_src_grid_coords, direct.from_clb_type); + /* Skip if we do not have a valid coordinate for source CLB/heterogeneous block */ + if ( (size_t(-1) == src_clb_coord.x()) + || (size_t(-1) == src_clb_coord.y()) ) { + continue; + } + /* For a valid coordinate, we can find the coordinate of the destination clb */ + vtr::Point des_clb_coord = find_intra_direct_destination_coordinate(device_size, grids, src_clb_coord, direct); + /* If destination clb is valid, we should add something */ + if ( (size_t(-1) == des_clb_coord.x()) + || (size_t(-1) == des_clb_coord.y()) ) { + continue; + } + add_module_nets_clb2clb_direct_connection(module_manager, top_module, circuit_lib, + device_size, grids, grid_instance_ids, + src_clb_coord, des_clb_coord, + direct); + } + continue; /* Go to next direct type */ + } + + /* Reach here, it must be a cross-row connection */ + VTR_ASSERT(P2P_DIRECT_ROW == direct.interconnection_type); + /* For cross-row connection, we will search the first valid grid in each column + * from x = 1 to x = nx + * + * x=1 x=nx + * +------+ +------+ + * | Grid | <--- ... ---- | Grid | + * +------+ +------+ + * + */ + for (size_t iy = 1; iy < device_size.y() - 1; ++iy) { + std::vector> next_col_src_grid_coords; + /* For negative x- direction, we should start from x = nx */ + for (size_t ix = 1; ix < device_size.x() - 1; ++ix) { + next_col_src_grid_coords.push_back(vtr::Point(ix, iy)); + } + /* For positive x- direction, we should start from x = 1 */ + if (POSITIVE_DIR == direct.x_dir) { + std::reverse(next_col_src_grid_coords.begin(), next_col_src_grid_coords.end()); + } + vtr::Point src_clb_coord = find_grid_coordinate_given_type(device_size, grids, next_col_src_grid_coords, direct.from_clb_type); + /* Skip if we do not have a valid coordinate for source CLB/heterogeneous block */ + if ( (size_t(-1) == src_clb_coord.x()) + || (size_t(-1) == src_clb_coord.y()) ) { + continue; + } + /* For a valid coordinate, we can find the coordinate of the destination clb */ + vtr::Point des_clb_coord = find_intra_direct_destination_coordinate(device_size, grids, src_clb_coord, direct); + /* If destination clb is valid, we should add something */ + if ( (size_t(-1) == des_clb_coord.x()) + || (size_t(-1) == des_clb_coord.y()) ) { + continue; + } + add_module_nets_clb2clb_direct_connection(module_manager, top_module, circuit_lib, + device_size, grids, grid_instance_ids, + src_clb_coord, des_clb_coord, + direct); + } + } +} + +/******************************************************************** + * Add module net of clb-to-clb direct connections to module manager + * Note that the direct connections are not limited to CLBs only. + * It can be more generic and thus cover all the grid types, + * such as heterogeneous blocks + *******************************************************************/ +void add_top_module_nets_clb2clb_direct_connections(ModuleManager& module_manager, + const ModuleId& top_module, + const CircuitLibrary& circuit_lib, + const vtr::Point& device_size, + const std::vector>& grids, + const std::vector>& grid_instance_ids, + const std::vector& clb2clb_directs) { + + add_top_module_nets_intra_clb2clb_direct_connections(module_manager, top_module, circuit_lib, + device_size, grids, grid_instance_ids, + clb2clb_directs); + + add_top_module_nets_inter_clb2clb_direct_connections(module_manager, top_module, circuit_lib, + device_size, grids, grid_instance_ids, + clb2clb_directs); +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/build_top_module_directs.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/build_top_module_directs.h new file mode 100644 index 000000000..4c6f759ee --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/build_top_module_directs.h @@ -0,0 +1,18 @@ +#ifndef BUILD_TOP_MODULE_DIRECTS_H +#define BUILD_TOP_MODULE_DIRECTS_H + +#include +#include "vtr_geometry.h" +#include "vpr_types.h" +#include "module_manager.h" +#include "circuit_library.h" + +void add_top_module_nets_clb2clb_direct_connections(ModuleManager& module_manager, + const ModuleId& top_module, + const CircuitLibrary& circuit_lib, + const vtr::Point& device_size, + const std::vector>& grids, + const std::vector>& grid_instance_ids, + const std::vector& clb2clb_directs); + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/build_top_module_memory.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/build_top_module_memory.cpp new file mode 100644 index 000000000..8331edad5 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/build_top_module_memory.cpp @@ -0,0 +1,425 @@ +/******************************************************************** + * This file includes functions that are used to organize memories + * in the top module of FPGA fabric + *******************************************************************/ +#include "vtr_assert.h" + +#include "fpga_x2p_utils.h" +#include "fpga_x2p_naming.h" + +#include "globals.h" +#include "verilog_global.h" + +#include "module_manager_utils.h" +#include "build_top_module_memory.h" + +/******************************************************************** + * This function adds the CBX/CBY of a tile + * to the memory modules and memory instances + * This function is designed for organizing memory modules in top-level + * module + *******************************************************************/ +static +void organize_top_module_tile_cb_modules(const ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, + const CircuitModelId& sram_model, + t_sram_orgz_info* cur_sram_orgz_info, + const std::vector>& cb_instance_ids, + const DeviceRRGSB& L_device_rr_gsb, + const RRGSB& rr_gsb, + const t_rr_type& cb_type, + const bool& compact_routing_hierarchy, + std::vector& memory_modules, + std::vector& memory_instances) { + /* If the CB does not exist, we can skip addition */ + if ( (TRUE != is_cb_exist(cb_type, rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type))) + || (true != rr_gsb.is_cb_exist(cb_type))) { + return; + } + + vtr::Point cb_coord(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)); + /* If we use compact routing hierarchy, we should instanciate the unique module of SB */ + if (true == compact_routing_hierarchy) { + const RRGSB& unique_mirror = L_device_rr_gsb.get_cb_unique_module(cb_type, DeviceCoordinator(cb_coord.x(), cb_coord.y())); + cb_coord.set_x(unique_mirror.get_cb_x(cb_type)); + cb_coord.set_y(unique_mirror.get_cb_y(cb_type)); + } + + std::string cb_module_name = generate_connection_block_module_name(cb_type, cb_coord); + ModuleId cb_module = module_manager.find_module(cb_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(cb_module)); + + /* Identify if this sub module includes configuration bits, + * we will update the memory module and instance list + */ + if (0 < find_module_num_config_bits(module_manager, cb_module, + circuit_lib, sram_model, + cur_sram_orgz_info->type)) { + memory_modules.push_back(cb_module); + memory_instances.push_back(cb_instance_ids[cb_coord.x()][cb_coord.y()]); + } +} + +/******************************************************************** + * This function adds the SB, CBX, CBY and Grid of a tile + * to the memory modules and memory instances + * This function is designed for organizing memory modules in top-level + * module + *******************************************************************/ +static +void organize_top_module_tile_memory_modules(const ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, + const CircuitModelId& sram_model, + t_sram_orgz_info* cur_sram_orgz_info, + const std::vector>& grids, + const std::vector>& grid_instance_ids, + const DeviceRRGSB& L_device_rr_gsb, + const std::vector>& sb_instance_ids, + const std::map>>& cb_instance_ids, + const bool& compact_routing_hierarchy, + const vtr::Point& tile_coord, + const e_side& tile_border_side, + std::vector& memory_modules, + std::vector& memory_instances) { + + vtr::Point gsb_coord_range(L_device_rr_gsb.get_gsb_range().get_x(), L_device_rr_gsb.get_gsb_range().get_y()); + + vtr::Point gsb_coord(tile_coord.x(), tile_coord.y() - 1); + + /* We do NOT consider SB and CBs if the gsb is not in the range! */ + if ( (gsb_coord.x() < gsb_coord_range.x()) + && (gsb_coord.y() < gsb_coord_range.y()) ) { + const RRGSB& rr_gsb = L_device_rr_gsb.get_gsb(gsb_coord.x(), gsb_coord.y()); + /* Find Switch Block: unique module id and instance id! + * Note that switch block does always exist in a GSB + */ + vtr::Point sb_coord(rr_gsb.get_sb_x(), rr_gsb.get_sb_y()); + /* If we use compact routing hierarchy, we should instanciate the unique module of SB */ + if (true == compact_routing_hierarchy) { + const RRGSB& unique_mirror = L_device_rr_gsb.get_sb_unique_module(DeviceCoordinator(sb_coord.x(), sb_coord.y())); + sb_coord.set_x(unique_mirror.get_sb_x()); + sb_coord.set_y(unique_mirror.get_sb_y()); + } + std::string sb_module_name = generate_switch_block_module_name(sb_coord); + ModuleId sb_module = module_manager.find_module(sb_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(sb_module)); + + /* Identify if this sub module includes configuration bits, + * we will update the memory module and instance list + */ + if (0 < find_module_num_config_bits(module_manager, sb_module, + circuit_lib, sram_model, + cur_sram_orgz_info->type)) { + memory_modules.push_back(sb_module); + memory_instances.push_back(sb_instance_ids[sb_coord.x()][sb_coord.y()]); + } + + /* Try to find and add CBX and CBY */ + organize_top_module_tile_cb_modules(module_manager, circuit_lib, + sram_model, cur_sram_orgz_info, + cb_instance_ids.at(CHANX), + L_device_rr_gsb, rr_gsb, CHANX, + compact_routing_hierarchy, + memory_modules, memory_instances); + + organize_top_module_tile_cb_modules(module_manager, circuit_lib, + sram_model, cur_sram_orgz_info, + cb_instance_ids.at(CHANY), + L_device_rr_gsb, rr_gsb, CHANY, + compact_routing_hierarchy, + memory_modules, memory_instances); + } + + /* Find the module name for this type of grid */ + t_type_ptr grid_type = grids[tile_coord.x()][tile_coord.y()].type; + std::string grid_module_name_prefix(grid_verilog_file_name_prefix); + std::string grid_module_name = generate_grid_block_module_name(grid_module_name_prefix, std::string(grid_type->name), IO_TYPE == grid_type, tile_border_side); + ModuleId grid_module = module_manager.find_module(grid_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(grid_module)); + + /* Identify if this sub module includes configuration bits, + * we will update the memory module and instance list + */ + if (0 < find_module_num_config_bits(module_manager, grid_module, + circuit_lib, sram_model, + cur_sram_orgz_info->type)) { + memory_modules.push_back(grid_module); + memory_instances.push_back(grid_instance_ids[tile_coord.x()][tile_coord.y()]); + } +} + +/******************************************************************** + * Organize the list of memory modules and instances + * This function will record all the sub modules of the top-level module + * (those have memory ports) to two lists: + * 1. memory_modules records the module ids + * 2. memory_instances records the instance ids + * To keep a clean memory connection between sub modules and top-level module, + * the sequence of memory_modules and memory_instances will follow + * a chain of tiles considering their physical location + * + * Inter tile connection: + * +--------------------------------------------------------+ + * | +------+------+-----+------+ | + * | | I/O | I/O | ... | I/O | | + * | | TOP | TOP | | TOP | | + * | +------+------+-----+------+ | + * | +---------------------------------->tail | + * | +------+ | +------+------+-----+------+ +------+ | + * | | | | | | | | | | | | + * | | I/O | | | Tile | Tile | ... | Tile | | I/O | | + * | | LEFT | | | [h+1]| [h+2]| | [n] | |RIGHT | | + * | +------+ | +------+------+-----+------+ +------+ | + * | +-------------------------------+ | + * | ... ... ... ... ... | ... | + * | +-------------------------------+ | + * | +------+ | +------+------+-----+------+ +------+ | + * | | | | | | | | | | | | + * | | I/O | | | Tile | Tile | ... | Tile | | I/O | | + * | | LEFT | | | [i+1]| [i+2]| | [j] | |RIGHT | | + * | +------+ | +------+------+-----+------+ +------+ | + * | +-------------------------------+ | + * | +------+ +------+------+-----+------+ | +------+ | + * | | | | | | | | | | | | + * | | I/O | | Tile | Tile | ... | Tile | | | I/O | | + * | | LEFT | | [0] | [1] | | [i] | | |RIGHT | | + * | +------+ +------+------+-----+------+ | +------+ | + * +-------------------------------------------+ | + * +------+------+-----+------+ | + * | I/O | I/O | ... | I/O | | + * |BOTTOM|BOTTOM| |BOTTOM| | + * +------+------+-----+------+ | + * head >-----------------------------------------------+ + * + * Inner tile connection + * + * Tile + * +---------------+----------+ + * <-+---------------+ + | + * | | | | + * | CLB | | CBY | + * | +-|-+ | + * | | | | + * +---------------+----------+ + * | +-+----+-----+---<--- + * | CBX | SB | + * | | | + * +---------------+----------+ + * + *******************************************************************/ +void organize_top_module_memory_modules(const ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, + const CircuitModelId& sram_model, + t_sram_orgz_info* cur_sram_orgz_info, + 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::map>>& cb_instance_ids, + const bool& compact_routing_hierarchy, + std::vector& memory_modules, + std::vector& memory_instances) { + /* Ensure clean vectors to return */ + VTR_ASSERT(true == memory_modules.empty()); + VTR_ASSERT(true == memory_instances.empty()); + + /* First, organize the I/O tiles on the border */ + /* Special for the I/O tileas on RIGHT and BOTTOM, + * which are only I/O blocks, which do NOT contain CBs and SBs + */ + std::vector io_sides{BOTTOM, RIGHT, TOP, LEFT}; + std::map>> io_coords; + + /* BOTTOM side I/Os */ + for (size_t ix = 1; ix < device_size.x() - 1; ++ix) { + io_coords[BOTTOM].push_back(vtr::Point(ix, 0)); + } + + /* RIGHT side I/Os */ + for (size_t iy = 1; iy < device_size.y() - 1; ++iy) { + io_coords[RIGHT].push_back(vtr::Point(device_size.x() - 1, iy)); + } + + /* TOP side I/Os */ + for (size_t ix = 1; ix < device_size.x() - 1; ++ix) { + io_coords[TOP].push_back(vtr::Point(ix, device_size.y() - 1)); + } + + /* LEFT side I/Os */ + for (size_t iy = 1; iy < device_size.y() - 1; ++iy) { + io_coords[LEFT].push_back(vtr::Point(0, iy)); + } + + for (const e_side& io_side : io_sides) { + for (const vtr::Point& io_coord : io_coords[io_side]) { + /* Identify the GSB that surrounds the grid */ + organize_top_module_tile_memory_modules(module_manager, + circuit_lib, sram_model, cur_sram_orgz_info, + grids, grid_instance_ids, + L_device_rr_gsb, sb_instance_ids, cb_instance_ids, + compact_routing_hierarchy, + io_coord, io_side, + memory_modules, memory_instances); + } + } + + /* For the core grids */ + std::vector> core_coords; + bool positive_direction = true; + for (size_t iy = 1; iy < device_size.y() - 1; ++iy) { + /* For positive direction: -----> */ + if (true == positive_direction) { + for (size_t ix = 1; ix < device_size.x() - 1; ++ix) { + core_coords.push_back(vtr::Point(ix, iy)); + } + } else { + VTR_ASSERT(false == positive_direction); + /* For negative direction: -----> */ + for (size_t ix = device_size.x() - 2; ix >= 1; --ix) { + core_coords.push_back(vtr::Point(ix, iy)); + } + } + /* Flip the positive direction to be negative */ + positive_direction = !positive_direction; + } + + for (const vtr::Point& core_coord : core_coords) { + organize_top_module_tile_memory_modules(module_manager, + circuit_lib, sram_model, cur_sram_orgz_info, + grids, grid_instance_ids, + L_device_rr_gsb, sb_instance_ids, cb_instance_ids, + compact_routing_hierarchy, + core_coord, NUM_SIDES, + memory_modules, memory_instances); + } +} + + +/********************************************************************* + * Add the port-to-port connection between all the memory modules + * and their parent module + * + * Create nets to wire the control signals of memory module to + * the configuration ports of primitive module + * + * Configuration Chain + * ------------------- + * + * config_bus (head) config_bus (tail) + * | ^ + * primitive | | + * +---------------------------------------------+ + * | | | | + * | v | | + * | +-------------------------------------+ | + * | | CMOS-based Memory Modules | | + * | +-------------------------------------+ | + * | | | | + * | v v | + * | sram_out sram_outb | + * | | + * +---------------------------------------------+ + * + * Memory bank + * ----------- + * + * config_bus (BL) config_bus (WL) + * | | + * primitive | | + * +---------------------------------------------+ + * | | | | + * | v v | + * | +-------------------------------------+ | + * | | CMOS-based Memory Modules | | + * | +-------------------------------------+ | + * | | | | + * | v v | + * | sram_out sram_outb | + * | | + * +---------------------------------------------+ + * + **********************************************************************/ +static +void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager, + const ModuleId& parent_module, + const std::vector& memory_modules, + const std::vector& memory_instances, + const e_sram_orgz& sram_orgz_type) { + /* Ensure that the size of memory_model vector matches the memory_module vector */ + VTR_ASSERT(memory_modules.size() == memory_instances.size()); + + switch (sram_orgz_type) { + case SPICE_SRAM_STANDALONE: + /* Nothing to do */ + break; + case SPICE_SRAM_SCAN_CHAIN: { + add_module_nets_cmos_memory_chain_config_bus(module_manager, parent_module, memory_modules, memory_instances, sram_orgz_type); + break; + } + case SPICE_SRAM_MEMORY_BANK: + /* TODO: */ + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s,[LINE%d])Invalid type of SRAM organization!\n", + __FILE__, __LINE__); + exit(1); + } +} + + +/******************************************************************** + * TODO: + * Add the port-to-port connection between a memory module + * and the configuration bus of a primitive module + * + * Create nets to wire the control signals of memory module to + * the configuration ports of primitive module + * + * Primitive module + * +----------------------------+ + * | +--------+ | + * config | | | | + * ports --->|--------------->| Memory | | + * | | Module | | + * | | | | + * | +--------+ | + * +----------------------------+ + * The detailed config ports really depend on the type + * of SRAM organization. + * + * The config_bus in the argument is the reserved address of configuration + * bus in the parent_module for this memory module + * + * The configuration bus connection will depend not only + * the design technology of the memory cells but also the + * configuration styles of FPGA fabric. + * Here we will branch on the design technology + * + * Note: this function SHOULD be called after the pb_type_module is created + * and its child module (logic_module and memory_module) is created! + *******************************************************************/ +void add_top_module_nets_memory_config_bus(ModuleManager& module_manager, + const ModuleId& parent_module, + const std::vector& memory_modules, + const std::vector& memory_instances, + const e_sram_orgz& sram_orgz_type, + const e_spice_model_design_tech& mem_tech) { + switch (mem_tech) { + case SPICE_MODEL_DESIGN_CMOS: + add_top_module_nets_cmos_memory_config_bus(module_manager, parent_module, + memory_modules, memory_instances, + sram_orgz_type); + break; + case SPICE_MODEL_DESIGN_RRAM: + /* TODO: */ + break; + default: + vpr_printf(TIO_MESSAGE_ERROR, + "(File:%s,[LINE%d])Invalid type of memory design technology !\n", + __FILE__, __LINE__); + exit(1); + } +} + diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/build_top_module_memory.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/build_top_module_memory.h new file mode 100644 index 000000000..66afa2a51 --- /dev/null +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/build_top_module_memory.h @@ -0,0 +1,32 @@ +#ifndef BUILD_TOP_MODULE_MEMORY_H +#define BUILD_TOP_MODULE_MEMORY_H + +#include +#include +#include "module_manager.h" +#include "spice_types.h" +#include "circuit_library.h" +#include "rr_blocks.h" + +void organize_top_module_memory_modules(const ModuleManager& module_manager, + const CircuitLibrary& circuit_lib, + const CircuitModelId& sram_model, + t_sram_orgz_info* cur_sram_orgz_info, + 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::map>>& cb_instance_ids, + const bool& compact_routing_hierarchy, + std::vector& memory_modules, + std::vector& memory_instances); + +void add_top_module_nets_memory_config_bus(ModuleManager& module_manager, + const ModuleId& parent_module, + const std::vector& memory_modules, + const std::vector& memory_instances, + const e_sram_orgz& sram_orgz_type, + const e_spice_model_design_tech& mem_tech); + +#endif diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.cpp index a703ee379..f7e6b7c8b 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.cpp @@ -565,6 +565,113 @@ void add_module_nets_between_logic_and_memory_sram_bus(ModuleManager& module_man } } +/* Connect all the memory modules under the parent module in a chain + * + * +--------+ +--------+ +--------+ + * ccff_head --->| Memory |--->| Memory |--->... --->| Memory |----> ccff_tail + * | Module | | Module | | Module | + * | [0] | | [1] | | [N-1] | + * +--------+ +--------+ +--------+ + * For the 1st memory module: + * net source is the configuration chain head of the primitive module + * net sink is the configuration chain head of the next memory module + * + * For the rest of memory modules: + * net source is the configuration chain tail of the previous memory module + * net sink is the configuration chain head of the next memory module + */ +void add_module_nets_cmos_memory_chain_config_bus(ModuleManager& module_manager, + const ModuleId& parent_module, + const std::vector& memory_modules, + const std::vector& memory_instances, + const e_sram_orgz& sram_orgz_type) { + for (size_t mem_index = 0; mem_index < memory_modules.size(); ++mem_index) { + ModuleId net_src_module_id; + size_t net_src_instance_id; + ModulePortId net_src_port_id; + + ModuleId net_sink_module_id; + size_t net_sink_instance_id; + ModulePortId net_sink_port_id; + + if (0 == mem_index) { + /* Find the port name of configuration chain head */ + std::string src_port_name = generate_sram_port_name(sram_orgz_type, SPICE_MODEL_PORT_INPUT); + net_src_module_id = parent_module; + net_src_instance_id = 0; + net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name); + + /* Find the port name of next memory module */ + std::string sink_port_name = generate_configuration_chain_head_name(); + net_sink_module_id = memory_modules[mem_index]; + net_sink_instance_id = memory_instances[mem_index]; + net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name); + } else { + /* Find the port name of previous memory module */ + std::string src_port_name = generate_configuration_chain_tail_name(); + net_src_module_id = memory_modules[mem_index - 1]; + net_src_instance_id = memory_instances[mem_index - 1]; + net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name); + + /* Find the port name of next memory module */ + std::string sink_port_name = generate_configuration_chain_head_name(); + net_sink_module_id = memory_modules[mem_index]; + net_sink_instance_id = memory_instances[mem_index]; + net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name); + } + + /* Get the pin id for source port */ + BasicPort net_src_port = module_manager.module_port(net_src_module_id, net_src_port_id); + /* Get the pin id for sink port */ + BasicPort net_sink_port = module_manager.module_port(net_sink_module_id, net_sink_port_id); + /* Port sizes of source and sink should match */ + VTR_ASSERT(net_src_port.get_width() == net_sink_port.get_width()); + + /* Create a net for each pin */ + for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) { + /* Create a net and add source and sink to it */ + ModuleNetId net = module_manager.create_module_net(parent_module); + /* Add net source */ + module_manager.add_module_net_source(parent_module, net, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]); + /* Add net sink */ + module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]); + } + } + + /* For the last memory module: + * net source is the configuration chain tail of the previous memory module + * net sink is the configuration chain tail of the primitive module + */ + /* Find the port name of previous memory module */ + std::string src_port_name = generate_configuration_chain_tail_name(); + ModuleId net_src_module_id = memory_modules.back(); + size_t net_src_instance_id = memory_instances.back(); + ModulePortId net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name); + + /* Find the port name of next memory module */ + std::string sink_port_name = generate_sram_port_name(sram_orgz_type, SPICE_MODEL_PORT_OUTPUT); + ModuleId net_sink_module_id = parent_module; + size_t net_sink_instance_id = 0; + ModulePortId net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name); + + /* Get the pin id for source port */ + BasicPort net_src_port = module_manager.module_port(net_src_module_id, net_src_port_id); + /* Get the pin id for sink port */ + BasicPort net_sink_port = module_manager.module_port(net_sink_module_id, net_sink_port_id); + /* Port sizes of source and sink should match */ + VTR_ASSERT(net_src_port.get_width() == net_sink_port.get_width()); + + /* Create a net for each pin */ + for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) { + /* Create a net and add source and sink to it */ + ModuleNetId net = module_manager.create_module_net(parent_module); + /* Add net source */ + module_manager.add_module_net_source(parent_module, net, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]); + /* Add net sink */ + module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]); + } +} + /********************************************************************* * Add the port-to-port connection between all the memory modules * and their parent module @@ -623,106 +730,7 @@ void add_module_nets_cmos_memory_config_bus(ModuleManager& module_manager, /* Nothing to do */ break; case SPICE_SRAM_SCAN_CHAIN: { - /* Connect all the memory modules under the parent module in a chain - * - * +--------+ +--------+ +--------+ - * ccff_head --->| Memory |--->| Memory |--->... --->| Memory |----> ccff_tail - * | Module | | Module | | Module | - * | [0] | | [1] | | [N-1] | - * +--------+ +--------+ +--------+ - * For the 1st memory module: - * net source is the configuration chain head of the primitive module - * net sink is the configuration chain head of the next memory module - * - * For the rest of memory modules: - * net source is the configuration chain tail of the previous memory module - * net sink is the configuration chain head of the next memory module - */ - for (size_t mem_index = 0; mem_index < memory_modules.size(); ++mem_index) { - ModuleId net_src_module_id; - size_t net_src_instance_id; - ModulePortId net_src_port_id; - - ModuleId net_sink_module_id; - size_t net_sink_instance_id; - ModulePortId net_sink_port_id; - - if (0 == mem_index) { - /* Find the port name of configuration chain head */ - std::string src_port_name = generate_sram_port_name(sram_orgz_type, SPICE_MODEL_PORT_INPUT); - net_src_module_id = parent_module; - net_src_instance_id = 0; - net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name); - - /* Find the port name of next memory module */ - std::string sink_port_name = generate_configuration_chain_head_name(); - net_sink_module_id = memory_modules[mem_index]; - net_sink_instance_id = memory_instances[mem_index]; - net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name); - } else { - /* Find the port name of previous memory module */ - std::string src_port_name = generate_configuration_chain_tail_name(); - net_src_module_id = memory_modules[mem_index - 1]; - net_src_instance_id = memory_instances[mem_index - 1]; - net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name); - - /* Find the port name of next memory module */ - std::string sink_port_name = generate_configuration_chain_head_name(); - net_sink_module_id = memory_modules[mem_index]; - net_sink_instance_id = memory_instances[mem_index]; - net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name); - } - - /* Get the pin id for source port */ - BasicPort net_src_port = module_manager.module_port(net_src_module_id, net_src_port_id); - /* Get the pin id for sink port */ - BasicPort net_sink_port = module_manager.module_port(net_sink_module_id, net_sink_port_id); - /* Port sizes of source and sink should match */ - VTR_ASSERT(net_src_port.get_width() == net_sink_port.get_width()); - - /* Create a net for each pin */ - for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) { - /* Create a net and add source and sink to it */ - ModuleNetId net = module_manager.create_module_net(parent_module); - /* Add net source */ - module_manager.add_module_net_source(parent_module, net, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]); - /* Add net sink */ - module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]); - } - } - - /* For the last memory module: - * net source is the configuration chain tail of the previous memory module - * net sink is the configuration chain tail of the primitive module - */ - /* Find the port name of previous memory module */ - std::string src_port_name = generate_configuration_chain_tail_name(); - ModuleId net_src_module_id = memory_modules.back(); - size_t net_src_instance_id = memory_instances.back(); - ModulePortId net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name); - - /* Find the port name of next memory module */ - std::string sink_port_name = generate_sram_port_name(sram_orgz_type, SPICE_MODEL_PORT_OUTPUT); - ModuleId net_sink_module_id = parent_module; - size_t net_sink_instance_id = 0; - ModulePortId net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name); - - /* Get the pin id for source port */ - BasicPort net_src_port = module_manager.module_port(net_src_module_id, net_src_port_id); - /* Get the pin id for sink port */ - BasicPort net_sink_port = module_manager.module_port(net_sink_module_id, net_sink_port_id); - /* Port sizes of source and sink should match */ - VTR_ASSERT(net_src_port.get_width() == net_sink_port.get_width()); - - /* Create a net for each pin */ - for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) { - /* Create a net and add source and sink to it */ - ModuleNetId net = module_manager.create_module_net(parent_module); - /* Add net source */ - module_manager.add_module_net_source(parent_module, net, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]); - /* Add net sink */ - module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]); - } + add_module_nets_cmos_memory_chain_config_bus(module_manager, parent_module, memory_modules, memory_instances, sram_orgz_type); break; } case SPICE_SRAM_MEMORY_BANK: diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.h index b0884192b..d1ab892b4 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/module_manager_utils.h @@ -69,6 +69,12 @@ void add_module_nets_between_logic_and_memory_sram_bus(ModuleManager& module_man const CircuitLibrary& circuit_lib, const CircuitModelId& logic_model); +void add_module_nets_cmos_memory_chain_config_bus(ModuleManager& module_manager, + const ModuleId& parent_module, + const std::vector& memory_modules, + const std::vector& memory_instances, + const e_sram_orgz& sram_orgz_type); + void add_module_nets_memory_config_bus(ModuleManager& module_manager, const ModuleId& parent_module, const std::vector& memory_modules, diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp index 9e1867de1..bd06d87d1 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.cpp @@ -2449,7 +2449,7 @@ const RRGSB& DeviceRRGSB::get_cb_unique_module(t_rr_type cb_type, size_t index) } /* Give a coordinator of a rr switch block, and return its unique mirror */ -const RRGSB& DeviceRRGSB::get_cb_unique_module(t_rr_type cb_type, DeviceCoordinator& coordinator) const { +const RRGSB& DeviceRRGSB::get_cb_unique_module(t_rr_type cb_type, const DeviceCoordinator& coordinator) const { assert (validate_cb_type(cb_type)); assert(validate_coordinator(coordinator)); size_t cb_unique_module_id; @@ -2472,7 +2472,7 @@ const RRGSB& DeviceRRGSB::get_cb_unique_module(t_rr_type cb_type, DeviceCoordina } /* Give a coordinator of a rr switch block, and return its unique mirror */ -const RRGSB DeviceRRGSB::get_sb_unique_module(DeviceCoordinator& coordinator) const { +const RRGSB DeviceRRGSB::get_sb_unique_module(const DeviceCoordinator& coordinator) const { assert(validate_coordinator(coordinator)); size_t sb_unique_module_id = sb_unique_module_id_[coordinator.get_x()][coordinator.get_y()]; return get_sb_unique_module(sb_unique_module_id); diff --git a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h index f1b519f13..125975da3 100644 --- a/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h +++ b/vpr7_x2p/vpr/SRC/fpga_x2p/base/rr_blocks.h @@ -338,9 +338,9 @@ class DeviceRRGSB { const RRGSB get_sb_unique_submodule(size_t index, enum e_side side, size_t seg_id) const; /* Get a rr switch block which a unique mirror */ const RRGSB get_sb_unique_submodule(DeviceCoordinator& coordinator, enum e_side side, size_t seg_id) const; /* Get a rr switch block which a unique mirror */ const RRGSB get_sb_unique_module(size_t index) const; /* Get a rr switch block which a unique mirror */ - const RRGSB get_sb_unique_module(DeviceCoordinator& coordinator) const; /* Get a rr switch block which a unique mirror */ + const RRGSB get_sb_unique_module(const DeviceCoordinator& coordinator) const; /* Get a rr switch block which a unique mirror */ const RRGSB& get_cb_unique_module(t_rr_type cb_type, size_t index) const; /* Get a rr switch block which a unique mirror */ - const RRGSB& get_cb_unique_module(t_rr_type cb_type, DeviceCoordinator& coordinator) const; + const RRGSB& get_cb_unique_module(t_rr_type cb_type, const DeviceCoordinator& coordinator) const; size_t get_max_num_sides() const; /* Get the maximum number of sides across the switch blocks */ size_t get_num_segments() const; /* Get the size of segment_ids */ size_t get_segment_id(size_t index) const; /* Get a segment id */ 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 29a9f5122..136cef804 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 @@ -15,6 +15,8 @@ #include "fpga_x2p_utils.h" #include "fpga_x2p_pbtypes_utils.h" #include "module_manager_utils.h" +#include "build_top_module_memory.h" +#include "build_top_module_directs.h" #include "verilog_global.h" #include "verilog_routing.h" @@ -22,15 +24,6 @@ #include "verilog_module_writer.h" #include "verilog_top_module.h" -/******************************************************************** - * Check if the grid coorindate given is in the device grid range - *******************************************************************/ -static -bool is_grid_coordinate_exist_in_device(const vtr::Point& device_size, - const vtr::Point& grid_coordinate) { - return (grid_coordinate < device_size); -} - /******************************************************************** * Generate the name for a grid block, by considering * 1. if it locates on the border with given device size @@ -236,6 +229,7 @@ std::vector> add_top_module_switch_block_instances(ModuleMan const ModuleId& top_module, const DeviceRRGSB& L_device_rr_gsb, const bool& compact_routing_hierarchy) { + /* TODO: deprecate DeviceCoordinator, use vtr::Point only! */ DeviceCoordinator sb_range = L_device_rr_gsb.get_gsb_range(); /* Reserve an array for the instance ids */ @@ -798,540 +792,6 @@ void add_top_module_nets_connect_grids_and_gsbs(ModuleManager& module_manager, } } -/******************************************************************** - * Add module net for one direction connection between two CLBs or - * two grids - * This function will - * 1. find the pin id and port id of the source clb port in module manager - * 2. find the pin id and port id of the destination clb port in module manager - * 3. add a direct connection module to the top module - * 4. add a first module net and configure its source and sink, - * in order to connect the source pin to the input of the top module - * 4. add a second module net and configure its source and sink, - * in order to connect the sink pin to the output of the top module - *******************************************************************/ -static -void add_module_nets_clb2clb_direct_connection(ModuleManager& module_manager, - const ModuleId& top_module, - const CircuitLibrary& circuit_lib, - const vtr::Point& device_size, - const std::vector>& grids, - const std::vector>& grid_instance_ids, - const vtr::Point& src_clb_coord, - const vtr::Point& des_clb_coord, - const t_clb_to_clb_directs& direct) { - /* Find the source port and destination port on the CLBs */ - BasicPort src_clb_port; - BasicPort des_clb_port; - - src_clb_port.set_width(direct.from_clb_pin_start_index, direct.from_clb_pin_end_index); - des_clb_port.set_width(direct.to_clb_pin_start_index, direct.to_clb_pin_end_index); - - /* Check bandwidth match between from_clb and to_clb pins */ - if (src_clb_port.get_width() != des_clb_port.get_width()) { - vpr_printf(TIO_MESSAGE_ERROR, - "(File:%s, [LINE%d]) Unmatch pin bandwidth in direct connection (name=%s)!\n", - __FILE__, __LINE__, direct.name); - exit(1); - } - - /* Find the module name of source clb */ - t_type_ptr src_grid_type = grids[src_clb_coord.x()][src_clb_coord.y()].type; - e_side src_grid_border_side = find_grid_border_side(device_size, src_clb_coord); - std::string src_module_name_prefix(grid_verilog_file_name_prefix); - std::string src_module_name = generate_grid_block_module_name(src_module_name_prefix, std::string(src_grid_type->name), IO_TYPE == src_grid_type, src_grid_border_side); - ModuleId src_grid_module = module_manager.find_module(src_module_name); - VTR_ASSERT(true == module_manager.valid_module_id(src_grid_module)); - /* Record the instance id */ - size_t src_grid_instance = grid_instance_ids[src_clb_coord.x()][src_clb_coord.y()]; - - /* Find the module name of sink clb */ - t_type_ptr sink_grid_type = grids[des_clb_coord.x()][des_clb_coord.y()].type; - e_side sink_grid_border_side = find_grid_border_side(device_size, des_clb_coord); - std::string sink_module_name_prefix(grid_verilog_file_name_prefix); - std::string sink_module_name = generate_grid_block_module_name(sink_module_name_prefix, std::string(sink_grid_type->name), IO_TYPE == sink_grid_type, sink_grid_border_side); - ModuleId sink_grid_module = module_manager.find_module(sink_module_name); - VTR_ASSERT(true == module_manager.valid_module_id(sink_grid_module)); - /* Record the instance id */ - size_t sink_grid_instance = grid_instance_ids[des_clb_coord.x()][des_clb_coord.y()]; - - /* Find the module id of a direct connection module */ - std::string direct_module_name = circuit_lib.model_name(direct.circuit_model); - ModuleId direct_module = module_manager.find_module(direct_module_name); - VTR_ASSERT(true == module_manager.valid_module_id(direct_module)); - - /* Find inputs and outputs of the direct circuit module */ - std::vector direct_input_ports = circuit_lib.model_ports_by_type(direct.circuit_model, SPICE_MODEL_PORT_INPUT, true); - VTR_ASSERT(1 == direct_input_ports.size()); - ModulePortId direct_input_port_id = module_manager.find_module_port(direct_module, circuit_lib.port_lib_name(direct_input_ports[0])); - VTR_ASSERT(true == module_manager.valid_module_port_id(direct_module, direct_input_port_id)); - VTR_ASSERT(1 == module_manager.module_port(direct_module, direct_input_port_id).get_width()); - - std::vector direct_output_ports = circuit_lib.model_ports_by_type(direct.circuit_model, SPICE_MODEL_PORT_OUTPUT, true); - VTR_ASSERT(1 == direct_output_ports.size()); - ModulePortId direct_output_port_id = module_manager.find_module_port(direct_module, circuit_lib.port_lib_name(direct_output_ports[0])); - VTR_ASSERT(true == module_manager.valid_module_port_id(direct_module, direct_output_port_id)); - VTR_ASSERT(1 == module_manager.module_port(direct_module, direct_output_port_id).get_width()); - - for (size_t pin_id : src_clb_port.pins()) { - /* Generate the pin name of source port/pin in the grid */ - size_t src_pin_height = find_grid_pin_height(grids, src_clb_coord, src_clb_port.pins()[pin_id]); - e_side src_pin_grid_side = find_grid_pin_side(device_size, grids, src_clb_coord, src_pin_height, src_clb_port.pins()[pin_id]); - std::string src_port_name = generate_grid_port_name(src_clb_coord, src_pin_height, src_pin_grid_side, src_clb_port.pins()[pin_id], false); - ModulePortId src_port_id = module_manager.find_module_port(src_grid_module, src_port_name); - VTR_ASSERT(true == module_manager.valid_module_port_id(src_grid_module, src_port_id)); - VTR_ASSERT(1 == module_manager.module_port(src_grid_module, src_port_id).get_width()); - - /* Generate the pin name of sink port/pin in the grid */ - size_t sink_pin_height = find_grid_pin_height(grids, des_clb_coord, des_clb_port.pins()[pin_id]); - e_side sink_pin_grid_side = find_grid_pin_side(device_size, grids, des_clb_coord, sink_pin_height, des_clb_port.pins()[pin_id]); - std::string sink_port_name = generate_grid_port_name(des_clb_coord, sink_pin_height, sink_pin_grid_side, des_clb_port.pins()[pin_id], false); - ModulePortId sink_port_id = module_manager.find_module_port(sink_grid_module, sink_port_name); - VTR_ASSERT(true == module_manager.valid_module_port_id(sink_grid_module, sink_port_id)); - VTR_ASSERT(1 == module_manager.module_port(sink_grid_module, sink_port_id).get_width()); - - /* Add a submodule of direct connection module to the top-level module */ - size_t direct_instance_id = module_manager.num_instance(top_module, direct_module); - module_manager.add_child_module(top_module, direct_module); - - /* Create the 1st module net */ - ModuleNetId net_direct_src = module_manager.create_module_net(top_module); - /* Connect the wire between src_pin of clb and direct_instance input*/ - module_manager.add_module_net_source(top_module, net_direct_src, src_grid_module, src_grid_instance, src_port_id, 0); - module_manager.add_module_net_sink(top_module, net_direct_src, direct_module, direct_instance_id, direct_input_port_id, 0); - - /* Create the 2nd module net */ - ModuleNetId net_direct_sink = module_manager.create_module_net(top_module); - /* Connect the wire between direct_instance output and sink_pin of clb */ - module_manager.add_module_net_source(top_module, net_direct_sink, direct_module, direct_instance_id, direct_output_port_id, 0); - module_manager.add_module_net_sink(top_module, net_direct_sink, sink_grid_module, sink_grid_instance, sink_port_id, 0); - } -} - -/******************************************************************** - * Add module net of clb-to-clb direct connections to module manager - * Note that the direct connections are not limited to CLBs only. - * It can be more generic and thus cover all the grid types, - * such as heterogeneous blocks - * - * This function supports the following type of direct connection: - * 1. Direct connection between grids in the same column or row - * +------+ +------+ - * | | | | - * | Grid |----->| Grid | - * | | | | - * +------+ +------+ - * | direction connection - * v - * +------+ - * | | - * | Grid | - * | | - * +------+ - * - *******************************************************************/ -static -void add_top_module_nets_intra_clb2clb_direct_connections(ModuleManager& module_manager, - const ModuleId& top_module, - const CircuitLibrary& circuit_lib, - const vtr::Point& device_size, - const std::vector>& grids, - const std::vector>& grid_instance_ids, - const std::vector& clb2clb_directs) { - /* Scan the grid, visit each grid and apply direct connections */ - for (size_t ix = 0; ix < device_size.x(); ++ix) { - for (size_t iy = 0; iy < device_size.y(); ++iy) { - /* Bypass EMPTY_TYPE*/ - if ( (NULL == grids[ix][iy].type) - || (EMPTY_TYPE == grids[ix][iy].type)) { - continue; - } - /* Bypass any grid with a non-zero offset! They have been visited in the offset=0 case */ - if (0 != grids[ix][iy].offset) { - continue; - } - /* Check each clb2clb directs by comparing the source and destination clb types - * Direct connections are made only for those matched clbs - */ - for (const t_clb_to_clb_directs& direct : clb2clb_directs) { - /* Bypass unmatched clb type */ - if (grids[ix][iy].type != direct.from_clb_type) { - continue; - } - - /* See if the destination CLB is in the bound */ - vtr::Point src_clb_coord(ix, iy); - vtr::Point des_clb_coord(ix + direct.x_offset, iy + direct.y_offset); - if (false == is_grid_coordinate_exist_in_device(device_size, des_clb_coord)) { - continue; - } - - /* Check if the destination clb_type matches */ - if (grids[des_clb_coord.x()][des_clb_coord.y()].type == direct.to_clb_type) { - /* Add a module net for a direct connection with the two grids in top_model */ - add_module_nets_clb2clb_direct_connection(module_manager, top_module, circuit_lib, - device_size, grids, grid_instance_ids, - src_clb_coord, des_clb_coord, - direct); - } - } - } - } -} - -/******************************************************************** - * Find the coordinate of a grid in a specific column - * with a given type - * This function will return the coordinate of the grid that satifies - * the type requirement - *******************************************************************/ -static -vtr::Point find_grid_coordinate_given_type(const vtr::Point& device_size, - const std::vector>& grids, - const std::vector>& candidate_coords, - t_type_ptr wanted_grid_type) { - for (vtr::Point coord : candidate_coords) { - /* If the next column is not longer in device range, we can return */ - if (false == is_grid_coordinate_exist_in_device(device_size, coord)) { - continue; - } - if (wanted_grid_type == grids[coord.x()][coord.y()].type) { - return coord; - } - } - /* Return an valid coordinate */ - return vtr::Point(size_t(-1), size_t(-1)); -} - -/******************************************************************** - * Find the coordinate of the destination clb/heterogeneous block - * considering intra column/row direct connections in core grids - *******************************************************************/ -static -vtr::Point find_intra_direct_destination_coordinate(const vtr::Point& device_size, - const std::vector>& grids, - const vtr::Point src_coord, - const t_clb_to_clb_directs& direct) { - vtr::Point des_coord(size_t(-1), size_t(-1)); - t_type_ptr src_grid_type = grids[src_coord.x()][src_coord.y()].type; - - std::vector first_search_space; - std::vector second_search_space; - - /* Cross column connection from Bottom to Top on Right - * The next column may NOT have the grid type we want! - * Think about heterogeneous architecture! - * Our search space will start from the next column - * and ends at the RIGHT side of fabric - */ - if (P2P_DIRECT_COLUMN == direct.interconnection_type) { - if (POSITIVE_DIR == direct.x_dir) { - /* Our first search space will be in x-direction: - * - * x ... nx - * +-----+ - * |Grid | -----> - * +-----+ - */ - for (size_t ix = src_coord.x() + 1; ix < device_size.x() - 1; ++ix) { - first_search_space.push_back(ix); - } - } else { - VTR_ASSERT(NEGATIVE_DIR == direct.x_dir); - /* Our first search space will be in x-direction: - * - * 1 ... x - * +-----+ - * < -------|Grid | - * +-----+ - */ - for (size_t ix = src_coord.x() - 1; ix >= 1; --ix) { - first_search_space.push_back(ix); - } - } - - /* Our second search space will be in y-direction: - * - * +------+ - * | Grid | ny - * +------+ - * | . - * | . - * v . - * +------+ - * | Grid | 1 - * +------+ - */ - for (size_t iy = 1 ; iy < device_size.y() - 1; ++iy) { - second_search_space.push_back(iy); - } - - /* For negative direction, our second search space will be in y-direction: - * - * +------+ - * | Grid | ny - * +------+ - * ^ . - * | . - * | . - * +------+ - * | Grid | 1 - * +------+ - */ - if (NEGATIVE_DIR == direct.y_dir) { - std::reverse(second_search_space.begin(), second_search_space.end()); - } - } - - - /* Cross row connection from Bottom to Top on Right - * The next column may NOT have the grid type we want! - * Think about heterogeneous architecture! - * Our search space will start from the next column - * and ends at the RIGHT side of fabric - */ - if (P2P_DIRECT_ROW == direct.interconnection_type) { - if (POSITIVE_DIR == direct.y_dir) { - /* Our first search space will be in y-direction: - * - * +------+ - * | Grid | ny - * +------+ - * ^ . - * | . - * | . - * +------+ - * | Grid | y - * +------+ - */ - for (size_t iy = src_coord.y() + 1; iy < device_size.y() - 1; ++iy) { - first_search_space.push_back(iy); - } - } else { - VTR_ASSERT(NEGATIVE_DIR == direct.y_dir); - /* For negative y-direction, - * Our first search space will be in y-direction: - * - * +------+ - * | Grid | ny - * +------+ - * | . - * | . - * v . - * +------+ - * | Grid | y - * +------+ - */ - for (size_t iy = src_coord.y() - 1; iy >= 1; --iy) { - first_search_space.push_back(iy); - } - } - - /* Our second search space will be in x-direction: - * - * 1 ... nx - * +------+ +------+ - * | Grid |------>| Grid | - * +------+ +------+ - */ - for (size_t ix = 1 ; ix < device_size.x() - 1; ++ix) { - second_search_space.push_back(ix); - } - - /* For negative direction, - * our second search space will be in x-direction: - * - * 1 ... nx - * +------+ +------+ - * | Grid |<------| Grid | - * +------+ +------+ - */ - if (NEGATIVE_DIR == direct.x_dir) { - std::reverse(second_search_space.begin(), second_search_space.end()); - } - } - - for (size_t ix : first_search_space) { - std::vector> next_col_row_coords; - for (size_t iy : second_search_space) { - if (P2P_DIRECT_COLUMN == direct.interconnection_type) { - next_col_row_coords.push_back(vtr::Point(ix, iy)); - } else { - VTR_ASSERT(P2P_DIRECT_ROW == direct.interconnection_type); - /* For cross-row connection, our search space is flipped */ - next_col_row_coords.push_back(vtr::Point(iy, ix)); - } - } - vtr::Point des_coord_cand = find_grid_coordinate_given_type(device_size, grids, next_col_row_coords, src_grid_type); - /* For a valid coordinate, we can return */ - if ( (size_t(-1) != des_coord_cand.x()) - && (size_t(-1) != des_coord_cand.y()) ) { - return des_coord_cand; - } - } - return des_coord; -} - -/******************************************************************** - * Add module net of clb-to-clb direct connections to module manager - * Note that the direct connections are not limited to CLBs only. - * It can be more generic and thus cover all the grid types, - * such as heterogeneous blocks - * - * This function supports the following type of direct connection: - * - * 1. Direct connections across columns and rows - * +------+ - * | | - * | v - * +------+ | +------+ - * | | | | | - * | Grid | | | Grid | - * | | | | | - * +------+ | +------+ - * | - * +------+ | +------+ - * | | | | | - * | Grid | | | Grid | - * | | | | | - * +------+ | +------+ - * | | - * +------+ - * - * Note that: this will only apply to the core grids! - * I/Os or any blocks on the border of fabric are NOT supported! - * - *******************************************************************/ -static -void add_top_module_nets_inter_clb2clb_direct_connections(ModuleManager& module_manager, - const ModuleId& top_module, - const CircuitLibrary& circuit_lib, - const vtr::Point& device_size, - const std::vector>& grids, - const std::vector>& grid_instance_ids, - const std::vector& clb2clb_directs) { - - std::vector border_sides = {TOP, RIGHT, BOTTOM, LEFT}; - - /* Go through the direct connection list, see if we need intra-column/row connection here */ - for (const t_clb_to_clb_directs& direct: clb2clb_directs) { - if ( (P2P_DIRECT_COLUMN != direct.interconnection_type) - && (P2P_DIRECT_ROW != direct.interconnection_type)) { - continue; - } - /* For cross-column connection, we will search the first valid grid in each column - * from y = 1 to y = ny - * - * +------+ - * | Grid | y=ny - * +------+ - * ^ - * | search direction (when y_dir is negative) - * ... - * | - * +------+ - * | Grid | y=1 - * +------+ - * - */ - if (P2P_DIRECT_COLUMN == direct.interconnection_type) { - for (size_t ix = 1; ix < device_size.x() - 1; ++ix) { - std::vector> next_col_src_grid_coords; - /* For negative y- direction, we should start from y = ny */ - for (size_t iy = 1; iy < device_size.y() - 1; ++iy) { - next_col_src_grid_coords.push_back(vtr::Point(ix, iy)); - } - /* For positive y- direction, we should start from y = 1 */ - if (POSITIVE_DIR == direct.y_dir) { - std::reverse(next_col_src_grid_coords.begin(), next_col_src_grid_coords.end()); - } - vtr::Point src_clb_coord = find_grid_coordinate_given_type(device_size, grids, next_col_src_grid_coords, direct.from_clb_type); - /* Skip if we do not have a valid coordinate for source CLB/heterogeneous block */ - if ( (size_t(-1) == src_clb_coord.x()) - || (size_t(-1) == src_clb_coord.y()) ) { - continue; - } - /* For a valid coordinate, we can find the coordinate of the destination clb */ - vtr::Point des_clb_coord = find_intra_direct_destination_coordinate(device_size, grids, src_clb_coord, direct); - /* If destination clb is valid, we should add something */ - if ( (size_t(-1) == des_clb_coord.x()) - || (size_t(-1) == des_clb_coord.y()) ) { - continue; - } - add_module_nets_clb2clb_direct_connection(module_manager, top_module, circuit_lib, - device_size, grids, grid_instance_ids, - src_clb_coord, des_clb_coord, - direct); - } - continue; /* Go to next direct type */ - } - - /* Reach here, it must be a cross-row connection */ - VTR_ASSERT(P2P_DIRECT_ROW == direct.interconnection_type); - /* For cross-row connection, we will search the first valid grid in each column - * from x = 1 to x = nx - * - * x=1 x=nx - * +------+ +------+ - * | Grid | <--- ... ---- | Grid | - * +------+ +------+ - * - */ - for (size_t iy = 1; iy < device_size.y() - 1; ++iy) { - std::vector> next_col_src_grid_coords; - /* For negative x- direction, we should start from x = nx */ - for (size_t ix = 1; ix < device_size.x() - 1; ++ix) { - next_col_src_grid_coords.push_back(vtr::Point(ix, iy)); - } - /* For positive x- direction, we should start from x = 1 */ - if (POSITIVE_DIR == direct.x_dir) { - std::reverse(next_col_src_grid_coords.begin(), next_col_src_grid_coords.end()); - } - vtr::Point src_clb_coord = find_grid_coordinate_given_type(device_size, grids, next_col_src_grid_coords, direct.from_clb_type); - /* Skip if we do not have a valid coordinate for source CLB/heterogeneous block */ - if ( (size_t(-1) == src_clb_coord.x()) - || (size_t(-1) == src_clb_coord.y()) ) { - continue; - } - /* For a valid coordinate, we can find the coordinate of the destination clb */ - vtr::Point des_clb_coord = find_intra_direct_destination_coordinate(device_size, grids, src_clb_coord, direct); - /* If destination clb is valid, we should add something */ - if ( (size_t(-1) == des_clb_coord.x()) - || (size_t(-1) == des_clb_coord.y()) ) { - continue; - } - add_module_nets_clb2clb_direct_connection(module_manager, top_module, circuit_lib, - device_size, grids, grid_instance_ids, - src_clb_coord, des_clb_coord, - direct); - } - } -} - -/******************************************************************** - * Add module net of clb-to-clb direct connections to module manager - * Note that the direct connections are not limited to CLBs only. - * It can be more generic and thus cover all the grid types, - * such as heterogeneous blocks - *******************************************************************/ -static -void add_top_module_nets_clb2clb_direct_connections(ModuleManager& module_manager, - const ModuleId& top_module, - const CircuitLibrary& circuit_lib, - const vtr::Point& device_size, - const std::vector>& grids, - const std::vector>& grid_instance_ids, - const std::vector& clb2clb_directs) { - - add_top_module_nets_intra_clb2clb_direct_connections(module_manager, top_module, circuit_lib, - device_size, grids, grid_instance_ids, - clb2clb_directs); - - add_top_module_nets_inter_clb2clb_direct_connections(module_manager, top_module, circuit_lib, - device_size, grids, grid_instance_ids, - clb2clb_directs); -} - /******************************************************************** * Print the top-level module for the FPGA fabric in Verilog format * This function will @@ -1421,13 +881,21 @@ void print_verilog_top_module(ModuleManager& module_manager, std::vector memory_modules; std::vector memory_instances; - /* TODO: Add module nets to connect memory cells inside + /* Organize the list of memory modules and instances */ + organize_top_module_memory_modules(module_manager, + circuit_lib, sram_model, cur_sram_orgz_info, + device_size, grids, grid_instance_ids, + L_device_rr_gsb, sb_instance_ids, cb_instance_ids, + compact_routing_hierarchy, + memory_modules, memory_instances); + + /* Add module nets to connect memory cells inside * This is a one-shot addition that covers all the memory modules in this pb module! */ if (false == memory_modules.empty()) { - add_module_nets_memory_config_bus(module_manager, top_module, - memory_modules, memory_instances, - cur_sram_orgz_info->type, circuit_lib.design_tech_type(sram_model)); + add_top_module_nets_memory_config_bus(module_manager, top_module, + memory_modules, memory_instances, + cur_sram_orgz_info->type, circuit_lib.design_tech_type(sram_model)); } /* Start printing out Verilog netlists */