diff --git a/.github/workflows/basic_reg_test.sh b/.github/workflows/basic_reg_test.sh index b3394c424..02d5da8db 100755 --- a/.github/workflows/basic_reg_test.sh +++ b/.github/workflows/basic_reg_test.sh @@ -102,6 +102,8 @@ echo -e "Testing tiles with pins only on top and right sides"; python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/tile_organization/top_right_custom_pins --debug --show_thread_logs echo -e "Testing tiles with pins only on bottom and right sides"; python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/tile_organization/bottom_right_custom_pins --debug --show_thread_logs +echo -e "Testing tiles with I/O in center grid"; +python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/tile_organization/tileable_io --debug --show_thread_logs echo -e "Testing global port definition from tiles"; python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/global_tile_ports/global_tile_clock --debug --show_thread_logs diff --git a/openfpga/src/base/openfpga_naming.cpp b/openfpga/src/base/openfpga_naming.cpp index 2e16058c0..f6f64d39a 100644 --- a/openfpga/src/base/openfpga_naming.cpp +++ b/openfpga/src/base/openfpga_naming.cpp @@ -1003,7 +1003,7 @@ std::string generate_grid_block_netlist_name(const std::string& block_name, /* Add the name of physical block */ std::string module_name(block_name); - if (true == is_block_io) { + if ((true == is_block_io) && (NUM_SIDES != io_side)) { SideManager side_manager(io_side); module_name += std::string("_"); module_name += std::string(side_manager.to_string()); diff --git a/openfpga/src/base/openfpga_pb_pin_fixup.cpp b/openfpga/src/base/openfpga_pb_pin_fixup.cpp index 944a85c70..358ae2fb9 100644 --- a/openfpga/src/base/openfpga_pb_pin_fixup.cpp +++ b/openfpga/src/base/openfpga_pb_pin_fixup.cpp @@ -157,8 +157,6 @@ void update_pb_pin_with_post_routing_results(const DeviceContext& device_ctx, if (true == is_empty_type(device_ctx.grid[x][y].type)) { continue; } - /* We must have an regular (non-I/O) type here */ - VTR_ASSERT(false == is_io_type(device_ctx.grid[x][y].type)); /* Get the mapped blocks to this grid */ for (const ClusterBlockId& cluster_blk_id : placement_ctx.grid_blocks[x][y].blocks) { /* Skip invalid ids */ diff --git a/openfpga/src/fabric/build_fabric_io_location_map.cpp b/openfpga/src/fabric/build_fabric_io_location_map.cpp index ac63e3354..36422f44d 100644 --- a/openfpga/src/fabric/build_fabric_io_location_map.cpp +++ b/openfpga/src/fabric/build_fabric_io_location_map.cpp @@ -99,6 +99,65 @@ IoLocationMap build_fabric_io_location_map(const ModuleManager& module_manager, } } + /* Walk through all the center grids, which may include I/O grids */ + for (size_t ix = 1; ix < grids.width() - 1; ++ix) { + for (size_t iy = 1; iy < grids.height() - 1; ++iy) { + /* Bypass EMPTY grid */ + if (true == is_empty_type(grids[ix][iy].type)) { + continue; + } + + /* Skip width or height > 1 tiles (mostly heterogeneous blocks) */ + if ( (0 < grids[ix][iy].width_offset) + || (0 < grids[ix][iy].height_offset)) { + continue; + } + + t_physical_tile_type_ptr grid_type = grids[ix][iy].type; + + /* Find the module name for this type of grid */ + std::string grid_module_name_prefix(GRID_MODULE_NAME_PREFIX); + std::string grid_module_name = generate_grid_block_module_name(grid_module_name_prefix, std::string(grid_type->name), is_io_type(grid_type), NUM_SIDES); + ModuleId grid_module = module_manager.find_module(grid_module_name); + VTR_ASSERT(true == module_manager.valid_module_id(grid_module)); + + /* Find all the GPIO ports in the grid module */ + + /* MUST DO: register in io location mapping! + * I/O location mapping is a critical look-up for testbench generators + * As we add the I/O grid instances to top module by following order: + * TOP -> RIGHT -> BOTTOM -> LEFT + * The I/O index will increase in this way as well. + * This organization I/O indices is also consistent to the way + * that GPIOs are wired in function connect_gpio_module() + * + * Note: if you change the GPIO function, you should update here as well! + */ + for (int z = 0; z < grids[ix][iy].type->capacity; ++z) { + for (const ModuleManager::e_module_port_type& module_io_port_type : MODULE_IO_PORT_TYPES) { + for (const ModulePortId& gpio_port_id : module_manager.module_port_ids_by_type(grid_module, module_io_port_type)) { + /* Only care mappable I/O */ + if (false == module_manager.port_is_mappable_io(grid_module, gpio_port_id)) { + continue; + } + + const BasicPort& gpio_port = module_manager.module_port(grid_module, gpio_port_id); + + auto curr_io_index = io_counter.find(gpio_port.get_name()); + /* Index always start from zero */ + if (curr_io_index == io_counter.end()) { + io_counter[gpio_port.get_name()] = 0; + } + io_location_map.set_io_index(ix, iy, z, + gpio_port.get_name(), + io_counter[gpio_port.get_name()]); + io_counter[gpio_port.get_name()]++; + } + } + } + } + } + /* Check all the GPIO ports in the top-level module has been mapped */ std::string top_module_name = generate_fpga_top_module_name(); ModuleId top_module = module_manager.find_module(top_module_name); diff --git a/openfpga/src/fabric/build_grid_module_duplicated_pins.cpp b/openfpga/src/fabric/build_grid_module_duplicated_pins.cpp index e02bae403..3efc7b011 100644 --- a/openfpga/src/fabric/build_grid_module_duplicated_pins.cpp +++ b/openfpga/src/fabric/build_grid_module_duplicated_pins.cpp @@ -66,7 +66,7 @@ void add_grid_module_duplicated_pb_type_ports(ModuleManager& module_manager, * Otherwise, we will iterate all the 4 sides */ if (true == is_io_type(grid_type_descriptor)) { - grid_pin_sides.push_back(find_grid_module_pin_side(grid_type_descriptor, border_side)); + grid_pin_sides = find_grid_module_pin_sides(grid_type_descriptor, border_side); } else { grid_pin_sides = {TOP, RIGHT, BOTTOM, LEFT}; } @@ -147,12 +147,9 @@ void add_grid_module_net_connect_duplicated_pb_graph_pin(ModuleManager& module_m * Otherwise, we will iterate all the 4 sides */ if (true == is_io_type(grid_type_descriptor)) { - grid_pin_sides.push_back(find_grid_module_pin_side(grid_type_descriptor, border_side)); + grid_pin_sides = find_grid_module_pin_sides(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}; } /* num_pins/capacity = the number of pins that each type_descriptor has. diff --git a/openfpga/src/fabric/build_grid_module_utils.cpp b/openfpga/src/fabric/build_grid_module_utils.cpp index a61bc5f0a..60e44a435 100644 --- a/openfpga/src/fabric/build_grid_module_utils.cpp +++ b/openfpga/src/fabric/build_grid_module_utils.cpp @@ -23,13 +23,19 @@ namespace openfpga { * 2. I/O grids on the right side of FPGA only have ports on its left side * 3. I/O grids on the bottom side of FPGA only have ports on its top side * 4. I/O grids on the left side of FPGA only have ports on its right side + * 5. I/O grids in the center part of FPGA can have ports on any side *******************************************************************/ -e_side find_grid_module_pin_side(t_physical_tile_type_ptr grid_type_descriptor, - const e_side& border_side) { +std::vector find_grid_module_pin_sides(t_physical_tile_type_ptr grid_type_descriptor, + const e_side& border_side) { /* We must have an regular (non-I/O) type here */ VTR_ASSERT(true == is_io_type(grid_type_descriptor)); SideManager side_manager(border_side); - return side_manager.get_opposite(); + + if (NUM_SIDES == border_side) { + return {TOP, RIGHT, BOTTOM, LEFT}; + } + + return std::vector(1, side_manager.get_opposite()); } /******************************************************************** @@ -50,12 +56,9 @@ void add_grid_module_net_connect_pb_graph_pin(ModuleManager& module_manager, * Otherwise, we will iterate all the 4 sides */ if (true == is_io_type(grid_type_descriptor)) { - grid_pin_sides.push_back(find_grid_module_pin_side(grid_type_descriptor, border_side)); + grid_pin_sides = find_grid_module_pin_sides(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}; } /* num_pins/capacity = the number of pins that each type_descriptor has. diff --git a/openfpga/src/fabric/build_grid_module_utils.h b/openfpga/src/fabric/build_grid_module_utils.h index 654551fc5..cf7b2d2d6 100644 --- a/openfpga/src/fabric/build_grid_module_utils.h +++ b/openfpga/src/fabric/build_grid_module_utils.h @@ -17,8 +17,8 @@ /* begin namespace openfpga */ namespace openfpga { -e_side find_grid_module_pin_side(t_physical_tile_type_ptr grid_type_descriptor, - const e_side& border_side); +std::vector find_grid_module_pin_sides(t_physical_tile_type_ptr grid_type_descriptor, + const e_side& border_side); void add_grid_module_net_connect_pb_graph_pin(ModuleManager& module_manager, const ModuleId& grid_module, diff --git a/openfpga/src/fabric/build_grid_modules.cpp b/openfpga/src/fabric/build_grid_modules.cpp index 26a5ae164..f9af7d722 100644 --- a/openfpga/src/fabric/build_grid_modules.cpp +++ b/openfpga/src/fabric/build_grid_modules.cpp @@ -52,7 +52,7 @@ void add_grid_module_pb_type_ports(ModuleManager& module_manager, * Otherwise, we will iterate all the 4 sides */ if (true == is_io_type(grid_type_descriptor)) { - grid_pin_sides.push_back(find_grid_module_pin_side(grid_type_descriptor, border_side)); + grid_pin_sides = find_grid_module_pin_sides(grid_type_descriptor, border_side); } else { grid_pin_sides = {TOP, RIGHT, BOTTOM, LEFT}; } @@ -981,11 +981,6 @@ void build_physical_tile_module(ModuleManager& module_manager, const e_side& border_side, const bool& duplicate_grid_pin, const bool& verbose) { - /* Check code: if this is an IO block, the border side MUST be valid */ - if (true == is_io_type(phy_block_type)) { - VTR_ASSERT(NUM_SIDES != border_side); - } - /* Create a 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_MODULE_NAME_PREFIX), std::string(phy_block_type->name), diff --git a/openfpga/src/fabric/build_top_module.cpp b/openfpga/src/fabric/build_top_module.cpp index 5d2d87aaa..568dd9e37 100644 --- a/openfpga/src/fabric/build_top_module.cpp +++ b/openfpga/src/fabric/build_top_module.cpp @@ -120,8 +120,6 @@ vtr::Matrix add_top_module_grid_instances(ModuleManager& module_manager, grid_instance_ids[ix][iy] = grid_instance_ids[root_grid_coord.x()][root_grid_coord.y()]; continue; } - /* We should not meet any I/O grid */ - VTR_ASSERT(false == is_io_type(grids[ix][iy].type)); /* Add a grid module to top_module*/ vtr::Point grid_coord(ix, iy); grid_instance_ids[ix][iy] = add_top_module_grid_instance(module_manager, top_module, diff --git a/openfpga/src/fpga_bitstream/build_grid_bitstream.cpp b/openfpga/src/fpga_bitstream/build_grid_bitstream.cpp index 9cc8753a7..3397be4b8 100644 --- a/openfpga/src/fpga_bitstream/build_grid_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/build_grid_bitstream.cpp @@ -710,8 +710,6 @@ void build_grid_bitstream(BitstreamManager& bitstream_manager, || (0 < grids[ix][iy].height_offset) ) { continue; } - /* We should not meet any I/O grid */ - VTR_ASSERT(true != is_io_type(grids[ix][iy].type)); /* Add a grid module to top_module*/ vtr::Point grid_coord(ix, iy); build_physical_block_bitstream(bitstream_manager, top_block, module_manager, diff --git a/openfpga/src/fpga_bitstream/build_routing_bitstream.cpp b/openfpga/src/fpga_bitstream/build_routing_bitstream.cpp index 012222369..de21fe52a 100644 --- a/openfpga/src/fpga_bitstream/build_routing_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/build_routing_bitstream.cpp @@ -463,6 +463,11 @@ void build_connection_block_bitstreams(BitstreamManager& bitstream_manager, ModuleId cb_module = module_manager.find_module(cb_module_name); VTR_ASSERT(true == module_manager.valid_module_id(cb_module)); + /* Bypass empty blocks which have none configurable children */ + if (0 == count_module_manager_module_configurable_children(module_manager, cb_module)) { + continue; + } + /* Create a block for the bitstream which corresponds to the Switch block */ ConfigBlockId cb_configurable_block = bitstream_manager.add_block(generate_connection_block_module_name(cb_type, cb_coord)); /* Set switch block as a child of top block */ @@ -530,6 +535,11 @@ void build_routing_bitstream(BitstreamManager& bitstream_manager, ModuleId sb_module = module_manager.find_module(sb_module_name); VTR_ASSERT(true == module_manager.valid_module_id(sb_module)); + /* Bypass empty blocks which have none configurable children */ + if (0 == count_module_manager_module_configurable_children(module_manager, sb_module)) { + continue; + } + /* Create a block for the bitstream which corresponds to the Switch block */ ConfigBlockId sb_configurable_block = bitstream_manager.add_block(generate_switch_block_module_name(sb_coord)); /* Set switch block as a child of top block */ diff --git a/openfpga/src/fpga_sdc/analysis_sdc_grid_writer.cpp b/openfpga/src/fpga_sdc/analysis_sdc_grid_writer.cpp index a49b2c85b..bb65f3757 100644 --- a/openfpga/src/fpga_sdc/analysis_sdc_grid_writer.cpp +++ b/openfpga/src/fpga_sdc/analysis_sdc_grid_writer.cpp @@ -618,9 +618,6 @@ void print_analysis_sdc_disable_unused_grids(std::fstream& fp, /* Process unused core grids */ for (size_t ix = 1; ix < grids.width() - 1; ++ix) { for (size_t iy = 1; iy < grids.height() - 1; ++iy) { - /* We should not meet any I/O grid */ - VTR_ASSERT(false == is_io_type(grids[ix][iy].type)); - print_analysis_sdc_disable_unused_grid(fp, vtr::Point(ix, iy), grids, device_annotation, cluster_annotation, place_annotation, module_manager, NUM_SIDES); diff --git a/openfpga/src/fpga_verilog/verilog_grid.cpp b/openfpga/src/fpga_verilog/verilog_grid.cpp index 35af744e6..ff7f7433e 100644 --- a/openfpga/src/fpga_verilog/verilog_grid.cpp +++ b/openfpga/src/fpga_verilog/verilog_grid.cpp @@ -286,11 +286,6 @@ void print_verilog_physical_tile_netlist(NetlistManager& netlist_manager, t_physical_tile_type_ptr phy_block_type, const e_side& border_side, const bool& use_explicit_mapping) { - /* Check code: if this is an IO block, the border side MUST be valid */ - if (true == is_io_type(phy_block_type)) { - VTR_ASSERT(NUM_SIDES != border_side); - } - /* Give a name to the Verilog netlist */ /* Create the file name for Verilog */ std::string verilog_fname(subckt_dir diff --git a/openfpga_flow/tasks/basic_tests/tile_organization/tileable_io/config/task.conf b/openfpga_flow/tasks/basic_tests/tile_organization/tileable_io/config/task.conf new file mode 100644 index 000000000..226faeda1 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/tile_organization/tileable_io/config/task.conf @@ -0,0 +1,36 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# Configuration file for running experiments +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs +# Each job execute fpga_flow script on combination of architecture & benchmark +# timeout_each_job is timeout for each job +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + +[GENERAL] +run_engine=openfpga_shell +power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml +power_analysis = true +spice_output=false +verilog_output=true +timeout_each_job = 20*60 +fpga_flow=yosys_vpr + +[OpenFPGA_SHELL] +openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/fix_device_example_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_frame_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml +openfpga_vpr_device_layout=2x2 + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileableIO_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/or2/or2.v + +[SYNTHESIS_PARAM] +bench0_top = or2 +bench0_chan_width = 300 + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= +vpr_fpga_verilog_formal_verification_top_netlist= diff --git a/openfpga_flow/vpr_arch/README.md b/openfpga_flow/vpr_arch/README.md index 9ff6903e0..4ab3a92e4 100644 --- a/openfpga_flow/vpr_arch/README.md +++ b/openfpga_flow/vpr_arch/README.md @@ -5,7 +5,8 @@ Please reveal the following architecture features in the names to help quickly s * The keyword 'frac' is to specify if fracturable LUT is used or not. * The keyword 'Native' is to specify if fracturable LUT design is a native one (without mode switch) or a standard one (with mode switch). - N: Number of logic elements for a CLB. If you have multiple CLB architectures, this should be largest number. -- tileable: If the routing architecture is tileable or not. +- tileable: If the routing architecture is tileable or not. + * The keyword 'IO' specifies if the I/O tile is tileable or not - adder\_chain: If hard adder/carry chain is used inside CLBs - register\_chain: If shift register chain is used inside CLBs - scan\_chain: If scan chain testing infrastructure is used inside CLBs diff --git a/openfpga_flow/vpr_arch/k4_N4_tileableIO_40nm.xml b/openfpga_flow/vpr_arch/k4_N4_tileableIO_40nm.xml new file mode 100644 index 000000000..97ffe88aa --- /dev/null +++ b/openfpga_flow/vpr_arch/k4_N4_tileableIO_40nm.xml @@ -0,0 +1,293 @@ + + + + + + + + + + + + + + + + + + + + + + + + io.outpad + io.inpad + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 1 1 1 1 + 1 1 1 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 261e-12 + 261e-12 + 261e-12 + 261e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/vpr/src/tileable_rr_graph/rr_graph_builder_utils.cpp b/vpr/src/tileable_rr_graph/rr_graph_builder_utils.cpp index 3bf54a6d5..f50c22f14 100644 --- a/vpr/src/tileable_rr_graph/rr_graph_builder_utils.cpp +++ b/vpr/src/tileable_rr_graph/rr_graph_builder_utils.cpp @@ -52,11 +52,15 @@ e_side determine_io_grid_pin_side(const vtr::Point& device_size, return TOP; /* Such I/O has only Top side pins */ } else if (0 == grid_coordinate.x()) { /* LEFT side IO of FPGA */ return RIGHT; /* Such I/O has only Right side pins */ - } else { - VTR_LOGF_ERROR(__FILE__, __LINE__, - "I/O Grid is in the center part of FPGA! Currently unsupported!\n"); - exit(1); + } else if ((grid_coordinate.x() < device_size.x()) && (grid_coordinate.y() < device_size.y())) { + /* I/O grid in the center grid */ + return NUM_SIDES; } + VTR_LOGF_ERROR(__FILE__, __LINE__, + "Invalid coordinate (%lu, %lu) for I/O Grid whose size is (%lu, %lu)!\n", + grid_coordinate.x(), grid_coordinate.y(), + device_size.x(), device_size.y()); + exit(1); } /* Deteremine the side of a pin of a grid */ @@ -111,7 +115,7 @@ size_t get_grid_num_pins(const t_grid_tile& cur_grid, for (const e_side& side : {TOP, RIGHT, BOTTOM, LEFT}) { /* skip unwanted sides */ if ( (true == is_io_type(cur_grid.type)) - && (side != io_side) ) { + && (side != io_side) && (NUM_SIDES != io_side)) { continue; } /* Get pin list */ diff --git a/vpr/src/tileable_rr_graph/tileable_rr_graph_node_builder.cpp b/vpr/src/tileable_rr_graph/tileable_rr_graph_node_builder.cpp index 3e9004175..3ccdbc64c 100644 --- a/vpr/src/tileable_rr_graph/tileable_rr_graph_node_builder.cpp +++ b/vpr/src/tileable_rr_graph/tileable_rr_graph_node_builder.cpp @@ -379,7 +379,7 @@ void load_one_grid_opin_nodes_basic_info(RRGraph& rr_graph, SideManager side_manager(side); /* skip unwanted sides */ if ( (true == is_io_type(cur_grid.type)) - && (side != io_side_manager.to_size_t()) ) { + && (side != io_side_manager.to_size_t()) && (NUM_SIDES != io_side) ) { continue; } /* Find OPINs */ @@ -442,7 +442,7 @@ void load_one_grid_ipin_nodes_basic_info(RRGraph& rr_graph, SideManager side_manager(side); /* skip unwanted sides */ if ( (true == is_io_type(cur_grid.type)) - && (side != io_side_manager.to_size_t()) ) { + && (side != io_side_manager.to_size_t()) && (NUM_SIDES != io_side) ) { continue; }