diff --git a/openfpga/src/base/openfpga_context.h b/openfpga/src/base/openfpga_context.h index 6f9ee0910..ac3cc99c8 100644 --- a/openfpga/src/base/openfpga_context.h +++ b/openfpga/src/base/openfpga_context.h @@ -8,6 +8,7 @@ #include "vpr_clustering_annotation.h" #include "vpr_routing_annotation.h" #include "mux_library.h" +#include "tile_direct.h" #include "module_manager.h" #include "device_rr_gsb.h" @@ -47,6 +48,7 @@ class OpenfpgaContext : public Context { const openfpga::VprRoutingAnnotation& vpr_routing_annotation() const { return vpr_routing_annotation_; } const openfpga::DeviceRRGSB& device_rr_gsb() const { return device_rr_gsb_; } const openfpga::MuxLibrary& mux_lib() const { return mux_lib_; } + const openfpga::TileDirect& tile_direct() const { return tile_direct_; } const openfpga::ModuleManager& module_graph() const { return module_graph_; } public: /* Public mutators */ openfpga::Arch& mutable_arch() { return arch_; } @@ -56,6 +58,7 @@ class OpenfpgaContext : public Context { openfpga::VprRoutingAnnotation& mutable_vpr_routing_annotation() { return vpr_routing_annotation_; } openfpga::DeviceRRGSB& mutable_device_rr_gsb() { return device_rr_gsb_; } openfpga::MuxLibrary& mutable_mux_lib() { return mux_lib_; } + openfpga::TileDirect& mutable_tile_direct() { return tile_direct_; } openfpga::ModuleManager& mutable_module_graph() { return module_graph_; } private: /* Internal data */ /* Data structure to store information from read_openfpga_arch library */ @@ -67,7 +70,7 @@ class OpenfpgaContext : public Context { /* Naming fix to netlist */ openfpga::VprNetlistAnnotation vpr_netlist_annotation_; - /* TODO: Pin net fix to cluster results */ + /* Pin net fix to cluster results */ openfpga::VprClusteringAnnotation vpr_clustering_annotation_; /* Routing results annotation */ @@ -79,6 +82,9 @@ class OpenfpgaContext : public Context { /* Library of physical implmentation of routing multiplexers */ openfpga::MuxLibrary mux_lib_; + /* Inner/inter-column/row tile direct connections */ + openfpga::TileDirect tile_direct_; + /* Fabric module graph */ openfpga::ModuleManager module_graph_; }; diff --git a/openfpga/src/base/openfpga_link_arch.cpp b/openfpga/src/base/openfpga_link_arch.cpp index 78afc93a2..7ee522b6a 100644 --- a/openfpga/src/base/openfpga_link_arch.cpp +++ b/openfpga/src/base/openfpga_link_arch.cpp @@ -14,6 +14,7 @@ #include "annotate_routing.h" #include "annotate_rr_graph.h" #include "mux_library_builder.h" +#include "build_tile_direct.h" #include "openfpga_link_arch.h" /* Include global variables of VPR */ @@ -106,6 +107,12 @@ void link_arch(OpenfpgaContext& openfpga_context, /* Build multiplexer library */ openfpga_context.mutable_mux_lib() = build_device_mux_library(g_vpr_ctx.device(), const_cast(openfpga_context)); + + /* 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); + } } /* end namespace openfpga */ diff --git a/openfpga/src/tile_direct/build_tile_direct.cpp b/openfpga/src/tile_direct/build_tile_direct.cpp new file mode 100644 index 000000000..5a40e2ca5 --- /dev/null +++ b/openfpga/src/tile_direct/build_tile_direct.cpp @@ -0,0 +1,367 @@ +/*************************************************************************************** + * 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: + * .[:] + ***************************************************************************************/ +static +std::string parse_direct_tile_name(const std::string& direct_tile_inf) { + StringToken tokenizer(direct_tile_inf); + std::vector 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 .[:].\n", + direct_tile_inf.c_str()); + } + + return tokens[0]; +} + +/*************************************************************************************** + * 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 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 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; +} + +/*************************************************************************************** + * Build the point-to-point direct connections based on + * - original VPR arch definition + * This is limited to the inner-column and inner-row connections + * + * Build the inner-column and inner-row connections + * + * +------+ + * | Tile | + * +------+ +------+ +------+ + * | or | Tile |--->| Tile | + * v +------+ +------+ + * +------+ + * | Tile | + * +------+ + * + ***************************************************************************************/ +static +void build_inner_column_row_tile_direct(TileDirect& tile_direct, + t_direct_inf& vpr_direct, + const DeviceContext& device_ctx, + 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)); + 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(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; + } + + /* 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); + /* 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; + } + + /* 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, + 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()) { + 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()); + 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, + 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 + * + * +------+ +------+ + * | Tile | | Tile | + * +------+ +------+ + * | ^ + * | | + * +------------- + * + * +------+ + * | Tile |-------+ + * +------+ | + * | + * +------+ | + * | Tile |<------+ + * +------+ + * + * + ***************************************************************************************/ +static +void build_inter_column_row_tile_direct(TileDirect& tile_direct, + t_direct_inf& vpr_direct, + const DeviceContext& device_ctx, + const ArchDirect& arch_direct, + const ArchDirectId& arch_direct_id, + const CircuitLibrary& circuit_lib) { + /* 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)); + 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(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; + } + + /* 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); + /* 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; + } + + /* 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, + 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()) { + 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()); + 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, + to_grid_coord, vpr_direct.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 CircuitLibrary& circuit_lib) { + 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)); + VTR_ASSERT(ArchDirectId::INVALID() != arch_direct_id); + /* Build from original VPR arch definition */ + build_inner_column_row_tile_direct(tile_direct, + device_ctx.arch->Directs[idirect], + device_ctx, + arch_direct_id); + /* TODO: Build from OpenFPGA arch definition */ + } + + return tile_direct; +} + +} /* end namespace openfpga */ diff --git a/openfpga/src/tile_direct/build_tile_direct.h b/openfpga/src/tile_direct/build_tile_direct.h new file mode 100644 index 000000000..08d0397ce --- /dev/null +++ b/openfpga/src/tile_direct/build_tile_direct.h @@ -0,0 +1,25 @@ +#ifndef BUILD_TILE_DIRECT_H +#define BUILD_TILE_DIRECT_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include "vpr_context.h" +#include "arch_direct.h" +#include "tile_direct.h" +#include "circuit_library.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ + +/* begin namespace openfpga */ +namespace openfpga { + +TileDirect build_device_tile_direct(const DeviceContext& device_ctx, + const ArchDirect& arch_direct, + const CircuitLibrary& circuit_lib); + +} /* end namespace openfpga */ + +#endif diff --git a/openfpga/src/tile_direct/tile_direct.cpp b/openfpga/src/tile_direct/tile_direct.cpp index 0face1b7e..d0d1f6122 100644 --- a/openfpga/src/tile_direct/tile_direct.cpp +++ b/openfpga/src/tile_direct/tile_direct.cpp @@ -63,6 +63,12 @@ e_side TileDirect::to_tile_side(const TileDirectId& direct_id) const { return to_tile_sides_[direct_id]; } +ArchDirectId TileDirect::arch_direct(const TileDirectId& direct_id) const { + /* Validate the direct_id */ + VTR_ASSERT(valid_direct_id(direct_id)); + return arch_directs_[direct_id]; +} + /****************************************************************************** * Private Mutators ******************************************************************************/ @@ -89,9 +95,18 @@ TileDirectId TileDirect::add_direct(t_physical_tile_type_ptr from_tile, to_tile_sides_.push_back(to_tile_side); to_tile_pins_.push_back(to_tile_pin); + arch_directs_.emplace_back(ArchDirectId::INVALID()); + return direct; } +void TileDirect::set_arch_direct_id(const TileDirectId& tile_direct_id, + const ArchDirectId& arch_direct_id) { + /* Validate the direct_id */ + VTR_ASSERT(valid_direct_id(tile_direct_id)); + arch_directs_[tile_direct_id] = arch_direct_id; +} + /****************************************************************************** * Private validators/invalidators ******************************************************************************/ diff --git a/openfpga/src/tile_direct/tile_direct.h b/openfpga/src/tile_direct/tile_direct.h index 562b559ca..d8d0e180f 100644 --- a/openfpga/src/tile_direct/tile_direct.h +++ b/openfpga/src/tile_direct/tile_direct.h @@ -11,6 +11,9 @@ /* Headers from readarch library */ #include "physical_types.h" +/* Headers from readarchopenfpga library */ +#include "arch_direct.h" + #include "tile_direct_fwd.h" /* Begin namespace openfpga */ @@ -38,6 +41,7 @@ class TileDirect { 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, @@ -47,6 +51,8 @@ class TileDirect { const vtr::Point& to_tile_coord, const e_side& to_tile_side, const size_t& to_tile_pin); + void set_arch_direct_id(const TileDirectId& tile_direct_id, + const ArchDirectId& arch_direct_id); public: /* Public validators/invalidators */ bool valid_direct_id(const TileDirectId& direct_id) const; private: /* Internal Data */ @@ -71,6 +77,8 @@ class TileDirect { vtr::vector> to_tile_coords_; vtr::vector to_tile_sides_; vtr::vector to_tile_pins_; + + vtr::vector arch_directs_; }; } /* End namespace openfpga*/