OpenFPGA/openfpga/src/tile_direct/build_tile_direct.cpp

796 lines
34 KiB
C++

/***************************************************************************************
* This file includes functions that build the point-to-point direct connections
* between tiles (programmable blocks)
***************************************************************************************/
/* Headers from vtrutil library */
#include "vtr_log.h"
#include "vtr_assert.h"
#include "vtr_time.h"
/* Headers from openfpgautil library */
#include "openfpga_tokenizer.h"
#include "openfpga_port.h"
#include "openfpga_port_parser.h"
/* Headers from vpr library */
#include "vpr_utils.h"
#include "build_tile_direct.h"
/* begin namespace openfpga */
namespace openfpga {
/***************************************************************************************
* Parse the from tile name from the direct definition
* The definition string should be in the following format:
* <tile_type_name>.<pin_name>[<pin_lsb>:<pin_msb>]
***************************************************************************************/
static
std::string parse_direct_tile_name(const std::string& direct_tile_inf) {
StringToken tokenizer(direct_tile_inf);
std::vector<std::string> tokens = tokenizer.split('.');
/* We should have only 2 elements and the first is tile name */
if (2 != tokens.size()) {
VTR_LOG_ERROR("Invalid definition on direct tile '%s'!\n\tExpect <tile_type_name>.<pin_name>[<pin_lsb>:<pin_msb>].\n",
direct_tile_inf.c_str());
}
return tokens[0];
}
/***************************************************************************************
* Parse the pin name and port MSB/LSB from the direct definition
* The definition string should be in the following format:
* <tile_type_name>.<pin_name>[<pin_lsb>:<pin_msb>]
***************************************************************************************/
static
std::string parse_direct_port(const std::string& direct_tile_inf) {
StringToken tokenizer(direct_tile_inf);
std::vector<std::string> tokens = tokenizer.split('.');
/* We should have only 2 elements and the first is tile name */
if (2 != tokens.size()) {
VTR_LOG_ERROR("Invalid definition on direct tile '%s'!\n\tExpect <tile_type_name>.<pin_name>[<pin_lsb>:<pin_msb>].\n",
direct_tile_inf.c_str());
}
return tokens[1];
}
/***************************************************************************************
* Check if a pin is located on a given side of physical tile
* If the given side is NUM_SIDES, we will search all the sides
***************************************************************************************/
static
bool is_pin_locate_at_physical_tile_side(t_physical_tile_type_ptr physical_tile,
const size_t& pin_width_offset,
const size_t& pin_height_offset,
const size_t& pin_id,
const e_side& pin_side) {
if (NUM_SIDES == pin_side) {
for (size_t side = 0; side < NUM_SIDES; ++side) {
if (true == physical_tile->pinloc[pin_width_offset][pin_height_offset][side][pin_id]) {
return true;
}
}
}
return physical_tile->pinloc[pin_width_offset][pin_height_offset][size_t(pin_side)][pin_id];
}
/***************************************************************************************
* Find the pin ids of a physical tile based on the given port name, LSB and MSB
***************************************************************************************/
static
std::vector<size_t> find_physical_tile_pin_id(t_physical_tile_type_ptr physical_tile,
const size_t& pin_width_offset,
const size_t& pin_height_offset,
const BasicPort& tile_port,
const e_side& pin_side) {
std::vector<size_t> pin_ids;
/* Walk through the port of the tile */
for (const t_physical_tile_port& physical_tile_port : physical_tile->ports) {
if (std::string(physical_tile_port.name) != tile_port.get_name()) {
continue;
}
/* If the wanted port is invalid, it assumes that we want the full port */
if (false == tile_port.is_valid()) {
for (int ipin = 0; ipin < physical_tile_port.num_pins; ++ipin) {
int pin_id = physical_tile_port.absolute_first_pin_index + ipin;
VTR_ASSERT(pin_id < physical_tile->num_pins);
/* Check if the pin is located on the wanted side */
if (true == is_pin_locate_at_physical_tile_side(physical_tile,
pin_width_offset,
pin_height_offset,
pin_id, pin_side)) {
pin_ids.push_back(pin_id);
}
}
continue;
}
/* Find the LSB and MSB of the pin */
VTR_ASSERT_SAFE(true == tile_port.is_valid());
BasicPort ref_port(physical_tile_port.name, physical_tile_port.num_pins);
if (false == ref_port.contained(tile_port)) {
VTR_LOG_ERROR("Defined direct port '%s[%lu:%lu]' is out of range for physical port '%s[%lu:%lu]'!\n",
tile_port.get_name().c_str(),
tile_port.get_lsb(), tile_port.get_msb(),
ref_port.get_name().c_str(),
ref_port.get_lsb(), ref_port.get_msb());
exit(1);
}
for (const size_t& ipin : tile_port.pins()) {
int pin_id = physical_tile_port.absolute_first_pin_index + ipin;
VTR_ASSERT(pin_id < physical_tile->num_pins);
/* Check if the pin is located on the wanted side */
if (true == is_pin_locate_at_physical_tile_side(physical_tile,
pin_width_offset,
pin_height_offset,
pin_id, pin_side)) {
pin_ids.push_back(pin_id);
}
}
}
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<size_t>& grid_coordinate) {
return (grid_coordinate < vtr::Point<size_t>(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<size_t> find_grid_coordinate_given_type(const DeviceGrid& grids,
const std::vector<vtr::Point<size_t>>& candidate_coords,
const std::string& wanted_grid_type_name) {
for (vtr::Point<size_t> 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<size_t>(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<size_t> find_inter_direct_destination_coordinate(const DeviceGrid& grids,
const vtr::Point<size_t>& src_coord,
const std::string des_tile_type_name,
const ArchDirect& arch_direct,
const ArchDirectId& arch_direct_id) {
vtr::Point<size_t> des_coord(grids.width(), grids.height());
std::vector<size_t> first_search_space;
std::vector<size_t> 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
* +------+
* ^ .
* | .
* | .
* +------+
* | 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
* +------+
* | .
* | .
* v .
* +------+
* | Grid | 1
* +------+
*/
if (POSITIVE_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 (POSITIVE_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<vtr::Point<size_t>> 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<size_t>(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<size_t>(iy, ix));
}
}
vtr::Point<size_t> 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
*
* 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,
const t_direct_inf& vpr_direct,
const DeviceContext& device_ctx,
const ArchDirectId& arch_direct_id,
const bool& verbose) {
/* 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(parse_direct_port(std::string(vpr_direct.from_pin)));
const BasicPort& from_tile_port = from_tile_port_parser.port();
/* Get the sink tile and pin information */
std::string to_tile_name = parse_direct_tile_name(std::string(vpr_direct.to_pin));
PortParser to_tile_port_parser(parse_direct_port(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;
}
/* Bypass the grid that does not fit the from_tile name */
if (from_tile_name != std::string(device_ctx.grid[x][y].type->name)) {
continue;
}
/* Search all the sides, the from pin may locate any side!
* Note: the vpr_direct.from_side is NUM_SIDES, which is unintialized
* This should be reported to VPR!!!
*/
for (const e_side& from_side : {TOP, RIGHT, BOTTOM, LEFT}) {
/* Try to find the pin in this tile */
std::vector<size_t> 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,
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<size_t> from_grid_coord(x, y);
vtr::Point<size_t> to_grid_coord(x + vpr_direct.x_offset, y + vpr_direct.y_offset);
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;
}
/* Search all the sides, the to pin may locate any side!
* Note: the vpr_direct.to_side is NUM_SIDES, which is unintialized
* This should be reported to VPR!!!
*/
for (const e_side& to_side : {TOP, RIGHT, BOTTOM, LEFT}) {
/* Try to find the pin in this tile */
std::vector<size_t> 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,
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) {
VTR_LOGV(verbose,
"Built a inner-column/row tile-to-tile direct from %s[%lu][%lu].%s[%lu] at side '%s' to %s[%lu][%lu].%s[%lu] at side '%s'\n",
from_tile_name.c_str(), x, y,
from_tile_port.get_name().c_str(), from_pins[ipin],
SIDE_STRING[from_side],
to_tile_name.c_str(),
to_grid_coord.x(), to_grid_coord.y(),
to_tile_port.get_name().c_str(), to_pins[ipin],
SIDE_STRING[to_side]
);
TileDirectId tile_direct_id = tile_direct.add_direct(from_grid_coord,
from_side,
from_pins[ipin],
to_grid_coord,
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
*
* 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 build_inter_column_row_tile_direct(TileDirect& tile_direct,
const t_direct_inf& vpr_direct,
const DeviceContext& device_ctx,
const ArchDirect& arch_direct,
const ArchDirectId& arch_direct_id,
const bool& verbose) {
/* 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(parse_direct_port(std::string(vpr_direct.from_pin)));
const BasicPort& from_tile_port = from_tile_port_parser.port();
/* Get the sink tile and pin information */
std::string to_tile_name = parse_direct_tile_name(std::string(vpr_direct.to_pin));
PortParser to_tile_port_parser(parse_direct_port(std::string(vpr_direct.to_pin)));
const BasicPort& to_tile_port = to_tile_port_parser.port();
/* 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<vtr::Point<size_t>> 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<size_t>(ix, iy));
}
/* For positive y- direction, we should start from y = 1 */
if (NEGATIVE_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 */
vtr::Point<size_t> 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;
}
/* Search all the sides, the from pin may locate any side!
* Note: the vpr_direct.from_side is NUM_SIDES, which is unintialized
* This should be reported to VPR!!!
*/
for (const e_side& from_side : {TOP, RIGHT, BOTTOM, LEFT}) {
/* Try to find the pin in this tile */
std::vector<size_t> 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,
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<size_t> 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;
}
/* Search all the sides, the to pin may locate any side!
* Note: the vpr_direct.to_side is NUM_SIDES, which is unintialized
* This should be reported to VPR!!!
*/
for (const e_side& to_side : {TOP, RIGHT, BOTTOM, LEFT}) {
/* Try to find the pin in this tile */
std::vector<size_t> 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,
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) {
VTR_LOGV(verbose,
"Built a inter-column/row tile-to-tile direct from %s[%lu][%lu].%s[%lu] at side '%s' to %s[%lu][%lu].%s[%lu] at side '%s'\n",
from_tile_name.c_str(),
from_grid_coord.x(), from_grid_coord.y(),
from_tile_port.get_name().c_str(), from_pins[ipin],
SIDE_STRING[from_side],
to_tile_name.c_str(),
to_grid_coord.x(), to_grid_coord.y(),
to_tile_port.get_name().c_str(), to_pins[ipin],
SIDE_STRING[to_side]
);
TileDirectId tile_direct_id = tile_direct.add_direct(from_grid_coord,
from_side,
from_pins[ipin],
to_grid_coord,
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<vtr::Point<size_t>> 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<size_t>(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<size_t> 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;
}
/* Search all the sides, the from pin may locate any side!
* Note: the vpr_direct.from_side is NUM_SIDES, which is unintialized
* This should be reported to VPR!!!
*/
for (const e_side& from_side : {TOP, RIGHT, BOTTOM, LEFT}) {
/* Try to find the pin in this tile */
std::vector<size_t> 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,
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<size_t> 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;
}
/* Search all the sides, the to pin may locate any side!
* Note: the vpr_direct.to_side is NUM_SIDES, which is unintialized
* This should be reported to VPR!!!
*/
for (const e_side& to_side : {TOP, RIGHT, BOTTOM, LEFT}) {
/* Try to find the pin in this tile */
std::vector<size_t> 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,
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) {
VTR_LOGV(verbose,
"Built a inter-column/row tile-to-tile direct from %s[%lu][%lu].%s[%lu] at side '%s' to %s[%lu][%lu].%s[%lu] at side '%s'\n",
from_tile_name.c_str(),
from_grid_coord.x(), from_grid_coord.y(),
from_tile_port.get_name().c_str(), from_pins[ipin],
SIDE_STRING[from_side],
to_tile_name.c_str(),
to_grid_coord.x(), to_grid_coord.y(),
to_tile_port.get_name().c_str(), to_pins[ipin],
SIDE_STRING[to_side]
);
TileDirectId tile_direct_id = tile_direct.add_direct(from_grid_coord,
from_side,
from_pins[ipin],
to_grid_coord,
to_side,
to_pins[ipin]);
tile_direct.set_arch_direct_id(tile_direct_id, arch_direct_id);
}
}
}
}
}
/***************************************************************************************
* Top-level functions that build the point-to-point direct connections
* between tiles (programmable blocks)
***************************************************************************************/
TileDirect build_device_tile_direct(const DeviceContext& device_ctx,
const ArchDirect& arch_direct,
const bool& verbose) {
vtr::ScopedStartFinishTimer timer("Build the annotation about direct connection between tiles");
TileDirect tile_direct;
/* Walk through each direct definition in the VPR arch */
for (int idirect = 0; idirect < device_ctx.arch->num_directs; ++idirect) {
ArchDirectId arch_direct_id = arch_direct.direct(std::string(device_ctx.arch->Directs[idirect].name));
if (ArchDirectId::INVALID() == arch_direct_id) {
VTR_LOG_ERROR("Unable to find an annotation in openfpga architecture XML for <direct> '%s'!\n",
device_ctx.arch->Directs[idirect].name);
exit(1);
}
/* Build from original VPR arch definition */
build_inner_column_row_tile_direct(tile_direct,
device_ctx.arch->Directs[idirect],
device_ctx,
arch_direct_id,
verbose);
/* 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,
verbose);
}
VTR_LOG("Built %lu tile-to-tile direct connections\n",
std::distance(tile_direct.directs().begin(), tile_direct.directs().end()));
return tile_direct;
}
} /* end namespace openfpga */