diff --git a/openfpga/src/fabric/build_device_module.cpp b/openfpga/src/fabric/build_device_module.cpp index f38103c8f..0ba0dd167 100644 --- a/openfpga/src/fabric/build_device_module.cpp +++ b/openfpga/src/fabric/build_device_module.cpp @@ -127,8 +127,8 @@ int build_device_module_graph( openfpga_ctx.arch().tile_annotations, vpr_device_ctx.rr_graph, openfpga_ctx.device_rr_gsb(), openfpga_ctx.tile_direct(), openfpga_ctx.arch().arch_direct, openfpga_ctx.arch().config_protocol, - sram_model, frame_view, compress_routing, duplicate_grid_pin, fabric_key, - generate_random_fabric_key); + sram_model, fabric_tile, frame_view, compress_routing, duplicate_grid_pin, + fabric_key, generate_random_fabric_key); if (CMD_EXEC_FATAL_ERROR == status) { return status; diff --git a/openfpga/src/fabric/build_top_module.cpp b/openfpga/src/fabric/build_top_module.cpp index b6525bc9f..745385cdf 100644 --- a/openfpga/src/fabric/build_top_module.cpp +++ b/openfpga/src/fabric/build_top_module.cpp @@ -537,6 +537,132 @@ static int build_top_module_fine_grained_child_instances( return CMD_EXEC_SUCCESS; } +/******************************************************************** + * Add a instance of a tile module to the top module + *******************************************************************/ +static size_t add_top_module_tile_instance(ModuleManager& module_manager, + const ModuleId& top_module, + const FabricTile& fabric_tile, + const FabricTileId& fabric_tile_id) { + /* Find the module name for this type of grid */ + vtr::Point tile_coord = fabric_tile.tile_coordinate(fabric_tile_id); + FabricTileId unique_fabric_tile_id = fabric_tile.unique_tile(tile_coord); + vtr::Point unique_tile_coord = + fabric_tile.tile_coordinate(unique_fabric_tile_id); + std::string tile_module_name = generate_tile_module_name(unique_tile_coord); + ModuleId tile_module = module_manager.find_module(tile_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(tile_module)); + /* Record the instance id */ + size_t tile_instance = module_manager.num_instance(top_module, tile_module); + /* Add the module to top_module */ + module_manager.add_child_module(top_module, tile_module, false); + /* Set an unique name to the instance + * Note: it is your risk to gurantee the name is unique! + */ + std::string instance_name = generate_tile_module_name(tile_coord); + module_manager.set_child_instance_name(top_module, tile_module, tile_instance, + instance_name); + return tile_instance; +} + +/******************************************************************** + * Add all the tiles as sub-modules across the fabric + * Here, we will iterate over the full fabric (coordinates) + * and instanciate the tile 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 tiles | + * | TOP side | + * +-----------------------------------+ + * + * +-----------+ +-----------------------------------+ +------------+ + * | | | | | | + * | I/O tiles | | Core tiles | | I/O tiles | + * | LEFT side | | (CLB, Heterogeneous blocks, etc.) | | RIGHT side | + * | | | | | | + * +-----------+ +-----------------------------------+ +------------+ + * + * +-----------------------------------+ + * | I/O tiles | + * | BOTTOM side | + * +-----------------------------------+ + * + *******************************************************************/ +static int add_top_module_tile_instances(ModuleManager& module_manager, + const ModuleId& top_module, + vtr::Matrix& tile_instance_ids, + const DeviceGrid& grids, + const FabricTile& fabric_tile) { + vtr::ScopedStartFinishTimer timer("Add tile instances to top module"); + int status = CMD_EXEC_SUCCESS; + + /* Reserve an array for the instance ids */ + tile_instance_ids.resize({grids.width(), grids.height()}); + tile_instance_ids.fill(size_t(-1)); + + /* Instanciate I/O grids */ + /* Create the coordinate range for each side of FPGA fabric */ + std::map>> io_coordinates = + generate_perimeter_tile_coordinates(grids); + + for (const e_side& io_side : FPGA_SIDES_CLOCKWISE) { + for (const vtr::Point& io_coord : io_coordinates[io_side]) { + FabricTileId fabric_tile_id = fabric_tile.find_tile(io_coord); + if (!fabric_tile.valid_tile_id(fabric_tile_id)) { + continue; + } + /* Add a tile module to top_module*/ + tile_instance_ids[io_coord.x()][io_coord.y()] = + add_top_module_tile_instance(module_manager, top_module, fabric_tile, + fabric_tile_id); + } + } + + /* Instanciate core grids + * IMPORTANT: sequence matters here, it impacts the I/O indexing. + * We should follow the same sequence as the build_io_location_map()! + * If you change the sequence of walking through grids here, you should change + * it in the build_io_location map()! + */ + for (size_t ix = 1; ix < grids.width() - 1; ++ix) { + for (size_t iy = 1; iy < grids.height() - 1; ++iy) { + vtr::Point curr_coord(ix, iy); + FabricTileId fabric_tile_id = fabric_tile.find_tile(curr_coord); + if (!fabric_tile.valid_tile_id(fabric_tile_id)) { + continue; + } + /* Add a tile module to top_module*/ + tile_instance_ids[curr_coord.x()][curr_coord.y()] = + add_top_module_tile_instance(module_manager, top_module, fabric_tile, + fabric_tile_id); + } + } + return status; +} + +/******************************************************************** + * Add the tile-level instances to the top module of FPGA fabric + * and build connects between them + *******************************************************************/ +static int build_top_module_tile_child_instances( + ModuleManager& module_manager, const ModuleId& top_module, + const DeviceGrid& grids, const FabricTile& fabric_tile) { + int status = CMD_EXEC_SUCCESS; + vtr::Matrix tile_instance_ids; + status = add_top_module_tile_instances(module_manager, top_module, + tile_instance_ids, grids, fabric_tile); + if (status != CMD_EXEC_SUCCESS) { + return CMD_EXEC_FATAL_ERROR; + } + return CMD_EXEC_SUCCESS; +} + /******************************************************************** * Print the top-level module for the FPGA fabric in Verilog format * This function will @@ -557,9 +683,10 @@ int build_top_module( const TileAnnotation& tile_annotation, const RRGraphView& rr_graph, const DeviceRRGSB& device_rr_gsb, const TileDirect& tile_direct, const ArchDirect& arch_direct, const ConfigProtocol& config_protocol, - const CircuitModelId& sram_model, const bool& frame_view, - const bool& compact_routing_hierarchy, const bool& duplicate_grid_pin, - const FabricKey& fabric_key, const bool& generate_random_fabric_key) { + const CircuitModelId& sram_model, const FabricTile& fabric_tile, + const bool& frame_view, const bool& compact_routing_hierarchy, + const bool& duplicate_grid_pin, const FabricKey& fabric_key, + const bool& generate_random_fabric_key) { vtr::ScopedStartFinishTimer timer("Build FPGA fabric module"); int status = CMD_EXEC_SUCCESS; @@ -572,11 +699,18 @@ int build_top_module( /* Label module usage */ module_manager.set_module_usage(top_module, ModuleManager::MODULE_TOP); - status = build_top_module_fine_grained_child_instances( - module_manager, top_module, blwl_sr_banks, circuit_lib, clk_ntwk, - rr_clock_lookup, vpr_device_annotation, grids, tile_annotation, rr_graph, - device_rr_gsb, tile_direct, arch_direct, config_protocol, sram_model, - frame_view, compact_routing_hierarchy, duplicate_grid_pin, fabric_key); + if (fabric_tile.empty()) { + status = build_top_module_fine_grained_child_instances( + module_manager, top_module, blwl_sr_banks, circuit_lib, clk_ntwk, + rr_clock_lookup, vpr_device_annotation, grids, tile_annotation, rr_graph, + device_rr_gsb, tile_direct, arch_direct, config_protocol, sram_model, + frame_view, compact_routing_hierarchy, duplicate_grid_pin, fabric_key); + } else { + /* TODO: Build the tile instances under the top module */ + status = build_top_module_tile_child_instances(module_manager, top_module, + grids, fabric_tile); + } + if (status != CMD_EXEC_SUCCESS) { return CMD_EXEC_FATAL_ERROR; } diff --git a/openfpga/src/fabric/build_top_module.h b/openfpga/src/fabric/build_top_module.h index 9a4fb8fe0..dbee3d6cd 100644 --- a/openfpga/src/fabric/build_top_module.h +++ b/openfpga/src/fabric/build_top_module.h @@ -15,6 +15,7 @@ #include "device_grid.h" #include "device_rr_gsb.h" #include "fabric_key.h" +#include "fabric_tile.h" #include "memory_bank_shift_register_banks.h" #include "module_manager.h" #include "rr_clock_spatial_lookup.h" @@ -40,9 +41,10 @@ int build_top_module( const TileAnnotation& tile_annotation, const RRGraphView& rr_graph, const DeviceRRGSB& device_rr_gsb, const TileDirect& tile_direct, const ArchDirect& arch_direct, const ConfigProtocol& config_protocol, - const CircuitModelId& sram_model, const bool& frame_view, - const bool& compact_routing_hierarchy, const bool& duplicate_grid_pin, - const FabricKey& fabric_key, const bool& generate_random_fabric_key); + const CircuitModelId& sram_model, const FabricTile& fabric_tile, + const bool& frame_view, const bool& compact_routing_hierarchy, + const bool& duplicate_grid_pin, const FabricKey& fabric_key, + const bool& generate_random_fabric_key); } /* end namespace openfpga */ diff --git a/openfpga/src/utils/openfpga_device_grid_utils.cpp b/openfpga/src/utils/openfpga_device_grid_utils.cpp index 5a234b60d..01437f48f 100644 --- a/openfpga/src/utils/openfpga_device_grid_utils.cpp +++ b/openfpga/src/utils/openfpga_device_grid_utils.cpp @@ -61,4 +61,63 @@ generate_perimeter_grid_coordinates(const DeviceGrid& grids) { return io_coordinates; } +/******************************************************************** + * Create a list of the coordinates for the tiles on the device perimeter + * It follows a clockwise sequence when including the coordinates. + * Note that different from the function for grids, this function include corner + *tiles! Detailed sequence is as follows: + * - Top-left + * - TOP side, from left most to the right + * - Top-right + * - Right side, from top to the bottom + * - Bottom-right + * - Bottom side, from right to the left + * - Bottom-left + * - Left side, from bottom to top + * + * Note: + * - This function offers a standard sequence to walk through the + * grids on the perimeter of an FPGA device + * When sequence matters, this function should be used to ensure + * consistency between functions. + *******************************************************************/ +std::map>> +generate_perimeter_tile_coordinates(const DeviceGrid& grids) { + /* Search the border side */ + /* Create the coordinate range for each side of FPGA fabric */ + std::vector fpga_sides{TOP, RIGHT, BOTTOM, LEFT}; + std::map>> io_coordinates; + + /* Top-left */ + io_coordinates[TOP].push_back(vtr::Point(0, grids.height() - 1)); + /* TOP side*/ + for (size_t ix = 1; ix < grids.width() - 1; ++ix) { + io_coordinates[TOP].push_back(vtr::Point(ix, grids.height() - 1)); + } + + /* Top-Right */ + io_coordinates[RIGHT].push_back( + vtr::Point(grids.width() - 1, grids.height() - 1)); + /* RIGHT side */ + for (size_t iy = grids.height() - 2; iy > 0; --iy) { + io_coordinates[RIGHT].push_back(vtr::Point(grids.width() - 1, iy)); + } + + /* Bottom-right */ + io_coordinates[BOTTOM].push_back(vtr::Point(grids.width() - 1, 0)); + /* BOTTOM side*/ + for (size_t ix = grids.width() - 2; ix > 0; --ix) { + io_coordinates[BOTTOM].push_back(vtr::Point(ix, 0)); + } + + /* Bottom-left */ + io_coordinates[BOTTOM].push_back(vtr::Point(0, 0)); + /* LEFT side */ + for (size_t iy = 1; iy < grids.height() - 1; ++iy) { + io_coordinates[LEFT].push_back(vtr::Point(0, iy)); + } + + return io_coordinates; +} + } /* end namespace openfpga */ diff --git a/openfpga/src/utils/openfpga_device_grid_utils.h b/openfpga/src/utils/openfpga_device_grid_utils.h index 4b49be150..6489e3be4 100644 --- a/openfpga/src/utils/openfpga_device_grid_utils.h +++ b/openfpga/src/utils/openfpga_device_grid_utils.h @@ -24,6 +24,9 @@ constexpr std::array FPGA_SIDES_CLOCKWISE{TOP, RIGHT, BOTTOM, LEFT}; std::map>> generate_perimeter_grid_coordinates(const DeviceGrid& grids); +std::map>> +generate_perimeter_tile_coordinates(const DeviceGrid& grids); + } /* end namespace openfpga */ #endif