diff --git a/openfpga/src/base/openfpga_link_arch.cpp b/openfpga/src/base/openfpga_link_arch.cpp index 7ee522b6a..567ad2e08 100644 --- a/openfpga/src/base/openfpga_link_arch.cpp +++ b/openfpga/src/base/openfpga_link_arch.cpp @@ -53,7 +53,7 @@ bool is_vpr_rr_graph_supported(const RRGraph& rr_graph) { * - physical pb_graph nodes and pb_graph pins * - circuit models for global routing architecture *******************************************************************/ -void link_arch(OpenfpgaContext& openfpga_context, +void link_arch(OpenfpgaContext& openfpga_ctx, const Command& cmd, const CommandContext& cmd_context) { vtr::ScopedStartFinishTimer timer("Link OpenFPGA architecture to VPR architecture"); @@ -65,8 +65,8 @@ void link_arch(OpenfpgaContext& openfpga_context, * - mode selection bits for pb_type and pb interconnect * - circuit models for pb_type and pb interconnect */ - annotate_pb_types(g_vpr_ctx.device(), openfpga_context.arch(), - openfpga_context.mutable_vpr_device_annotation(), + annotate_pb_types(g_vpr_ctx.device(), openfpga_ctx.arch(), + openfpga_ctx.mutable_vpr_device_annotation(), cmd_context.option_enable(cmd, opt_verbose)); /* Annotate pb_graph_nodes @@ -75,21 +75,21 @@ void link_arch(OpenfpgaContext& openfpga_context, * - Bind pins from operating pb_graph_node to their physical pb_graph_node pins */ annotate_pb_graph(g_vpr_ctx.device(), - openfpga_context.mutable_vpr_device_annotation(), + openfpga_ctx.mutable_vpr_device_annotation(), cmd_context.option_enable(cmd, opt_verbose)); /* Annotate routing architecture to circuit library */ annotate_rr_graph_circuit_models(g_vpr_ctx.device(), - openfpga_context.arch(), - openfpga_context.mutable_vpr_device_annotation(), + openfpga_ctx.arch(), + openfpga_ctx.mutable_vpr_device_annotation(), cmd_context.option_enable(cmd, opt_verbose)); /* Annotate net mapping to each rr_node */ - openfpga_context.mutable_vpr_routing_annotation().init(g_vpr_ctx.device().rr_graph); + openfpga_ctx.mutable_vpr_routing_annotation().init(g_vpr_ctx.device().rr_graph); annotate_rr_node_nets(g_vpr_ctx.device(), g_vpr_ctx.clustering(), g_vpr_ctx.routing(), - openfpga_context.mutable_vpr_routing_annotation(), + openfpga_ctx.mutable_vpr_routing_annotation(), cmd_context.option_enable(cmd, opt_verbose)); /* Build the routing graph annotation @@ -101,17 +101,16 @@ void link_arch(OpenfpgaContext& openfpga_context, } annotate_device_rr_gsb(g_vpr_ctx.device(), - openfpga_context.mutable_device_rr_gsb(), + openfpga_ctx.mutable_device_rr_gsb(), cmd_context.option_enable(cmd, opt_verbose)); /* Build multiplexer library */ - openfpga_context.mutable_mux_lib() = build_device_mux_library(g_vpr_ctx.device(), - const_cast(openfpga_context)); + openfpga_ctx.mutable_mux_lib() = build_device_mux_library(g_vpr_ctx.device(), + const_cast(openfpga_ctx)); /* Build tile direct annotation */ - openfpga_context.mutable_tile_direct() = build_device_tile_direct(g_vpr_ctx.device(), - openfpga_context.arch().arch_direct, - openfpga_context.arch().circuit_lib); + openfpga_ctx.mutable_tile_direct() = build_device_tile_direct(g_vpr_ctx.device(), + openfpga_ctx.arch().arch_direct); } diff --git a/openfpga/src/fabric/build_top_module_directs.cpp b/openfpga/src/fabric/build_top_module_directs.cpp new file mode 100644 index 000000000..63d4a1882 --- /dev/null +++ b/openfpga/src/fabric/build_top_module_directs.cpp @@ -0,0 +1,151 @@ +/******************************************************************** + * 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 + +/* Headers from vtrutil library */ +#include "vtr_assert.h" +#include "vtr_log.h" + +/* Headers from openfpgautil library */ +#include "openfpga_port.h" + +/* Headers from vpr library */ +#include "vpr_utils.h" + +#include "openfpga_reserved_words.h" +#include "openfpga_naming.h" +#include "module_manager_utils.h" + +#include "build_top_module_directs.h" + +/* begin namespace openfpga */ +namespace openfpga { + +/******************************************************************** + * 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_tile_direct_connection(ModuleManager& module_manager, + const ModuleId& top_module, + const CircuitLibrary& circuit_lib, + const DeviceGrid& grids, + const vtr::Matrix& grid_instance_ids, + const TileDirect& tile_direct, + const TileDirectId& tile_direct_id, + const ArchDirect& arch_direct) { + vtr::Point device_size(grids.width(), grids.height()); + + /* Find the module name of source clb */ + vtr::Point src_clb_coord = tile_direct.from_tile_coordinate(tile_direct_id); + t_physical_tile_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_MODULE_NAME_PREFIX); + std::string src_module_name = generate_grid_block_module_name(src_module_name_prefix, std::string(src_grid_type->name), is_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 */ + vtr::Point des_clb_coord = tile_direct.to_tile_coordinate(tile_direct_id); + t_physical_tile_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_MODULE_NAME_PREFIX); + std::string sink_module_name = generate_grid_block_module_name(sink_module_name_prefix, std::string(sink_grid_type->name), is_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 */ + CircuitModelId direct_circuit_model = arch_direct.circuit_model(tile_direct.arch_direct(tile_direct_id)); + 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, CIRCUIT_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_prefix(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, CIRCUIT_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_prefix(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()); + + /* Generate the pin name of source port/pin in the grid */ + e_side src_pin_grid_side = tile_direct.from_tile_side(tile_direct_id); + size_t src_tile_pin = tile_direct.from_tile_pin(tile_direct_id); + size_t src_pin_width = grids[src_clb_coord.x()][src_clb_coord.y()].type->pin_width_offset[src_tile_pin]; + size_t src_pin_height = grids[src_clb_coord.x()][src_clb_coord.y()].type->pin_height_offset[src_tile_pin]; + std::string src_port_name = generate_grid_port_name(src_clb_coord, src_pin_width, src_pin_height, src_pin_grid_side, src_tile_pin, 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 */ + e_side sink_pin_grid_side = tile_direct.to_tile_side(tile_direct_id); + size_t sink_tile_pin = tile_direct.to_tile_pin(tile_direct_id); + size_t sink_pin_width = grids[des_clb_coord.x()][des_clb_coord.y()].type->pin_width_offset[src_tile_pin]; + size_t sink_pin_height = grids[des_clb_coord.x()][des_clb_coord.y()].type->pin_height_offset[src_tile_pin]; + + std::string sink_port_name = generate_grid_port_name(des_clb_coord, sink_pin_width, sink_pin_height, sink_pin_grid_side, sink_tile_pin, 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 + *******************************************************************/ +void add_top_module_nets_tile_direct_connections(ModuleManager& module_manager, + const ModuleId& top_module, + const CircuitLibrary& circuit_lib, + const DeviceGrid& grids, + const vtr::Matrix& grid_instance_ids, + const TileDirect& tile_direct, + const ArchDirect& arch_direct) { + + for (const TileDirectId& tile_direct_id : tile_direct.directs()) { + add_module_nets_tile_direct_connection(module_manager, top_module, circuit_lib, + grids, grid_instance_ids, + tile_direct, tile_direct_id, + arch_direct); + } +} + +} /* end namespace openfpga */ diff --git a/openfpga/src/fabric/build_top_module_directs.h b/openfpga/src/fabric/build_top_module_directs.h new file mode 100644 index 000000000..e9855db70 --- /dev/null +++ b/openfpga/src/fabric/build_top_module_directs.h @@ -0,0 +1,33 @@ +#ifndef BUILD_TOP_MODULE_DIRECTS_H +#define BUILD_TOP_MODULE_DIRECTS_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include +#include "vtr_geometry.h" +#include "vtr_ndmatrix.h" +#include "arch_direct.h" +#include "tile_direct.h" +#include "device_grid.h" +#include "module_manager.h" +#include "circuit_library.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ + +/* begin namespace openfpga */ +namespace openfpga { + +void add_top_module_nets_tile_direct_connections(ModuleManager& module_manager, + const ModuleId& top_module, + const CircuitLibrary& circuit_lib, + const DeviceGrid& grids, + const vtr::Matrix& grid_instance_ids, + const TileDirect& tile_direct, + const ArchDirect& arch_direct); + +} /* end namespace openfpga */ + +#endif diff --git a/openfpga/src/tile_direct/build_tile_direct.cpp b/openfpga/src/tile_direct/build_tile_direct.cpp index 5a40e2ca5..a99370a0b 100644 --- a/openfpga/src/tile_direct/build_tile_direct.cpp +++ b/openfpga/src/tile_direct/build_tile_direct.cpp @@ -119,26 +119,250 @@ std::vector find_physical_tile_pin_id(t_physical_tile_type_ptr physical_ return pin_ids; } +/******************************************************************** + * Check if the grid coorindate given is in the device grid range + *******************************************************************/ +static +bool is_grid_coordinate_exist_in_device(const DeviceGrid& device_grid, + const vtr::Point& grid_coordinate) { + return (grid_coordinate < vtr::Point(device_grid.width(), device_grid.height())); +} + +/******************************************************************** + * 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 DeviceGrid& grids, + const std::vector>& candidate_coords, + const std::string& wanted_grid_type_name) { + 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(grids, coord)) { + continue; + } + if (wanted_grid_type_name == std::string(grids[coord.x()][coord.y()].type->name)) { + return coord; + } + } + /* Return an valid coordinate */ + return vtr::Point(grids.width(), grids.height()); +} + +/******************************************************************** + * Find the coordinate of the destination clb/heterogeneous block + * considering intra column/row direct connections in core grids + *******************************************************************/ +static +vtr::Point find_inter_direct_destination_coordinate(const DeviceGrid& grids, + const vtr::Point& src_coord, + const std::string des_tile_type_name, + const ArchDirect& arch_direct, + const ArchDirectId& arch_direct_id) { + vtr::Point des_coord(grids.width(), grids.height()); + + 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 (INTER_COLUMN == arch_direct.type(arch_direct_id)) { + if (POSITIVE_DIR == arch_direct.x_dir(arch_direct_id)) { + /* Our first search space will be in x-direction: + * + * x ... nx + * +-----+ + * |Grid | -----> + * +-----+ + */ + for (size_t ix = src_coord.x() + 1; ix < grids.width() - 1; ++ix) { + first_search_space.push_back(ix); + } + } else { + VTR_ASSERT(NEGATIVE_DIR == arch_direct.x_dir(arch_direct_id)); + /* 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 < grids.height() - 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 == arch_direct.y_dir(arch_direct_id)) { + 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 (INTER_ROW == arch_direct.type(arch_direct_id)) { + if (POSITIVE_DIR == arch_direct.y_dir(arch_direct_id)) { + /* Our first search space will be in y-direction: + * + * +------+ + * | Grid | ny + * +------+ + * ^ . + * | . + * | . + * +------+ + * | Grid | y + * +------+ + */ + for (size_t iy = src_coord.y() + 1; iy < grids.height() - 1; ++iy) { + first_search_space.push_back(iy); + } + } else { + VTR_ASSERT(NEGATIVE_DIR == arch_direct.y_dir(arch_direct_id)); + /* 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 < grids.width() - 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 == arch_direct.x_dir(arch_direct_id)) { + 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 (INTER_COLUMN == arch_direct.type(arch_direct_id)) { + next_col_row_coords.push_back(vtr::Point(ix, iy)); + } else { + VTR_ASSERT(INTER_ROW == arch_direct.type(arch_direct_id)); + /* 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(grids, next_col_row_coords, des_tile_type_name); + /* For a valid coordinate, we can return */ + if (true == is_grid_coordinate_exist_in_device(grids, des_coord_cand)) { + return des_coord_cand; + } + } + return des_coord; +} + +/*************************************************************************************** + * Report error for port matching failure + ***************************************************************************************/ +static +void report_direct_from_port_and_to_port_mismatch(const t_direct_inf& vpr_direct, + const BasicPort& from_tile_port, + const BasicPort& to_tile_port) { + VTR_LOG_ERROR("From_port '%s[%lu:%lu] of direct '%s' does not match to_port '%s[%lu:%lu]'!\n", + from_tile_port.get_name().c_str(), + from_tile_port.get_lsb(), + from_tile_port.get_msb(), + vpr_direct.name, + to_tile_port.get_name().c_str(), + to_tile_port.get_lsb(), + to_tile_port.get_msb()); +} + /*************************************************************************************** * Build the point-to-point direct connections based on * - original VPR arch definition * This is limited to the inner-column and inner-row connections + * 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 * - * Build the inner-column and inner-row connections - * - * +------+ - * | Tile | - * +------+ +------+ +------+ - * | or | Tile |--->| Tile | - * v +------+ +------+ + * This function supports the following type of direct connection: + * 1. Direct connection between tiles in the same column or row + * +------+ +------+ + * | | | | + * | Tile |----->| Tile | + * | | | | + * +------+ +------+ + * | direction connection + * v * +------+ + * | | * | Tile | + * | | * +------+ * ***************************************************************************************/ static void build_inner_column_row_tile_direct(TileDirect& tile_direct, - t_direct_inf& vpr_direct, + const t_direct_inf& vpr_direct, const DeviceContext& device_ctx, const ArchDirectId& arch_direct_id) { /* Get the source tile and pin information */ @@ -166,10 +390,10 @@ void build_inner_column_row_tile_direct(TileDirect& tile_direct, /* Try to find the pin in this tile */ std::vector from_pins = find_physical_tile_pin_id(device_ctx.grid[x][y].type, - device_ctx.grid[x][y].width_offset, - device_ctx.grid[x][y].height_offset, - from_tile_port, - vpr_direct.from_side); + device_ctx.grid[x][y].width_offset, + device_ctx.grid[x][y].height_offset, + from_tile_port, + vpr_direct.from_side); /* If nothing found, we can continue */ if (0 == from_pins.size()) { continue; @@ -178,8 +402,7 @@ void build_inner_column_row_tile_direct(TileDirect& tile_direct, /* We should try to the sink grid for inner-column/row direct connections */ vtr::Point from_grid_coord(x, y); vtr::Point to_grid_coord(x + vpr_direct.x_offset, y + vpr_direct.y_offset); - if ((to_grid_coord.x() >= device_ctx.grid.width()) - || (to_grid_coord.y() >= device_ctx.grid.height())) { + if (false == is_grid_coordinate_exist_in_device(device_ctx.grid, to_grid_coord)) { continue; } @@ -200,61 +423,60 @@ void build_inner_column_row_tile_direct(TileDirect& tile_direct, /* If from port and to port do not match in sizes, error out */ if (from_pins.size() != to_pins.size()) { - VTR_LOG_ERROR("From_port '%s[%lu:%lu] of direct '%s' does not match to_port '%s[%lu:%lu]'!\n", - from_tile_port.get_name().c_str(), - from_tile_port.get_lsb(), - from_tile_port.get_msb(), - vpr_direct.name, - to_tile_port.get_name().c_str(), - to_tile_port.get_lsb(), - to_tile_port.get_msb()); + report_direct_from_port_and_to_port_mismatch(vpr_direct, from_tile_port, to_tile_port); exit(1); } /* Now add the tile direct */ for (size_t ipin = 0; ipin < from_pins.size(); ++ipin) { - TileDirectId tile_direct_id = tile_direct.add_direct(device_ctx.grid[x][y].type, - from_grid_coord, vpr_direct.from_side, from_pins[ipin], - device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].type, + TileDirectId tile_direct_id = tile_direct.add_direct(from_grid_coord, vpr_direct.from_side, from_pins[ipin], to_grid_coord, vpr_direct.to_side, to_pins[ipin]); tile_direct.set_arch_direct_id(tile_direct_id, arch_direct_id); } - } } } -/*************************************************************************************** +/******************************************************************** * Build the point-to-point direct connections based on * - OpenFPGA arch definition * This is limited to the inter-column and inter-row connections * - * Build the inter-column and inter-row connections + * 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 * - * +------+ +------+ - * | Tile | | Tile | - * +------+ +------+ - * | ^ - * | | - * +------------- + * This function supports the following type of direct connection: * - * +------+ - * | Tile |-------+ - * +------+ | - * | - * +------+ | - * | Tile |<------+ - * +------+ - * + * 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 build_inter_column_row_tile_direct(TileDirect& tile_direct, - t_direct_inf& vpr_direct, + const t_direct_inf& vpr_direct, const DeviceContext& device_ctx, const ArchDirect& arch_direct, - const ArchDirectId& arch_direct_id, - const CircuitLibrary& circuit_lib) { + const ArchDirectId& arch_direct_id) { + /* Get the source tile and pin information */ std::string from_tile_name = parse_direct_tile_name(std::string(vpr_direct.from_pin)); PortParser from_tile_port_parser(std::string(vpr_direct.from_pin)); @@ -265,42 +487,63 @@ void build_inter_column_row_tile_direct(TileDirect& tile_direct, PortParser to_tile_port_parser(std::string(vpr_direct.to_pin)); const BasicPort& to_tile_port = to_tile_port_parser.port(); - /* Walk through the device fabric and find the grid that fit the source */ - for (size_t x = 0; x < device_ctx.grid.width(); ++x) { - for (size_t y = 0; y < device_ctx.grid.height(); ++y) { - /* Bypass empty grid */ - if (true == is_empty_type(device_ctx.grid[x][y].type)) { - continue; + /* Go through the direct connection list, see if we need intra-column/row connection here */ + if ( (INTER_COLUMN != arch_direct.type(arch_direct_id)) + && (INTER_ROW != arch_direct.type(arch_direct_id))) { + return; + } + /* 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 (INTER_COLUMN == arch_direct.type(arch_direct_id)) { + for (size_t ix = 1; ix < device_ctx.grid.width() - 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_ctx.grid.height() - 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 == arch_direct.y_dir(arch_direct_id)) { + std::reverse(next_col_src_grid_coords.begin(), next_col_src_grid_coords.end()); } /* Bypass the grid that does not fit the from_tile name */ - if (from_tile_name != std::string(device_ctx.grid[x][y].type->name)) { + vtr::Point from_grid_coord = find_grid_coordinate_given_type(device_ctx.grid, next_col_src_grid_coords, from_tile_name); + /* Skip if we do not have a valid coordinate for source CLB/heterogeneous block */ + if (false == is_grid_coordinate_exist_in_device(device_ctx.grid, from_grid_coord)) { continue; } /* Try to find the pin in this tile */ - std::vector from_pins = find_physical_tile_pin_id(device_ctx.grid[x][y].type, - device_ctx.grid[x][y].width_offset, - device_ctx.grid[x][y].height_offset, + std::vector from_pins = find_physical_tile_pin_id(device_ctx.grid[from_grid_coord.x()][from_grid_coord.y()].type, + device_ctx.grid[from_grid_coord.x()][from_grid_coord.y()].width_offset, + device_ctx.grid[from_grid_coord.x()][from_grid_coord.y()].height_offset, from_tile_port, vpr_direct.from_side); /* If nothing found, we can continue */ if (0 == from_pins.size()) { continue; } - - /* We should try to the sink grid for inner-column/row direct connections */ - vtr::Point from_grid_coord(x, y); - vtr::Point to_grid_coord(x + vpr_direct.x_offset, y + vpr_direct.y_offset); - if ((to_grid_coord.x() >= device_ctx.grid.width()) - || (to_grid_coord.y() >= device_ctx.grid.height())) { - continue; + + /* For a valid coordinate, we can find the coordinate of the destination clb */ + vtr::Point to_grid_coord = find_inter_direct_destination_coordinate(device_ctx.grid, from_grid_coord, to_tile_name, arch_direct, arch_direct_id); + /* If destination clb is valid, we should add something */ + if (false == is_grid_coordinate_exist_in_device(device_ctx.grid, to_grid_coord)) { + continue; } - /* Bypass the grid that does not fit the from_tile name */ - if (to_tile_name != std::string(device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].type->name)) { - continue; - } /* Try to find the pin in this tile */ std::vector to_pins = find_physical_tile_pin_id(device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].type, device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].width_offset, @@ -314,26 +557,88 @@ void build_inter_column_row_tile_direct(TileDirect& tile_direct, /* If from port and to port do not match in sizes, error out */ if (from_pins.size() != to_pins.size()) { - VTR_LOG_ERROR("From_port '%s[%lu:%lu] of direct '%s' does not match to_port '%s[%lu:%lu]'!\n", - from_tile_port.get_name().c_str(), - from_tile_port.get_lsb(), - from_tile_port.get_msb(), - vpr_direct.name, - to_tile_port.get_name().c_str(), - to_tile_port.get_lsb(), - to_tile_port.get_msb()); + report_direct_from_port_and_to_port_mismatch(vpr_direct, from_tile_port, to_tile_port); exit(1); } /* Now add the tile direct */ for (size_t ipin = 0; ipin < from_pins.size(); ++ipin) { - TileDirectId tile_direct_id = tile_direct.add_direct(device_ctx.grid[x][y].type, - from_grid_coord, vpr_direct.from_side, from_pins[ipin], - device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].type, + TileDirectId tile_direct_id = tile_direct.add_direct(from_grid_coord, vpr_direct.from_side, from_pins[ipin], to_grid_coord, vpr_direct.to_side, to_pins[ipin]); tile_direct.set_arch_direct_id(tile_direct_id, arch_direct_id); } + } + return; /* Go to next direct type */ + } + + /* Reach here, it must be a cross-row connection */ + VTR_ASSERT(INTER_ROW == arch_direct.type(arch_direct_id)); + /* 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_ctx.grid.height() - 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_ctx.grid.width() - 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 == arch_direct.x_dir(arch_direct_id)) { + std::reverse(next_col_src_grid_coords.begin(), next_col_src_grid_coords.end()); + } + vtr::Point from_grid_coord = find_grid_coordinate_given_type(device_ctx.grid, next_col_src_grid_coords, from_tile_name); + /* Skip if we do not have a valid coordinate for source CLB/heterogeneous block */ + if (false == is_grid_coordinate_exist_in_device(device_ctx.grid, from_grid_coord)) { + continue; + } + + /* Try to find the pin in this tile */ + std::vector from_pins = find_physical_tile_pin_id(device_ctx.grid[from_grid_coord.x()][from_grid_coord.y()].type, + device_ctx.grid[from_grid_coord.x()][from_grid_coord.y()].width_offset, + device_ctx.grid[from_grid_coord.x()][from_grid_coord.y()].height_offset, + from_tile_port, + vpr_direct.from_side); + /* If nothing found, we can continue */ + if (0 == from_pins.size()) { + continue; + } + + /* For a valid coordinate, we can find the coordinate of the destination clb */ + vtr::Point to_grid_coord = find_inter_direct_destination_coordinate(device_ctx.grid, from_grid_coord, to_tile_name, arch_direct, arch_direct_id); + /* If destination clb is valid, we should add something */ + if (false == is_grid_coordinate_exist_in_device(device_ctx.grid, to_grid_coord)) { + continue; + } + + /* Try to find the pin in this tile */ + std::vector to_pins = find_physical_tile_pin_id(device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].type, + device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].width_offset, + device_ctx.grid[to_grid_coord.x()][to_grid_coord.y()].height_offset, + to_tile_port, + vpr_direct.to_side); + /* If nothing found, we can continue */ + if (0 == to_pins.size()) { + continue; + } + + /* If from port and to port do not match in sizes, error out */ + if (from_pins.size() != to_pins.size()) { + report_direct_from_port_and_to_port_mismatch(vpr_direct, from_tile_port, to_tile_port); + exit(1); + } + + /* Now add the tile direct */ + for (size_t ipin = 0; ipin < from_pins.size(); ++ipin) { + TileDirectId tile_direct_id = tile_direct.add_direct(from_grid_coord, vpr_direct.from_side, from_pins[ipin], + to_grid_coord, vpr_direct.to_side, to_pins[ipin]); + tile_direct.set_arch_direct_id(tile_direct_id, arch_direct_id); } } } @@ -343,8 +648,7 @@ void build_inter_column_row_tile_direct(TileDirect& tile_direct, * between tiles (programmable blocks) ***************************************************************************************/ TileDirect build_device_tile_direct(const DeviceContext& device_ctx, - const ArchDirect& arch_direct, - const CircuitLibrary& circuit_lib) { + const ArchDirect& arch_direct) { vtr::ScopedStartFinishTimer timer("Build the annotation about direct connection between tiles"); TileDirect tile_direct; @@ -358,7 +662,12 @@ TileDirect build_device_tile_direct(const DeviceContext& device_ctx, device_ctx.arch->Directs[idirect], device_ctx, arch_direct_id); - /* TODO: Build from OpenFPGA arch definition */ + /* Build from OpenFPGA arch definition */ + build_inter_column_row_tile_direct(tile_direct, + device_ctx.arch->Directs[idirect], + device_ctx, + arch_direct, + arch_direct_id); } return tile_direct; diff --git a/openfpga/src/tile_direct/build_tile_direct.h b/openfpga/src/tile_direct/build_tile_direct.h index 08d0397ce..78ca2f6b0 100644 --- a/openfpga/src/tile_direct/build_tile_direct.h +++ b/openfpga/src/tile_direct/build_tile_direct.h @@ -17,8 +17,7 @@ namespace openfpga { TileDirect build_device_tile_direct(const DeviceContext& device_ctx, - const ArchDirect& arch_direct, - const CircuitLibrary& circuit_lib); + const ArchDirect& arch_direct); } /* end namespace openfpga */ diff --git a/openfpga/src/tile_direct/tile_direct.cpp b/openfpga/src/tile_direct/tile_direct.cpp index d0d1f6122..228724c78 100644 --- a/openfpga/src/tile_direct/tile_direct.cpp +++ b/openfpga/src/tile_direct/tile_direct.cpp @@ -15,12 +15,6 @@ TileDirect::tile_direct_range TileDirect::directs() const { return vtr::make_range(direct_ids_.begin(), direct_ids_.end()); } -t_physical_tile_type_ptr TileDirect::from_tile(const TileDirectId& direct_id) const { - /* Validate the direct_id */ - VTR_ASSERT(valid_direct_id(direct_id)); - return from_tiles_[direct_id]; -} - vtr::Point TileDirect::from_tile_coordinate(const TileDirectId& direct_id) const { /* Validate the direct_id */ VTR_ASSERT(valid_direct_id(direct_id)); @@ -39,12 +33,6 @@ e_side TileDirect::from_tile_side(const TileDirectId& direct_id) const { return from_tile_sides_[direct_id]; } -t_physical_tile_type_ptr TileDirect::to_tile(const TileDirectId& direct_id) const { - /* Validate the direct_id */ - VTR_ASSERT(valid_direct_id(direct_id)); - return to_tiles_[direct_id]; -} - vtr::Point TileDirect::to_tile_coordinate(const TileDirectId& direct_id) const { /* Validate the direct_id */ VTR_ASSERT(valid_direct_id(direct_id)); @@ -72,11 +60,9 @@ ArchDirectId TileDirect::arch_direct(const TileDirectId& direct_id) const { /****************************************************************************** * Private Mutators ******************************************************************************/ -TileDirectId TileDirect::add_direct(t_physical_tile_type_ptr from_tile, - const vtr::Point& from_tile_coord, +TileDirectId TileDirect::add_direct(const vtr::Point& from_tile_coord, const e_side& from_tile_side, const size_t& from_tile_pin, - t_physical_tile_type_ptr to_tile, const vtr::Point& to_tile_coord, const e_side& to_tile_side, const size_t& to_tile_pin) { @@ -85,12 +71,10 @@ TileDirectId TileDirect::add_direct(t_physical_tile_type_ptr from_tile, direct_ids_.push_back(direct); /* Allocate other attributes */ - from_tiles_.push_back(from_tile); from_tile_coords_.push_back(from_tile_coord); from_tile_sides_.push_back(from_tile_side); from_tile_pins_.push_back(from_tile_pin); - to_tiles_.push_back(to_tile); to_tile_coords_.push_back(to_tile_coord); to_tile_sides_.push_back(to_tile_side); to_tile_pins_.push_back(to_tile_pin); diff --git a/openfpga/src/tile_direct/tile_direct.h b/openfpga/src/tile_direct/tile_direct.h index d8d0e180f..84593e80c 100644 --- a/openfpga/src/tile_direct/tile_direct.h +++ b/openfpga/src/tile_direct/tile_direct.h @@ -33,21 +33,17 @@ class TileDirect { typedef vtr::Range tile_direct_range; public: /* Public aggregators */ tile_direct_range directs() const; - t_physical_tile_type_ptr from_tile(const TileDirectId& direct_id) const; vtr::Point from_tile_coordinate(const TileDirectId& direct_id) const; e_side from_tile_side(const TileDirectId& direct_id) const; size_t from_tile_pin(const TileDirectId& direct_id) const; - t_physical_tile_type_ptr to_tile(const TileDirectId& direct_id) const; vtr::Point to_tile_coordinate(const TileDirectId& direct_id) const; e_side to_tile_side(const TileDirectId& direct_id) const; size_t to_tile_pin(const TileDirectId& direct_id) const; ArchDirectId arch_direct(const TileDirectId& direct_id) const; public: /* Public mutators */ - TileDirectId add_direct(t_physical_tile_type_ptr from_tile, - const vtr::Point& from_tile_coord, + TileDirectId add_direct(const vtr::Point& from_tile_coord, const e_side& from_tile_side, const size_t& from_tile_pin, - t_physical_tile_type_ptr to_tile, const vtr::Point& to_tile_coord, const e_side& to_tile_side, const size_t& to_tile_pin); @@ -63,7 +59,6 @@ class TileDirect { * - tile coordinate * - tile pin id */ - vtr::vector from_tiles_; vtr::vector> from_tile_coords_; vtr::vector from_tile_sides_; vtr::vector from_tile_pins_; @@ -73,7 +68,6 @@ class TileDirect { * - tile coordinate * - tile pin id */ - vtr::vector to_tiles_; vtr::vector> to_tile_coords_; vtr::vector to_tile_sides_; vtr::vector to_tile_pins_;