Merge pull request #1265 from lnis-uofu/xt_fabric_tile

Support tile module when building CCFF-based FPGA fabric
This commit is contained in:
tangxifan 2023-07-26 10:32:15 -07:00 committed by GitHub
commit c011641fa0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
77 changed files with 6568 additions and 607 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

View File

@ -37,3 +37,5 @@ OpenFPGA widely uses XML format for interchangable files
clock_network
io_naming_file
tile_config_file

View File

@ -5,9 +5,9 @@ Fabric Netlists
In this part, we will introduce the hierarchy, dependency and functionality of each Verilog netlist, which are generated to model the FPGA fabric.
.. note:: These netlists are automatically generated by the OpenFPGA command ``write_fabric_verilog``. See :ref:`openfpga_verilog_commands` for its detailed usage.
.. note:: These netlists are automatically generated by the OpenFPGA command :ref:`cmd_write_fabric_verilog`. See :ref:`openfpga_verilog_commands` for its detailed usage.
All the generated Verilog netlists are located in the directory as you specify in the OpenFPGA command ``write_fabric_verilog``.
All the generated Verilog netlists are located in the directory as you specify in the OpenFPGA command :ref:`cmd_write_fabric_verilog`.
Inside the directory, the Verilog netlists are organized as illustrated in :numref:`fig_fabric_netlist_hierarchy`.
.. _fig_fabric_netlist_hierarchy:
@ -24,6 +24,8 @@ Inside the directory, the Verilog netlists are organized as illustrated in :numr
An illustrative FPGA fabric modelled by the Verilog netlists
.. _fabric_netlists_top_level_netlists:
Top-level Netlists
~~~~~~~~~~~~~~~~~~
@ -48,6 +50,21 @@ Top-level Netlists
.. note:: We strongly recommend users to turn on this flag as it can help simulators to converge quickly.
.. _fabric_netlists_tiles:
Tiles
~~~~~
This sub-directory contains all the tile-level modules. Only seen when the ``--group_tile`` option is enabled when calling command :ref:`cmd_build_fabric`.
Each tile groups a number of programmable blocks (:ref:`fabric_netlists_logic_blocks`) and routing blocks (:ref:`fabric_netlists_routing_blocks`), as depicted in :numref:`fig_generic_fabric`.
Tiles are instanciated under the top-level module (:ref:`fabric_netlists_top_level_netlists`).
.. option:: tile_<x>__<y>_.v
For each unique tile, a Verilog netlist will be generated. The ``<x>`` and ``<y>`` denote the coordinate of the tile in the FPGA fabric.
.. _fabric_netlists_logic_blocks:
Logic Blocks
~~~~~~~~~~~~
This sub-directory contains all the Verilog modules modeling configurable logic blocks, heterogeneous blocks as well as I/O blocks.
@ -63,6 +80,8 @@ Take the example in :numref:`fig_generic_fabric`, the modules are CLBs, DSP bloc
For each root ``pb_type`` defined in the ``<complexblock>`` of VPR architecture description, a Verilog netlist will be generated to model its internal structure.
.. _fabric_netlists_routing_blocks:
Routing Blocks
~~~~~~~~~~~~~~
This sub-directory contains all the Verilog modules modeling Switch Blocks (SBs) and Connection Blocks (CBs).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 54 KiB

View File

@ -3,6 +3,8 @@
FPGA-Verilog
------------
.. _cmd_write_fabric_verilog:
write_fabric_verilog
~~~~~~~~~~~~~~~~~~~~

View File

@ -252,6 +252,14 @@ build_fabric
.. option:: --compress_routing
Enable compression on routing architecture modules. Strongly recommend this as it will minimize the number of routing modules to be outputted. It can reduce the netlist size significantly.
.. option:: --group_tile <string>
Group fine-grained programmable blocks, connection blocks and switch blocks into tiles. Once enabled, tiles will be added to the top-level module. Otherwise, the top-level module consists of programmable blocks, connection blocks and switch blocks. The tile style can be customized through a file. See details in :ref:`file_formats_tile_config_file`. When enabled, the Verilog netlists will contain additional netlists that model tiles (see details in :ref:`fabric_netlists_tiles`).
.. warning:: This option does not support ``--duplicate_grid_pin``!
.. warning:: This option requires ``--compress_routing`` to be enabled!
.. option:: --duplicate_grid_pin

View File

@ -9,3 +9,4 @@ add_subdirectory(libfpgabitstream)
add_subdirectory(libpcf)
add_subdirectory(libbusgroup)
add_subdirectory(libionamemap)
add_subdirectory(libtileconfig)

View File

@ -6,6 +6,7 @@
#include <algorithm>
#include "vtr_assert.h"
#include "vtr_log.h"
/* begin namespace openfpga */
namespace openfpga {
@ -200,10 +201,20 @@ ConfigBlockId BitstreamManager::create_block() {
}
ConfigBlockId BitstreamManager::add_block(const std::string& block_name) {
ConfigBlockId block = create_block();
set_block_name(block, block_name);
ConfigBlockId new_block = create_block();
set_block_name(new_block, block_name);
return new_block;
}
return block;
ConfigBlockId BitstreamManager::find_or_create_child_block(
const ConfigBlockId& block_id, const std::string& child_block_name) {
ConfigBlockId curr_block = find_child_block(block_id, child_block_name);
if (valid_block_id(curr_block)) {
return curr_block;
}
curr_block = add_block(child_block_name);
add_child_block(block_id, curr_block);
return curr_block;
}
void BitstreamManager::set_block_name(const ConfigBlockId& block_id,

View File

@ -181,6 +181,11 @@ class BitstreamManager {
/* Add a new block of configuration bits to the bitstream manager */
ConfigBlockId add_block(const std::string& block_name);
/* Try to find the child block in a bitstream manager with a given name. If
* not found, create a new child block */
ConfigBlockId find_or_create_child_block(const ConfigBlockId& block_id,
const std::string& child_block_name);
/* Set a name for a block */
void set_block_name(const ConfigBlockId& block_id,
const std::string& block_name);
@ -234,6 +239,9 @@ class BitstreamManager {
vtr::vector<ConfigBlockId, ConfigBlockId> parent_block_ids_;
vtr::vector<ConfigBlockId, std::vector<ConfigBlockId>> child_block_ids_;
/* Fast look-up by block name to ids */
std::map<std::string, ConfigBlockId> block_name2ids_;
/* The ids of the inputs of routing multiplexer blocks which is propagated to
* outputs By default, it will be -2 (which is invalid) A valid id starts from
* -1 -1 indicates an unused routing multiplexer. It will be converted to a

View File

@ -68,6 +68,7 @@ constexpr const char* INV_PORT_POSTFIX = "_inv";
/* Bitstream file strings */
constexpr const char* BITSTREAM_XML_FILE_NAME_POSTFIX = "_bitstream.xml";
constexpr const char* DEFAULT_TILE_DIR_NAME = "tile/";
constexpr const char* DEFAULT_LB_DIR_NAME = "lb/";
constexpr const char* DEFAULT_RR_DIR_NAME = "routing/";
constexpr const char* DEFAULT_SUBMODULE_DIR_NAME = "sub_module/";

View File

@ -0,0 +1,37 @@
cmake_minimum_required(VERSION 3.9)
project("libtileconfig")
file(GLOB_RECURSE EXEC_SOURCES test/*.cpp)
file(GLOB_RECURSE LIB_SOURCES src/*/*.cpp)
file(GLOB_RECURSE LIB_HEADERS src/*/*.h)
files_to_dirs(LIB_HEADERS LIB_INCLUDE_DIRS)
#Remove test executable from library
list(REMOVE_ITEM LIB_SOURCES ${EXEC_SOURCES})
#Create the library
add_library(libtileconfig STATIC
${LIB_HEADERS}
${LIB_SOURCES})
target_include_directories(libtileconfig PUBLIC ${LIB_INCLUDE_DIRS})
set_target_properties(libtileconfig PROPERTIES PREFIX "") #Avoid extra 'lib' prefix
#Specify link-time dependancies
target_link_libraries(libtileconfig
libarchopenfpga
libopenfpgautil
libopenfpgashell
libvtrutil
libpugiutil)
#Create the test executable
foreach(testsourcefile ${EXEC_SOURCES})
# Use a simple string replace, to cut off .cpp.
get_filename_component(testname ${testsourcefile} NAME_WE)
add_executable(${testname} ${testsourcefile})
# Make sure the library is linked to each test executable
target_link_libraries(${testname} libtileconfig)
endforeach(testsourcefile ${EXEC_SOURCES})
install(TARGETS libtileconfig DESTINATION bin)

View File

@ -0,0 +1 @@
<tiles style="top_left"/>

View File

@ -0,0 +1,76 @@
/******************************************************************************
* Memember functions for data structure TileConfig
******************************************************************************/
#include "tile_config.h"
#include <algorithm>
#include "command_exit_codes.h"
#include "vtr_assert.h"
#include "vtr_log.h"
#include "vtr_time.h"
/* begin namespace openfpga */
namespace openfpga {
TileConfig::TileConfig() {
style_ = TileConfig::e_style::NUM_TYPES; /* Deposit an invalid value */
STYLE_STRING_ = {"top_left", "top_right", "bottom_left", "bottom_right",
"custom"};
}
/**************************************************
* Public Accessors
*************************************************/
TileConfig::e_style TileConfig::style() const { return style_; }
std::string TileConfig::style_to_string() const { return style2str(style_); }
bool TileConfig::is_valid() const {
return style_ != TileConfig::e_style::NUM_TYPES;
}
int TileConfig::set_style(const std::string& value) {
style_ = str2style(value);
return valid_style(style_);
}
std::string TileConfig::style_all2str() const {
std::string full_types = "[";
for (int itype = size_t(TileConfig::e_style::TOP_LEFT);
itype != size_t(TileConfig::e_style::NUM_TYPES); ++itype) {
full_types += std::string(STYLE_STRING_[itype]) + std::string("|");
}
full_types.pop_back();
full_types += "]";
return full_types;
}
TileConfig::e_style TileConfig::str2style(const std::string& style_str,
const bool& verbose) const {
for (int itype = size_t(TileConfig::e_style::TOP_LEFT);
itype != size_t(TileConfig::e_style::NUM_TYPES); ++itype) {
if (style_str == std::string(STYLE_STRING_[itype])) {
return static_cast<TileConfig::e_style>(itype);
}
}
VTR_LOGV_ERROR(verbose, "Invalid style for tile configuration! Expect %s\n",
style_all2str().c_str());
return TileConfig::e_style::NUM_TYPES;
}
std::string TileConfig::style2str(const TileConfig::e_style& style,
const bool& verbose) const {
if (!valid_style(style)) {
VTR_LOGV_ERROR(verbose, "Invalid style for tile configuration! Expect %s\n",
style_all2str().c_str());
return std::string();
}
return std::string(STYLE_STRING_[size_t(style)]);
}
bool TileConfig::valid_style(const TileConfig::e_style& style) const {
return style != TileConfig::e_style::NUM_TYPES;
}
} /* end namespace openfpga */

View File

@ -0,0 +1,67 @@
#ifndef TILE_CONFIG_H
#define TILE_CONFIG_H
/********************************************************************
* Include header files required by the data structure definition
*******************************************************************/
#include <array>
#include <string>
/* Begin namespace openfpga */
namespace openfpga {
/**
* @brief tile configuration is a data structure to represent how programmable
* blocks and routing blocks are grouped into tiles
*/
class TileConfig {
public: /* Types */
enum class e_style {
TOP_LEFT = 0,
TOP_RIGHT,
BOTTOM_LEFT,
BOTTOM_RIGHT,
CUSTOM,
NUM_TYPES
};
public: /* Constructors */
TileConfig();
public: /* Public accessors */
/** @brief Get all the fpga style */
e_style style() const;
std::string style_to_string() const;
public: /* Public mutators */
/** @brief Create the one-on-one mapping between an port of fpga_top and
* fpga_core. Return 0 for success, return 1 for fail */
int set_style(const std::string& value);
public: /* Public utility */
/** @brief identify if the tile config is valid or not */
bool is_valid() const;
/** @brief Parse the style from string to valid type. Parser
* error can be turned on */
e_style str2style(const std::string& style_str,
const bool& verbose = false) const;
/** @brief Output the string representing style */
std::string style2str(const e_style& style,
const bool& verbose = false) const;
/** @brief Validate the style */
bool valid_style(const e_style& style) const;
private: /* Internal utility */
/* Generate a string include all the valid style
* Useful for printing debugging messages */
std::string style_all2str() const;
private: /* Internal Data */
e_style style_;
/* Constants */
std::array<const char*, size_t(e_style::NUM_TYPES)> STYLE_STRING_;
};
} /* End namespace openfpga*/
#endif

View File

@ -0,0 +1,55 @@
/********************************************************************
* This file includes the top-level function of this library
* which reads an XML of clock network file to the associated
* data structures
*******************************************************************/
#include <string>
/* Headers from pugi XML library */
#include "pugixml.hpp"
#include "pugixml_util.hpp"
/* Headers from vtr util library */
#include "vtr_assert.h"
#include "vtr_log.h"
#include "vtr_time.h"
/* Headers from libarchfpga */
#include "arch_error.h"
#include "command_exit_codes.h"
#include "read_xml_tile_config.h"
#include "read_xml_util.h"
#include "tile_config_xml_constants.h"
namespace openfpga { // Begin namespace openfpga
/********************************************************************
* Parse XML codes about <ports> to an object of ClockNetwork
*******************************************************************/
int read_xml_tile_config(const char* fname, TileConfig& tile_config) {
vtr::ScopedStartFinishTimer timer("Read tile configuration rules");
int status = CMD_EXEC_SUCCESS;
/* Parse the file */
pugi::xml_document doc;
pugiutil::loc_data loc_data;
try {
loc_data = pugiutil::load_xml(doc, fname);
pugi::xml_node xml_root =
get_single_child(doc, XML_TILE_CONFIG_ROOT_NAME, loc_data);
std::string style =
get_attribute(xml_root, XML_TILE_CONFIG_ATTRIBUTE_STYLE_NAME, loc_data)
.as_string();
tile_config.set_style(style);
} catch (pugiutil::XmlError& e) {
archfpga_throw(fname, e.line(), "%s", e.what());
}
return status;
}
} // End of namespace openfpga

View File

@ -0,0 +1,21 @@
#ifndef READ_XML_TILE_CONFIG_H
#define READ_XML_TILE_CONFIG_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include "pugixml.hpp"
#include "pugixml_util.hpp"
#include "tile_config.h"
/********************************************************************
* Function declaration
*******************************************************************/
namespace openfpga { // Begin namespace openfpga
int read_xml_tile_config(const char* fname, TileConfig& tile_config);
} // End of namespace openfpga
#endif

View File

@ -0,0 +1,8 @@
#ifndef TILE_CONFIG_XML_CONSTANTS_H
#define TILE_CONFIG_XML_CONSTANTS_H
/* Constants required by XML parser */
constexpr const char* XML_TILE_CONFIG_ROOT_NAME = "tiles";
constexpr const char* XML_TILE_CONFIG_ATTRIBUTE_STYLE_NAME = "style";
#endif

View File

@ -0,0 +1,59 @@
/********************************************************************
* This file includes functions that outputs a clock network object to XML
*format
*******************************************************************/
/* Headers from system goes first */
#include <algorithm>
#include <string>
/* Headers from vtr util library */
#include "vtr_assert.h"
#include "vtr_log.h"
#include "vtr_time.h"
/* Headers from arch openfpga library */
#include "openfpga_digest.h"
#include "write_xml_utils.h"
/* Headers from pin constraint library */
#include "tile_config_xml_constants.h"
#include "write_xml_tile_config.h"
namespace openfpga { // Begin namespace openfpga
/********************************************************************
* A writer to output an object to XML format
*
* Return 0 if successful
* Return 1 if there are more serious bugs in the architecture
* Return 2 if fail when creating files
*******************************************************************/
int write_xml_tile_config(const char* fname, const TileConfig& tile_config) {
vtr::ScopedStartFinishTimer timer("Write tile configuration rules");
/* Create a file handler */
std::fstream fp;
/* Open the file stream */
fp.open(std::string(fname), std::fstream::out | std::fstream::trunc);
/* Validate the file stream */
openfpga::check_file_stream(fname, fp);
int err_code = 0;
/* Write the root node */
fp << "<" << XML_TILE_CONFIG_ROOT_NAME;
write_xml_attribute(fp, XML_TILE_CONFIG_ATTRIBUTE_STYLE_NAME,
tile_config.style_to_string().c_str());
/* Finish writing the root node */
fp << "/>"
<< "\n";
/* Close the file stream */
fp.close();
return err_code;
}
} // End of namespace openfpga

View File

@ -0,0 +1,20 @@
#ifndef WRITE_XML_TILE_CONFIG_H
#define WRITE_XML_TILE_CONFIG_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <fstream>
#include "tile_config.h"
/********************************************************************
* Function declaration
*******************************************************************/
namespace openfpga { // Begin namespace openfpga
int write_xml_tile_config(const char* fname, const TileConfig& tile_config);
} // End of namespace openfpga
#endif

View File

@ -0,0 +1,37 @@
/********************************************************************
* Unit test functions to validate the correctness of
* 1. parser of data structures
* 2. writer of data structures
*******************************************************************/
/* Headers from vtrutils */
#include "vtr_assert.h"
#include "vtr_log.h"
/* Headers from readarchopenfpga */
#include "read_xml_tile_config.h"
#include "write_xml_tile_config.h"
int main(int argc, const char** argv) {
/* Ensure we have only one or two argument */
VTR_ASSERT((2 == argc) || (3 == argc));
int status = 0;
/* Parse the circuit library from an XML file */
openfpga::TileConfig tile_config;
status = openfpga::read_xml_tile_config(argv[1], tile_config);
if (status != 0) {
return status;
}
VTR_LOG("Parsed tile configuration from XML file: %s\n", argv[1]);
/* Output the bus group to an XML file
* This is optional only used when there is a second argument
*/
if (3 <= argc) {
status = openfpga::write_xml_tile_config(argv[2], tile_config);
VTR_LOG("Write the tile configuration to an XML file: %s.\n", argv[2]);
}
return status;
}

View File

@ -42,6 +42,7 @@ target_link_libraries(libopenfpga
libvtrutil
libbusgroup
libionamemap
libtileconfig
libpugixml
libvpr)

View File

@ -145,34 +145,14 @@ const RRGSB& DeviceRRGSB::get_cb_unique_module(const t_rr_type& cb_type,
/* Give a coordinate of a rr switch block, and return its unique mirror */
const RRGSB& DeviceRRGSB::get_cb_unique_module(
const t_rr_type& cb_type, const vtr::Point<size_t>& coordinate) const {
VTR_ASSERT(validate_cb_type(cb_type));
VTR_ASSERT(validate_coordinate(coordinate));
size_t cb_unique_module_id;
switch (cb_type) {
case CHANX:
cb_unique_module_id =
cbx_unique_module_id_[coordinate.x()][coordinate.y()];
break;
case CHANY:
cb_unique_module_id =
cby_unique_module_id_[coordinate.x()][coordinate.y()];
break;
default:
VTR_LOG_ERROR("Invalid type of connection block!\n");
exit(1);
}
return get_cb_unique_module(cb_type, cb_unique_module_id);
return get_cb_unique_module(cb_type,
get_cb_unique_module_index(cb_type, coordinate));
}
/* Give a coordinate of a rr switch block, and return its unique mirror */
const RRGSB& DeviceRRGSB::get_sb_unique_module(
const vtr::Point<size_t>& coordinate) const {
VTR_ASSERT(validate_coordinate(coordinate));
size_t sb_unique_module_id =
sb_unique_module_id_[coordinate.x()][coordinate.y()];
return get_sb_unique_module(sb_unique_module_id);
return get_sb_unique_module(get_sb_unique_module_index(coordinate));
}
/************************************************************************
@ -550,4 +530,35 @@ bool DeviceRRGSB::validate_cb_type(const t_rr_type& cb_type) const {
return ((CHANX == cb_type) || (CHANY == cb_type));
}
size_t DeviceRRGSB::get_sb_unique_module_index(
const vtr::Point<size_t>& coordinate) const {
VTR_ASSERT(validate_coordinate(coordinate));
size_t sb_unique_module_id =
sb_unique_module_id_[coordinate.x()][coordinate.y()];
return sb_unique_module_id;
}
size_t DeviceRRGSB::get_cb_unique_module_index(
const t_rr_type& cb_type, const vtr::Point<size_t>& coordinate) const {
VTR_ASSERT(validate_cb_type(cb_type));
VTR_ASSERT(validate_coordinate(coordinate));
size_t cb_unique_module_id;
switch (cb_type) {
case CHANX:
cb_unique_module_id =
cbx_unique_module_id_[coordinate.x()][coordinate.y()];
break;
case CHANY:
cb_unique_module_id =
cby_unique_module_id_[coordinate.x()][coordinate.y()];
break;
default:
VTR_LOG_ERROR("Invalid type of connection block!\n");
exit(1);
}
return cb_unique_module_id;
}
} /* End namespace openfpga*/

View File

@ -59,6 +59,13 @@ class DeviceRRGSB {
size_t get_num_cb_unique_module(const t_rr_type& cb_type)
const; /* get the number of unique mirrors of CBs */
bool is_gsb_exist(const vtr::Point<size_t> coord) const;
/* Get the index of the unique Switch block module with a given GSB
* coordinate. Note: Do NOT use sb coordinate!!! */
size_t get_sb_unique_module_index(const vtr::Point<size_t>& coordinate) const;
/* Get the index of the unique Connection block module with a given GSB
* coordinate. Note: Do NOT use sb coordinate!!! */
size_t get_cb_unique_module_index(const t_rr_type& cb_type,
const vtr::Point<size_t>& coordinate) const;
public: /* Mutators */
void reserve(

View File

@ -0,0 +1,625 @@
/************************************************************************
* Member functions for class FabricTile
***********************************************************************/
#include "fabric_tile.h"
#include "build_top_module_utils.h"
#include "vtr_assert.h"
#include "vtr_log.h"
/* namespace openfpga begins */
namespace openfpga {
vtr::Point<size_t> FabricTile::tile_coordinate(
const FabricTileId& tile_id) const {
VTR_ASSERT(valid_tile_id(tile_id));
return coords_[tile_id];
}
vtr::Point<size_t> FabricTile::unique_tile_coordinate(
const FabricTileId& tile_id) const {
vtr::Point<size_t> tile_coord = tile_coordinate(tile_id);
FabricTileId unique_fabric_tile_id = unique_tile(tile_coord);
return tile_coordinate(unique_fabric_tile_id);
}
std::vector<vtr::Point<size_t>> FabricTile::pb_coordinates(
const FabricTileId& tile_id) const {
VTR_ASSERT(valid_tile_id(tile_id));
return pb_coords_[tile_id];
}
std::vector<vtr::Point<size_t>> FabricTile::cb_coordinates(
const FabricTileId& tile_id, const t_rr_type& cb_type) const {
VTR_ASSERT(valid_tile_id(tile_id));
switch (cb_type) {
case CHANX:
return cbx_coords_[tile_id];
case CHANY:
return cby_coords_[tile_id];
default:
VTR_LOG("Invalid type of connection block!\n");
exit(1);
}
return std::vector<vtr::Point<size_t>>();
}
std::vector<vtr::Point<size_t>> FabricTile::sb_coordinates(
const FabricTileId& tile_id) const {
VTR_ASSERT(valid_tile_id(tile_id));
return sb_coords_[tile_id];
}
FabricTileId FabricTile::unique_tile(const vtr::Point<size_t>& coord) const {
/* Return invalid Id when out of range! */
if (coord.x() < tile_coord2unique_tile_ids_.size()) {
if (coord.y() < tile_coord2unique_tile_ids_[coord.x()].size()) {
return tile_coord2unique_tile_ids_[coord.x()][coord.y()];
}
}
return FabricTileId::INVALID();
}
FabricTileId FabricTile::find_tile(const vtr::Point<size_t>& coord) const {
if (coord.x() >= tile_coord2id_lookup_.size()) {
VTR_LOG_ERROR(
"Tile coordinate [%lu][%lu] exceeds the maximum range [%lu][%lu]!\n",
coord.x(), coord.y(), tile_coord2id_lookup_.size(),
tile_coord2id_lookup_[0].size());
return FabricTileId::INVALID();
}
if (coord.y() >= tile_coord2id_lookup_[coord.x()].size()) {
VTR_LOG_ERROR(
"Tile coordinate [%lu][%lu] exceeds the maximum range [%lu][%lu]!\n",
coord.x(), coord.y(), tile_coord2id_lookup_.size(),
tile_coord2id_lookup_[0].size());
return FabricTileId::INVALID();
}
return tile_coord2id_lookup_[coord.x()][coord.y()];
}
FabricTileId FabricTile::find_tile_by_pb_coordinate(
const vtr::Point<size_t>& coord) const {
if (pb_coord2id_lookup_.empty()) {
return FabricTileId::INVALID();
}
if (coord.x() >= pb_coord2id_lookup_.size()) {
VTR_LOG_ERROR(
"Programmable block coordinate [%lu][%lu] exceeds the maximum range "
"[%lu][%lu]!\n",
coord.x(), coord.y(), pb_coord2id_lookup_.size(),
pb_coord2id_lookup_[0].size());
return FabricTileId::INVALID();
}
if (coord.y() >= pb_coord2id_lookup_[coord.x()].size()) {
VTR_LOG_ERROR(
"Programmable block coordinate [%lu][%lu] exceeds the maximum range "
"[%lu][%lu]!\n",
coord.x(), coord.y(), pb_coord2id_lookup_.size(),
pb_coord2id_lookup_[0].size());
return FabricTileId::INVALID();
}
return pb_coord2id_lookup_[coord.x()][coord.y()];
}
FabricTileId FabricTile::find_tile_by_cb_coordinate(
const t_rr_type& cb_type, const vtr::Point<size_t>& coord) const {
switch (cb_type) {
case CHANX: {
if (cbx_coord2id_lookup_.empty()) {
return FabricTileId::INVALID();
}
if (coord.x() >= cbx_coord2id_lookup_.size()) {
VTR_LOG_ERROR(
"X-direction connection block coordinate [%lu][%lu] exceeds the "
"maximum range [%lu][%lu]!\n",
coord.x(), coord.y(), cbx_coord2id_lookup_.size(),
cbx_coord2id_lookup_[0].size());
return FabricTileId::INVALID();
}
if (coord.y() >= cbx_coord2id_lookup_[coord.x()].size()) {
VTR_LOG_ERROR(
"X-direction connection block coordinate [%lu][%lu] exceeds the "
"maximum range [%lu][%lu]!\n",
coord.x(), coord.y(), cbx_coord2id_lookup_.size(),
cbx_coord2id_lookup_[0].size());
return FabricTileId::INVALID();
}
return cbx_coord2id_lookup_[coord.x()][coord.y()];
}
case CHANY: {
if (cby_coord2id_lookup_.empty()) {
return FabricTileId::INVALID();
}
if (coord.x() >= cby_coord2id_lookup_.size()) {
VTR_LOG_ERROR(
"Y-direction connection block coordinate [%lu][%lu] exceeds the "
"maximum range [%lu][%lu]!\n",
coord.x(), coord.y(), cby_coord2id_lookup_.size(),
cby_coord2id_lookup_[0].size());
return FabricTileId::INVALID();
}
if (coord.y() >= cby_coord2id_lookup_[coord.x()].size()) {
VTR_LOG_ERROR(
"Y-direction connection block coordinate [%lu][%lu] exceeds the "
"maximum range [%lu][%lu]!\n",
coord.x(), coord.y(), cby_coord2id_lookup_.size(),
cby_coord2id_lookup_[0].size());
return FabricTileId::INVALID();
}
return cby_coord2id_lookup_[coord.x()][coord.y()];
}
default:
VTR_LOG("Invalid type of connection block!\n");
exit(1);
}
}
FabricTileId FabricTile::find_tile_by_sb_coordinate(
const vtr::Point<size_t>& coord) const {
if (sb_coord2id_lookup_.empty()) {
return FabricTileId::INVALID();
}
if (coord.x() >= sb_coord2id_lookup_.size()) {
VTR_LOG_ERROR(
"Switch block coordinate [%lu][%lu] exceeds the maximum range "
"[%lu][%lu]!\n",
coord.x(), coord.y(), sb_coord2id_lookup_.size(),
sb_coord2id_lookup_[0].size());
return FabricTileId::INVALID();
}
if (coord.y() >= sb_coord2id_lookup_[coord.x()].size()) {
VTR_LOG_ERROR(
"Switch block coordinate [%lu][%lu] exceeds the maximum range "
"[%lu][%lu]!\n",
coord.x(), coord.y(), sb_coord2id_lookup_.size(),
sb_coord2id_lookup_[0].size());
return FabricTileId::INVALID();
}
return sb_coord2id_lookup_[coord.x()][coord.y()];
}
bool FabricTile::pb_in_tile(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord,
const bool& use_gsb_coord) const {
if (use_gsb_coord) {
return !pb_gsb_coords_[tile_id].empty() &&
find_pb_index_in_tile(tile_id, coord, use_gsb_coord) !=
pb_gsb_coords_[tile_id].size();
}
return !pb_coords_[tile_id].empty() &&
find_pb_index_in_tile(tile_id, coord) != pb_coords_[tile_id].size();
}
size_t FabricTile::find_pb_index_in_tile(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord,
const bool& use_gsb_coord) const {
VTR_ASSERT(valid_tile_id(tile_id));
if (use_gsb_coord) {
for (size_t idx = 0; idx < pb_gsb_coords_[tile_id].size(); ++idx) {
vtr::Point<size_t> curr_coord = pb_gsb_coords_[tile_id][idx];
if (curr_coord == coord) {
return idx;
}
}
/* Not found, return an invalid index */
return pb_gsb_coords_[tile_id].size();
} else {
for (size_t idx = 0; idx < pb_coords_[tile_id].size(); ++idx) {
vtr::Point<size_t> curr_coord = pb_coords_[tile_id][idx];
if (curr_coord == coord) {
return idx;
}
}
/* Not found, return an invalid index */
return pb_coords_[tile_id].size();
}
}
bool FabricTile::sb_in_tile(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord) const {
return !sb_coords_[tile_id].empty() &&
find_sb_index_in_tile(tile_id, coord) != sb_coords_[tile_id].size();
}
size_t FabricTile::find_sb_index_in_tile(
const FabricTileId& tile_id, const vtr::Point<size_t>& coord) const {
VTR_ASSERT(valid_tile_id(tile_id));
for (size_t idx = 0; idx < sb_coords_[tile_id].size(); ++idx) {
vtr::Point<size_t> curr_coord = sb_coords_[tile_id][idx];
if (curr_coord == coord) {
return idx;
}
}
/* Not found, return an invalid index */
return sb_coords_[tile_id].size();
}
bool FabricTile::cb_in_tile(const FabricTileId& tile_id,
const t_rr_type& cb_type,
const vtr::Point<size_t>& coord) const {
switch (cb_type) {
case CHANX:
return !cbx_coords_[tile_id].empty() &&
find_cb_index_in_tile(tile_id, cb_type, coord) ==
cbx_coords_[tile_id].size();
case CHANY:
return !cby_coords_[tile_id].empty() &&
find_cb_index_in_tile(tile_id, cb_type, coord) ==
cby_coords_[tile_id].size();
default:
VTR_LOG("Invalid type of connection block!\n");
exit(1);
}
}
size_t FabricTile::find_cb_index_in_tile(
const FabricTileId& tile_id, const t_rr_type& cb_type,
const vtr::Point<size_t>& coord) const {
VTR_ASSERT(valid_tile_id(tile_id));
switch (cb_type) {
case CHANX:
for (size_t idx = 0; idx < cbx_coords_[tile_id].size(); ++idx) {
vtr::Point<size_t> curr_coord = cbx_coords_[tile_id][idx];
if (curr_coord == coord) {
return idx;
}
}
return cbx_coords_[tile_id].size();
case CHANY:
for (size_t idx = 0; idx < cby_coords_[tile_id].size(); ++idx) {
vtr::Point<size_t> curr_coord = cby_coords_[tile_id][idx];
if (curr_coord == coord) {
return idx;
}
}
return cby_coords_[tile_id].size();
default:
VTR_LOG("Invalid type of connection block!\n");
exit(1);
}
}
std::vector<FabricTileId> FabricTile::unique_tiles() const {
return unique_tile_ids_;
}
bool FabricTile::empty() const { return ids_.empty(); }
FabricTileId FabricTile::create_tile(const vtr::Point<size_t>& coord) {
FabricTileId tile_id = FabricTileId(ids_.size());
ids_.push_back(tile_id);
coords_.push_back(coord);
pb_coords_.emplace_back();
pb_gsb_coords_.emplace_back();
cbx_coords_.emplace_back();
cby_coords_.emplace_back();
sb_coords_.emplace_back();
/* Register in fast look-up */
if (register_tile_in_lookup(tile_id, coord)) {
return tile_id;
}
return FabricTileId::INVALID();
}
void FabricTile::init(const vtr::Point<size_t>& max_coord) {
tile_coord2id_lookup_.resize(max_coord.x());
pb_coord2id_lookup_.resize(max_coord.x());
cbx_coord2id_lookup_.resize(max_coord.x());
cby_coord2id_lookup_.resize(max_coord.x());
sb_coord2id_lookup_.resize(max_coord.x());
for (size_t ix = 0; ix < max_coord.x(); ++ix) {
tile_coord2id_lookup_[ix].resize(max_coord.y(), FabricTileId::INVALID());
pb_coord2id_lookup_[ix].resize(max_coord.y(), FabricTileId::INVALID());
cbx_coord2id_lookup_[ix].resize(max_coord.y(), FabricTileId::INVALID());
cby_coord2id_lookup_[ix].resize(max_coord.y(), FabricTileId::INVALID());
sb_coord2id_lookup_[ix].resize(max_coord.y(), FabricTileId::INVALID());
}
tile_coord2unique_tile_ids_.resize(max_coord.x());
for (size_t ix = 0; ix < max_coord.x(); ++ix) {
tile_coord2unique_tile_ids_[ix].resize(max_coord.y(),
FabricTileId::INVALID());
}
}
bool FabricTile::register_tile_in_lookup(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord) {
if (coord.x() >= tile_coord2id_lookup_.size()) {
VTR_LOG_ERROR(
"Fast look-up has not been re-allocated properly! Given x='%lu' exceeds "
"the upper-bound '%lu'!\n",
coord.x(), tile_coord2id_lookup_.size());
return false;
}
if (coord.y() >= tile_coord2id_lookup_[coord.x()].size()) {
VTR_LOG_ERROR(
"Fast look-up has not been re-allocated properly! Given y='%lu' exceeds "
"the upper-bound '%lu'!\n",
coord.y(), tile_coord2id_lookup_[coord.x()].size());
return false;
}
/* Throw error if this coord is already registered! */
if (tile_coord2id_lookup_[coord.x()][coord.y()]) {
VTR_LOG_ERROR("Tile at [%lu][%lu] has already been registered!\n");
return false;
}
tile_coord2id_lookup_[coord.x()][coord.y()] = tile_id;
return true;
}
bool FabricTile::register_pb_in_lookup(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord) {
if (coord.x() >= pb_coord2id_lookup_.size()) {
VTR_LOG_ERROR(
"Fast look-up has not been re-allocated properly! Given x='%lu' exceeds "
"the upper-bound '%lu'!\n",
coord.x(), pb_coord2id_lookup_.size());
return false;
}
if (coord.y() >= pb_coord2id_lookup_[coord.x()].size()) {
VTR_LOG_ERROR(
"Fast look-up has not been re-allocated properly! Given y='%lu' exceeds "
"the upper-bound '%lu'!\n",
coord.y(), pb_coord2id_lookup_[coord.x()].size());
return false;
}
/* Throw error if this coord is already registered! */
if (pb_coord2id_lookup_[coord.x()][coord.y()]) {
VTR_LOG_ERROR(
"Programmable block at [%lu][%lu] has already been registered!\n");
return false;
}
pb_coord2id_lookup_[coord.x()][coord.y()] = tile_id;
return true;
}
bool FabricTile::register_cbx_in_lookup(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord) {
if (coord.x() >= cbx_coord2id_lookup_.size()) {
VTR_LOG_ERROR(
"Fast look-up has not been re-allocated properly! Given x='%lu' exceeds "
"the upper-bound '%lu'!\n",
coord.x(), cbx_coord2id_lookup_.size());
return false;
}
if (coord.y() >= cbx_coord2id_lookup_[coord.x()].size()) {
VTR_LOG_ERROR(
"Fast look-up has not been re-allocated properly! Given y='%lu' exceeds "
"the upper-bound '%lu'!\n",
coord.y(), cbx_coord2id_lookup_[coord.x()].size());
return false;
}
/* Throw error if this coord is already registered! */
if (cbx_coord2id_lookup_[coord.x()][coord.y()]) {
VTR_LOG_ERROR(
"X-direction connection block at [%lu][%lu] has already been "
"registered!\n");
return false;
}
cbx_coord2id_lookup_[coord.x()][coord.y()] = tile_id;
return true;
}
bool FabricTile::register_cby_in_lookup(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord) {
if (coord.x() >= cby_coord2id_lookup_.size()) {
VTR_LOG_ERROR(
"Fast look-up has not been re-allocated properly! Given x='%lu' exceeds "
"the upper-bound '%lu'!\n",
coord.x(), cby_coord2id_lookup_.size());
return false;
}
if (coord.y() >= cby_coord2id_lookup_[coord.x()].size()) {
VTR_LOG_ERROR(
"Fast look-up has not been re-allocated properly! Given y='%lu' exceeds "
"the upper-bound '%lu'!\n",
coord.y(), cby_coord2id_lookup_[coord.x()].size());
return false;
}
/* Throw error if this coord is already registered! */
if (cby_coord2id_lookup_[coord.x()][coord.y()]) {
VTR_LOG_ERROR(
"Y-direction connection block at [%lu][%lu] has already been "
"registered!\n");
return false;
}
cby_coord2id_lookup_[coord.x()][coord.y()] = tile_id;
return true;
}
bool FabricTile::register_sb_in_lookup(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord) {
if (coord.x() >= sb_coord2id_lookup_.size()) {
VTR_LOG_ERROR(
"Fast look-up has not been re-allocated properly! Given x='%lu' exceeds "
"the upper-bound '%lu'!\n",
coord.x(), sb_coord2id_lookup_.size());
return false;
}
if (coord.y() >= sb_coord2id_lookup_[coord.x()].size()) {
VTR_LOG_ERROR(
"Fast look-up has not been re-allocated properly! Given y='%lu' exceeds "
"the upper-bound '%lu'!\n",
coord.y(), sb_coord2id_lookup_[coord.x()].size());
return false;
}
/* Throw error if this coord is already registered! */
if (sb_coord2id_lookup_[coord.x()][coord.y()]) {
VTR_LOG_ERROR("Switch block at [%lu][%lu] has already been registered!\n");
return false;
}
sb_coord2id_lookup_[coord.x()][coord.y()] = tile_id;
return true;
}
void FabricTile::invalidate_tile_in_lookup(const vtr::Point<size_t>& coord) {
tile_coord2id_lookup_[coord.x()][coord.y()] = FabricTileId::INVALID();
}
void FabricTile::invalidate_pb_in_lookup(const vtr::Point<size_t>& coord) {
pb_coord2id_lookup_[coord.x()][coord.y()] = FabricTileId::INVALID();
}
void FabricTile::invalidate_cbx_in_lookup(const vtr::Point<size_t>& coord) {
cbx_coord2id_lookup_[coord.x()][coord.y()] = FabricTileId::INVALID();
}
void FabricTile::invalidate_cby_in_lookup(const vtr::Point<size_t>& coord) {
cby_coord2id_lookup_[coord.x()][coord.y()] = FabricTileId::INVALID();
}
void FabricTile::invalidate_sb_in_lookup(const vtr::Point<size_t>& coord) {
sb_coord2id_lookup_[coord.x()][coord.y()] = FabricTileId::INVALID();
}
bool FabricTile::set_tile_coordinate(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord) {
VTR_ASSERT(valid_tile_id(tile_id));
/* Invalidate previous coordinate in look-up */
invalidate_tile_in_lookup(coords_[tile_id]);
/* update coordinate */
coords_[tile_id] = coord;
/* Register in fast look-up */
return register_tile_in_lookup(tile_id, coord);
}
int FabricTile::add_pb_coordinate(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord,
const vtr::Point<size_t>& gsb_coord) {
VTR_ASSERT(valid_tile_id(tile_id));
pb_coords_[tile_id].push_back(coord);
pb_gsb_coords_[tile_id].push_back(gsb_coord);
/* Register in fast look-up */
return register_pb_in_lookup(tile_id, coord);
}
int FabricTile::add_cb_coordinate(const FabricTileId& tile_id,
const t_rr_type& cb_type,
const vtr::Point<size_t>& coord) {
VTR_ASSERT(valid_tile_id(tile_id));
switch (cb_type) {
case CHANX:
cbx_coords_[tile_id].push_back(coord);
/* Register in fast look-up */
return register_cbx_in_lookup(tile_id, coord);
case CHANY:
cby_coords_[tile_id].push_back(coord);
/* Register in fast look-up */
return register_cby_in_lookup(tile_id, coord);
default:
VTR_LOG("Invalid type of connection block!\n");
exit(1);
}
}
int FabricTile::add_sb_coordinate(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord) {
VTR_ASSERT(valid_tile_id(tile_id));
sb_coords_[tile_id].push_back(coord);
/* Register in fast look-up */
return register_sb_in_lookup(tile_id, coord);
}
void FabricTile::clear() {
ids_.clear();
coords_.clear();
pb_coords_.clear();
pb_gsb_coords_.clear();
cbx_coords_.clear();
cby_coords_.clear();
sb_coords_.clear();
tile_coord2id_lookup_.clear();
pb_coord2id_lookup_.clear();
cbx_coord2id_lookup_.clear();
cby_coord2id_lookup_.clear();
sb_coord2id_lookup_.clear();
tile_coord2unique_tile_ids_.clear();
unique_tile_ids_.clear();
}
bool FabricTile::valid_tile_id(const FabricTileId& tile_id) const {
return (size_t(tile_id) < ids_.size()) && (tile_id == ids_[tile_id]);
}
bool FabricTile::equivalent_tile(const FabricTileId& tile_a,
const FabricTileId& tile_b,
const DeviceGrid& grids,
const DeviceRRGSB& device_rr_gsb) const {
/* The number of cbx, cby and sb blocks should be the same */
if (pb_coords_[tile_a].size() != pb_coords_[tile_b].size() ||
pb_gsb_coords_[tile_a].size() != pb_gsb_coords_[tile_b].size() ||
cbx_coords_[tile_a].size() != cbx_coords_[tile_b].size() ||
cby_coords_[tile_a].size() != cby_coords_[tile_b].size() ||
sb_coords_[tile_a].size() != sb_coords_[tile_b].size()) {
return false;
}
/* The pb of two tiles should be the same, otherwise not equivalent */
for (size_t iblk = 0; iblk < pb_coords_[tile_a].size(); ++iblk) {
vtr::Point<size_t> tile_a_pb_coord = pb_coords_[tile_a][iblk];
vtr::Point<size_t> tile_b_pb_coord = pb_coords_[tile_b][iblk];
if (generate_grid_block_module_name_in_top_module(std::string(), grids,
tile_a_pb_coord) !=
generate_grid_block_module_name_in_top_module(std::string(), grids,
tile_b_pb_coord)) {
return false;
}
}
/* Each CBx should have the same unique modules in the device rr_gsb */
for (size_t iblk = 0; iblk < cbx_coords_[tile_a].size(); ++iblk) {
if (device_rr_gsb.get_cb_unique_module_index(CHANX,
cbx_coords_[tile_a][iblk]) !=
device_rr_gsb.get_cb_unique_module_index(CHANX,
cbx_coords_[tile_b][iblk])) {
return false;
}
}
for (size_t iblk = 0; iblk < cby_coords_[tile_a].size(); ++iblk) {
if (device_rr_gsb.get_cb_unique_module_index(CHANY,
cby_coords_[tile_a][iblk]) !=
device_rr_gsb.get_cb_unique_module_index(CHANY,
cby_coords_[tile_b][iblk])) {
return false;
}
}
for (size_t iblk = 0; iblk < sb_coords_[tile_a].size(); ++iblk) {
if (device_rr_gsb.get_sb_unique_module_index(sb_coords_[tile_a][iblk]) !=
device_rr_gsb.get_sb_unique_module_index(sb_coords_[tile_b][iblk])) {
return false;
}
}
return true;
}
int FabricTile::build_unique_tiles(const DeviceGrid& grids,
const DeviceRRGSB& device_rr_gsb) {
for (size_t ix = 0; ix < grids.width(); ++ix) {
for (size_t iy = 0; iy < grids.height(); ++iy) {
if (!valid_tile_id(tile_coord2id_lookup_[ix][iy])) {
continue; /* Skip invalid tile (which does not exist) */
}
bool is_unique_tile = true;
for (FabricTileId unique_tile_id : unique_tile_ids_) {
if (equivalent_tile(tile_coord2id_lookup_[ix][iy], unique_tile_id,
grids, device_rr_gsb)) {
is_unique_tile = false;
tile_coord2unique_tile_ids_[ix][iy] = unique_tile_id;
break;
}
}
/* Update list if this is a unique tile */
if (is_unique_tile) {
unique_tile_ids_.push_back(tile_coord2id_lookup_[ix][iy]);
tile_coord2unique_tile_ids_[ix][iy] = tile_coord2id_lookup_[ix][iy];
}
}
}
return 0;
}
} /* End namespace openfpga*/

View File

@ -0,0 +1,167 @@
#ifndef FABRIC_TILE_H
#define FABRIC_TILE_H
/********************************************************************
* Include header files required by the data structure definition
*******************************************************************/
#include <vector>
#include "device_grid.h"
#include "device_rr_gsb.h"
#include "fabric_tile_fwd.h"
#include "vtr_geometry.h"
#include "vtr_vector.h"
/* namespace openfpga begins */
namespace openfpga {
/********************************************************************
* Object models the tiles in an FPGA fabric
* This includes:
* 1. a collection of tiles, each which contains a programmable block and
*surrounding routing blocks
* 2. a collection of unique tiles
*******************************************************************/
class FabricTile {
public: /* Accessors */
vtr::Point<size_t> tile_coordinate(const FabricTileId& tile_id) const;
std::vector<vtr::Point<size_t>> pb_coordinates(
const FabricTileId& tile_id) const;
std::vector<vtr::Point<size_t>> cb_coordinates(
const FabricTileId& tile_id, const t_rr_type& cb_type) const;
std::vector<vtr::Point<size_t>> sb_coordinates(
const FabricTileId& tile_id) const;
/** @brief With a given coordinate, find the id of the unique tile (which is
* the same as the tile in structure) */
FabricTileId unique_tile(const vtr::Point<size_t>& coord) const;
/** @brief Find the tile info with a given coordinate */
FabricTileId find_tile(const vtr::Point<size_t>& coord) const;
/** @brief Find the id of a tile, with a given coordinate of the programmable
* block under the tile */
FabricTileId find_tile_by_pb_coordinate(
const vtr::Point<size_t>& coord) const;
/** @brief Find the id of a tile, with a given coordinate of the connection
* block under the tile */
FabricTileId find_tile_by_cb_coordinate(
const t_rr_type& cb_type, const vtr::Point<size_t>& coord) const;
/** @brief Find the id of a tile, with a given coordinate of the switch block
* under the tile */
FabricTileId find_tile_by_sb_coordinate(
const vtr::Point<size_t>& coord) const;
/** @brief Find the coordinate of the unique tile w.r.t the tile with a tile
* id */
vtr::Point<size_t> unique_tile_coordinate(const FabricTileId& tile_id) const;
/** @brief Return a list of unique tiles */
std::vector<FabricTileId> unique_tiles() const;
/** @brief Find the index of a programmable block in the internal list by a
* given coordinate. Note that the coord can be either the one in device grid
* or the one of gsb which the programmable block belongs to */
size_t find_pb_index_in_tile(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord,
const bool& use_gsb_coord = false) const;
/** @brief Find the index of a switch block in the internal list by a given
* coordinate. */
size_t find_sb_index_in_tile(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord) const;
/** @brief Find the index of a connection block in the internal list by a
* given coordinate. */
size_t find_cb_index_in_tile(const FabricTileId& tile_id,
const t_rr_type& cb_type,
const vtr::Point<size_t>& coord) const;
/** @brief Check if a programmable block (with a coordinate) exists in a tile.
* Note that the coord can be either the one in device grid or the one of gsb
* which the programmable block belongs to
*/
bool pb_in_tile(const FabricTileId& tile_id, const vtr::Point<size_t>& coord,
const bool& use_gsb_coord = false) const;
/** @brief Check if a switch block (with a coordinate) exists in a tile */
bool sb_in_tile(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord) const;
/** @brief Check if a connection block (with a coordinate) exists in a tile */
bool cb_in_tile(const FabricTileId& tile_id, const t_rr_type& cb_type,
const vtr::Point<size_t>& coord) const;
/** @brief Identify if the fabric tile is empty: no tiles are defined */
bool empty() const;
public: /* Mutators */
FabricTileId create_tile(const vtr::Point<size_t>& coord);
bool set_tile_coordinate(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord);
int add_pb_coordinate(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord,
const vtr::Point<size_t>& gsb_coord);
int add_cb_coordinate(const FabricTileId& tile_id, const t_rr_type& cb_type,
const vtr::Point<size_t>& coord);
int add_sb_coordinate(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord);
/** @brief Build a list of unique tiles by comparing the coordinates in
* DeviceRRGSB */
void build_unique_tiles();
/** @brief Clear all the content */
void clear();
/** @brief Initialize the data with a given range. Used by constructors */
void init(const vtr::Point<size_t>& max_coord);
/** @brief Identify the number of unique tiles and keep in the lookup */
int build_unique_tiles(const DeviceGrid& grids,
const DeviceRRGSB& device_rr_gsb);
public: /* Validators */
bool valid_tile_id(const FabricTileId& tile_id) const;
private: /* Internal validators */
/** @brief Identify if two tile are equivalent in their sub-modules, including
* pb, cbx, cby and sb */
bool equivalent_tile(const FabricTileId& tile_a, const FabricTileId& tile_b,
const DeviceGrid& grids,
const DeviceRRGSB& device_rr_gsb) const;
private: /* Internal builders */
void invalidate_tile_in_lookup(const vtr::Point<size_t>& coord);
void invalidate_pb_in_lookup(const vtr::Point<size_t>& coord);
void invalidate_cbx_in_lookup(const vtr::Point<size_t>& coord);
void invalidate_cby_in_lookup(const vtr::Point<size_t>& coord);
void invalidate_sb_in_lookup(const vtr::Point<size_t>& coord);
bool register_tile_in_lookup(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord);
bool register_pb_in_lookup(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord);
bool register_cbx_in_lookup(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord);
bool register_cby_in_lookup(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord);
bool register_sb_in_lookup(const FabricTileId& tile_id,
const vtr::Point<size_t>& coord);
private: /* Internal Data */
vtr::vector<FabricTileId, FabricTileId> ids_;
vtr::vector<FabricTileId, vtr::Point<size_t>> coords_;
/* Coordinates w.r.t. RRGSB
* Note that we keep two coordinates for the programmable block: regular one
* (in device grid) and the one in gsb. This is to ease the lookup/search for
* coordinates through both device grid and gsb. Client functions need one of
* the them depending on the scenario. In future, once we refactor the RRGSB
* organization (to follow bottom-left corner style). This limitation can be
* resolved.
*/
vtr::vector<FabricTileId, std::vector<vtr::Point<size_t>>> pb_coords_;
vtr::vector<FabricTileId, std::vector<vtr::Point<size_t>>> pb_gsb_coords_;
vtr::vector<FabricTileId, std::vector<vtr::Point<size_t>>> cbx_coords_;
vtr::vector<FabricTileId, std::vector<vtr::Point<size_t>>> cby_coords_;
vtr::vector<FabricTileId, std::vector<vtr::Point<size_t>>> sb_coords_;
/* A few fast lookup to spot tile by coordinate of programmable blocks,
* connection blocks and switch blocks */
std::vector<std::vector<FabricTileId>> pb_coord2id_lookup_;
std::vector<std::vector<FabricTileId>> cbx_coord2id_lookup_;
std::vector<std::vector<FabricTileId>> cby_coord2id_lookup_;
std::vector<std::vector<FabricTileId>> sb_coord2id_lookup_;
/* A fast lookup to spot tile by coordinate */
std::vector<std::vector<FabricTileId>> tile_coord2id_lookup_;
std::vector<std::vector<FabricTileId>>
tile_coord2unique_tile_ids_; /* Use [x][y] to get the id of the unique tile
with a given coordinate */
std::vector<FabricTileId> unique_tile_ids_;
};
} /* End namespace openfpga*/
#endif

View File

@ -0,0 +1,23 @@
/**************************************************
* This file includes only declarations for
* the data structures for fabric tiles
* Please refer to fabric_tiles.h for more details
*************************************************/
#ifndef FABRIC_TILE_FWD_H
#define FABRIC_TILE_FWD_H
#include "vtr_strong_id.h"
/* begin namespace openfpga */
namespace openfpga {
/* Strong Ids for ModuleManager */
struct fabric_tile_id_tag;
typedef vtr::StrongId<fabric_tile_id_tag> FabricTileId;
class FabricTile;
} /* end namespace openfpga */
#endif

View File

@ -39,6 +39,7 @@ class NetlistManager {
SUBMODULE_NETLIST,
LOGIC_BLOCK_NETLIST,
ROUTING_MODULE_NETLIST,
TILE_MODULE_NETLIST,
TOP_MODULE_NETLIST,
TESTBENCH_NETLIST,
NUM_NETLIST_TYPES

View File

@ -18,6 +18,7 @@
#include "openfpga_naming.h"
#include "read_xml_fabric_key.h"
#include "read_xml_io_name_map.h"
#include "read_xml_tile_config.h"
#include "vtr_log.h"
#include "vtr_time.h"
@ -98,8 +99,30 @@ int build_fabric_template(T& openfpga_ctx, const Command& cmd,
cmd.option("generate_random_fabric_key");
CommandOptionId opt_write_fabric_key = cmd.option("write_fabric_key");
CommandOptionId opt_load_fabric_key = cmd.option("load_fabric_key");
CommandOptionId opt_group_tile = cmd.option("group_tile");
CommandOptionId opt_verbose = cmd.option("verbose");
/* Report conflicts with options:
* - group tile does not support duplicate_grid_pin
* - group tile requires compress_routing to be enabled
*/
if (cmd_context.option_enable(cmd, opt_group_tile)) {
if (cmd_context.option_enable(cmd, opt_duplicate_grid_pin)) {
VTR_LOG_ERROR(
"Option '%s' requires options '%s' to be disabled due to a conflict!\n",
cmd.option_name(opt_group_tile).c_str(),
cmd.option_name(opt_duplicate_grid_pin).c_str());
return CMD_EXEC_FATAL_ERROR;
}
if (!cmd_context.option_enable(cmd, opt_compress_routing)) {
VTR_LOG_ERROR(
"Option '%s' requires options '%s' to be enabled due to a conflict!\n",
cmd.option_name(opt_group_tile).c_str(),
cmd.option_name(opt_compress_routing).c_str());
return CMD_EXEC_FATAL_ERROR;
}
}
if (true == cmd_context.option_enable(cmd, opt_compress_routing)) {
compress_routing_hierarchy_template<T>(
openfpga_ctx, cmd_context.option_enable(cmd, opt_verbose));
@ -125,14 +148,33 @@ int build_fabric_template(T& openfpga_ctx, const Command& cmd,
VTR_LOG("\n");
/* Build tile-level information:
* - This feature only supports when compress routing is enabled
* - Read the tile organization configuration file
* - Build tile info
*/
TileConfig tile_config;
if (cmd_context.option_enable(cmd, opt_group_tile)) {
if (!cmd_context.option_enable(cmd, opt_compress_routing)) {
VTR_LOG_ERROR(
"Group tile is applicable only when compress routing is enabled!\n");
return CMD_EXEC_FATAL_ERROR;
}
curr_status = read_xml_tile_config(
cmd_context.option_value(cmd, opt_group_tile).c_str(), tile_config);
if (CMD_EXEC_SUCCESS != curr_status) {
return CMD_EXEC_FATAL_ERROR;
}
}
curr_status = build_device_module_graph(
openfpga_ctx.mutable_module_graph(), openfpga_ctx.mutable_decoder_lib(),
openfpga_ctx.mutable_blwl_shift_register_banks(),
const_cast<const T&>(openfpga_ctx), g_vpr_ctx.device(),
cmd_context.option_enable(cmd, opt_frame_view),
openfpga_ctx.mutable_fabric_tile(), const_cast<const T&>(openfpga_ctx),
g_vpr_ctx.device(), cmd_context.option_enable(cmd, opt_frame_view),
cmd_context.option_enable(cmd, opt_compress_routing),
cmd_context.option_enable(cmd, opt_duplicate_grid_pin),
predefined_fabric_key,
predefined_fabric_key, tile_config,
cmd_context.option_enable(cmd, opt_gen_random_fabric_key),
cmd_context.option_enable(cmd, opt_verbose));
@ -144,7 +186,8 @@ int build_fabric_template(T& openfpga_ctx, const Command& cmd,
/* Build I/O location map */
openfpga_ctx.mutable_io_location_map() = build_fabric_io_location_map(
openfpga_ctx.module_graph(), g_vpr_ctx.device().grid);
openfpga_ctx.module_graph(), g_vpr_ctx.device().grid,
cmd_context.option_enable(cmd, opt_group_tile));
/* Build fabric global port information */
openfpga_ctx.mutable_fabric_global_port_info() =

View File

@ -10,6 +10,7 @@
#include "device_rr_gsb.h"
#include "fabric_bitstream.h"
#include "fabric_global_port_info.h"
#include "fabric_tile.h"
#include "io_location_map.h"
#include "io_name_map.h"
#include "memory_bank_shift_register_banks.h"
@ -106,6 +107,7 @@ class OpenfpgaContext : public Context {
return io_location_map_;
}
const openfpga::IoNameMap& io_name_map() const { return io_name_map_; }
const openfpga::FabricTile& fabric_tile() const { return fabric_tile_; }
const openfpga::FabricGlobalPortInfo& fabric_global_port_info() const {
return fabric_global_port_info_;
}
@ -165,6 +167,7 @@ class OpenfpgaContext : public Context {
return io_location_map_;
}
openfpga::IoNameMap& mutable_io_name_map() { return io_name_map_; }
openfpga::FabricTile& mutable_fabric_tile() { return fabric_tile_; }
openfpga::FabricGlobalPortInfo& mutable_fabric_global_port_info() {
return fabric_global_port_info_;
}
@ -220,6 +223,7 @@ class OpenfpgaContext : public Context {
openfpga::ModuleManager module_graph_;
openfpga::IoLocationMap io_location_map_;
openfpga::IoNameMap io_name_map_;
openfpga::FabricTile fabric_tile_;
openfpga::FabricGlobalPortInfo fabric_global_port_info_;
/* Bitstream database */

View File

@ -497,6 +497,31 @@ std::string generate_switch_block_module_name(
std::string("_"));
}
/*********************************************************************
* Generate the module name for a tile module with a given coordinate
*********************************************************************/
std::string generate_tile_module_name(const vtr::Point<size_t>& tile_coord) {
return std::string("tile_" + std::to_string(tile_coord.x()) + "__" +
std::to_string(tile_coord.y()) + "_");
}
/*********************************************************************
* Generate the port name for a tile. Note that use the index to make the tile
*port name unique!
*********************************************************************/
std::string generate_tile_module_port_name(const std::string& prefix,
const std::string& port_name) {
return prefix + std::string("_") + port_name;
}
/*********************************************************************
* Generate the netlist name of a grid block
**********************************************************************/
std::string generate_tile_module_netlist_name(const std::string& block_name,
const std::string& postfix) {
return block_name + postfix;
}
/*********************************************************************
* Generate the module name for a connection block with a given coordinate
*********************************************************************/

View File

@ -110,6 +110,14 @@ std::string generate_switch_block_module_name(
std::string generate_connection_block_module_name(
const t_rr_type& cb_type, const vtr::Point<size_t>& coordinate);
std::string generate_tile_module_name(const vtr::Point<size_t>& tile_coord);
std::string generate_tile_module_port_name(const std::string& prefix,
const std::string& port_name);
std::string generate_tile_module_netlist_name(const std::string& block_name,
const std::string& postfix);
std::string generate_sb_mux_instance_name(const std::string& prefix,
const e_side& sb_side,
const size_t& track_id,

View File

@ -96,11 +96,12 @@ int write_pnr_sdc_template(const T& openfpga_ctx, const Command& cmd,
/* Execute only when sdc is enabled */
if (true == options.generate_sdc_pnr()) {
print_pnr_sdc(
return print_pnr_sdc(
options, g_vpr_ctx.device(), openfpga_ctx.vpr_device_annotation(),
openfpga_ctx.device_rr_gsb(), openfpga_ctx.module_graph(),
openfpga_ctx.mux_lib(), openfpga_ctx.arch().circuit_lib,
openfpga_ctx.fabric_global_port_info(), openfpga_ctx.simulation_setting(),
openfpga_ctx.fabric_tile(), openfpga_ctx.device_rr_gsb(),
openfpga_ctx.module_graph(), openfpga_ctx.mux_lib(),
openfpga_ctx.arch().circuit_lib, openfpga_ctx.fabric_global_port_info(),
openfpga_ctx.simulation_setting(),
openfpga_ctx.flow_manager().compress_routing());
}

View File

@ -405,6 +405,13 @@ ShellCommandId add_build_fabric_command_template(
"write_fabric_key", false, "output current fabric key to a file");
shell_cmd.set_option_require_value(opt_write_fkey, openfpga::OPT_STRING);
/* Add an option '--group_tile' */
CommandOptionId opt_group_tile = shell_cmd.add_option(
"group_tile", false,
"group programmable blocks and routing blocks into tiles. This helps to "
"reduce the number of blocks at top-level");
shell_cmd.set_option_require_value(opt_group_tile, openfpga::OPT_STRING);
/* Add an option '--generate_random_fabric_key' */
shell_cmd.add_option("generate_random_fabric_key", false,
"Create a random fabric key which will shuffle the "

View File

@ -57,16 +57,13 @@ int write_fabric_verilog_template(T& openfpga_ctx, const Command& cmd,
options.set_verbose_output(cmd_context.option_enable(cmd, opt_verbose));
options.set_compress_routing(openfpga_ctx.flow_manager().compress_routing());
fpga_fabric_verilog(openfpga_ctx.mutable_module_graph(),
openfpga_ctx.mutable_verilog_netlists(),
openfpga_ctx.blwl_shift_register_banks(),
openfpga_ctx.arch().circuit_lib, openfpga_ctx.mux_lib(),
openfpga_ctx.decoder_lib(), g_vpr_ctx.device(),
openfpga_ctx.vpr_device_annotation(),
openfpga_ctx.device_rr_gsb(), options);
/* TODO: should identify the error code from internal function execution */
return CMD_EXEC_SUCCESS;
return fpga_fabric_verilog(
openfpga_ctx.mutable_module_graph(),
openfpga_ctx.mutable_verilog_netlists(),
openfpga_ctx.blwl_shift_register_banks(), openfpga_ctx.arch().circuit_lib,
openfpga_ctx.mux_lib(), openfpga_ctx.decoder_lib(), g_vpr_ctx.device(),
openfpga_ctx.vpr_device_annotation(), openfpga_ctx.device_rr_gsb(),
openfpga_ctx.fabric_tile(), options);
}
/********************************************************************

View File

@ -12,11 +12,13 @@
#include "build_decoder_modules.h"
#include "build_device_module.h"
#include "build_essential_modules.h"
#include "build_fabric_tile.h"
#include "build_grid_modules.h"
#include "build_lut_modules.h"
#include "build_memory_modules.h"
#include "build_mux_modules.h"
#include "build_routing_modules.h"
#include "build_tile_modules.h"
#include "build_top_module.h"
#include "build_wire_modules.h"
#include "command_exit_codes.h"
@ -31,11 +33,12 @@ namespace openfpga {
*******************************************************************/
int build_device_module_graph(
ModuleManager& module_manager, DecoderLibrary& decoder_lib,
MemoryBankShiftRegisterBanks& blwl_sr_banks,
MemoryBankShiftRegisterBanks& blwl_sr_banks, FabricTile& fabric_tile,
const OpenfpgaContext& openfpga_ctx, const DeviceContext& vpr_device_ctx,
const bool& frame_view, const bool& compress_routing,
const bool& duplicate_grid_pin, const FabricKey& fabric_key,
const bool& generate_random_fabric_key, const bool& verbose) {
const TileConfig& tile_config, const bool& generate_random_fabric_key,
const bool& verbose) {
vtr::ScopedStartFinishTimer timer("Build fabric module graph");
int status = CMD_EXEC_SUCCESS;
@ -99,6 +102,23 @@ int build_device_module_graph(
openfpga_ctx.arch().config_protocol.type(), sram_model, verbose);
}
/* Build tile modules if defined */
if (tile_config.is_valid()) {
/* Build detailed tile-level information */
status = build_fabric_tile(fabric_tile, tile_config, vpr_device_ctx.grid,
openfpga_ctx.device_rr_gsb(), verbose);
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
/* Build the modules */
build_tile_modules(
module_manager, decoder_lib, openfpga_ctx.fabric_tile(),
vpr_device_ctx.grid, openfpga_ctx.vpr_device_annotation(),
openfpga_ctx.device_rr_gsb(), vpr_device_ctx.rr_graph,
openfpga_ctx.arch().circuit_lib, sram_model,
openfpga_ctx.arch().config_protocol.type(), frame_view, verbose);
}
/* Build FPGA fabric top-level module */
status = build_top_module(
module_manager, decoder_lib, blwl_sr_banks, openfpga_ctx.arch().circuit_lib,
@ -107,8 +127,8 @@ int build_device_module_graph(
openfpga_ctx.arch().tile_annotations, vpr_device_ctx.rr_graph,
openfpga_ctx.device_rr_gsb(), openfpga_ctx.tile_direct(),
openfpga_ctx.arch().arch_direct, openfpga_ctx.arch().config_protocol,
sram_model, frame_view, compress_routing, duplicate_grid_pin, fabric_key,
generate_random_fabric_key);
sram_model, fabric_tile, frame_view, compress_routing, duplicate_grid_pin,
fabric_key, generate_random_fabric_key, verbose);
if (CMD_EXEC_FATAL_ERROR == status) {
return status;

View File

@ -5,8 +5,10 @@
* Include header files that are required by function declaration
*******************************************************************/
#include "fabric_key.h"
#include "fabric_tile.h"
#include "io_name_map.h"
#include "openfpga_context.h"
#include "tile_config.h"
#include "vpr_context.h"
/********************************************************************
@ -18,11 +20,12 @@ namespace openfpga {
int build_device_module_graph(
ModuleManager& module_manager, DecoderLibrary& decoder_lib,
MemoryBankShiftRegisterBanks& blwl_sr_banks,
MemoryBankShiftRegisterBanks& blwl_sr_banks, FabricTile& fabric_tile,
const OpenfpgaContext& openfpga_ctx, const DeviceContext& vpr_device_ctx,
const bool& frame_view, const bool& compress_routing,
const bool& duplicate_grid_pin, const FabricKey& fabric_key,
const bool& generate_random_fabric_key, const bool& verbose);
const TileConfig& tile_config, const bool& generate_random_fabric_key,
const bool& verbose);
} /* end namespace openfpga */

View File

@ -31,8 +31,8 @@ namespace openfpga {
*io_children() list of top-level module. Here we just build a fast lookup from
*(x, y, z) coordinate to the actual indices
*******************************************************************/
IoLocationMap build_fabric_io_location_map(const ModuleManager& module_manager,
const DeviceGrid& grids) {
static IoLocationMap build_fabric_fine_grained_io_location_map(
const ModuleManager& module_manager, const DeviceGrid& grids) {
vtr::ScopedStartFinishTimer timer(
"Create I/O location mapping for top module");
@ -144,4 +144,145 @@ IoLocationMap build_fabric_io_location_map(const ModuleManager& module_manager,
return io_location_map;
}
/********************************************************************
* Find all the GPIO ports in the tile modules
* and cache their port/pin index in the top-level module
*
* .. note:: The I/O sequence(indexing) is already determined in the
*io_children() list of top-level module. Here we just build a fast lookup from
*(x, y, z) coordinate to the actual indices
*******************************************************************/
static IoLocationMap build_fabric_tiled_io_location_map(
const ModuleManager& module_manager, const DeviceGrid& grids) {
vtr::ScopedStartFinishTimer timer(
"Create I/O location mapping for top module");
IoLocationMap io_location_map;
std::map<std::string, size_t> io_counter;
std::string top_module_name = generate_fpga_top_module_name();
ModuleId top_module = module_manager.find_module(top_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
/* Walk through the I/O child list */
for (size_t ichild = 0;
ichild < module_manager.io_children(top_module).size(); ++ichild) {
ModuleId child = module_manager.io_children(top_module)[ichild];
vtr::Point<int> coord =
module_manager.io_child_coordinates(top_module)[ichild];
t_physical_tile_type_ptr phy_tile_type =
grids.get_physical_type(coord.x(), coord.y());
/* Bypass EMPTY grid */
if (true == is_empty_type(phy_tile_type)) {
continue;
}
/* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
if ((0 < grids.get_width_offset(coord.x(), coord.y())) ||
(0 < grids.get_height_offset(coord.x(), coord.y()))) {
continue;
}
VTR_ASSERT_SAFE(true == module_manager.valid_module_id(child));
/* 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
*/
for (ModuleId tile_child : module_manager.io_children(child)) {
/* Note that we should use the subchild of the subchild module when
* checking the GPIO ports. The child module is the tile module while the
* subchild module is actually the grid-level I/O module, while the
* subchild module is the subtile inside grid-level I/O modules. Note that
* grid-level I/O module contains all the GPIO ports while the subtile may
* have part of it. For example, a grid I/O module may have 24 GPINs and
* 12 GPOUTs, while the first subtile only have 4 GPINs, and the second
* subtile only have 3 GPOUTs. Therefore, to accurately build the I/O
* location map downto subtile level, we need to check the subchild module
* here.
*/
if (size_t(phy_tile_type->capacity) !=
module_manager.io_children(tile_child).size()) {
VTR_LOG("%s[%ld][%ld] capacity: %d while io_child number is %d",
phy_tile_type->name, coord.x(), coord.y(),
phy_tile_type->capacity,
module_manager.io_children(tile_child).size());
}
VTR_ASSERT(size_t(phy_tile_type->capacity) ==
module_manager.io_children(tile_child).size());
for (size_t isubchild = 0;
isubchild < module_manager.io_children(tile_child).size();
++isubchild) {
ModuleId subchild = module_manager.io_children(tile_child)[isubchild];
vtr::Point<int> subchild_coord =
module_manager.io_child_coordinates(tile_child)[isubchild];
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(subchild,
module_io_port_type)) {
/* Only care mappable I/O */
if (false ==
module_manager.port_is_mappable_io(subchild, gpio_port_id)) {
continue;
}
const BasicPort& gpio_port =
module_manager.module_port(subchild, 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;
}
/* This is a dirty hack! */
io_location_map.set_io_index(
coord.x(), coord.y(), subchild_coord.x(), 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 */
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(top_module,
module_io_port_type)) {
/* Only care mappable I/O */
if (false ==
module_manager.port_is_mappable_io(top_module, gpio_port_id)) {
continue;
}
const BasicPort& gpio_port =
module_manager.module_port(top_module, gpio_port_id);
VTR_ASSERT(io_counter[gpio_port.get_name()] == gpio_port.get_width());
}
}
return io_location_map;
}
/********************************************************************
* Top-level function, if tile modules are built under the top-level module
* The data to access for I/O location is different than the fine-grained grid
*modules
* FIXME: Think about a unified way for the two kinds of fabrics!!!
*******************************************************************/
IoLocationMap build_fabric_io_location_map(const ModuleManager& module_manager,
const DeviceGrid& grids,
const bool& tiled_fabric) {
if (tiled_fabric) {
return build_fabric_tiled_io_location_map(module_manager, grids);
}
return build_fabric_fine_grained_io_location_map(module_manager, grids);
}
} /* end namespace openfpga */

View File

@ -19,7 +19,8 @@
namespace openfpga {
IoLocationMap build_fabric_io_location_map(const ModuleManager& module_manager,
const DeviceGrid& grids);
const DeviceGrid& grids,
const bool& tiled_fabric);
} /* end namespace openfpga */

View File

@ -0,0 +1,163 @@
/********************************************************************
* This file includes functions that are used to build the location
* map information for the top-level module of the FPGA fabric
* It helps OpenFPGA to link the I/O port index in top-level module
* to the VPR I/O mapping results
*******************************************************************/
#include <algorithm>
#include <map>
/* Headers from vtrutil library */
#include "command_exit_codes.h"
#include "vtr_assert.h"
#include "vtr_log.h"
#include "vtr_time.h"
/* Headers from vpr library */
#include "build_fabric_tile.h"
#include "openfpga_naming.h"
#include "openfpga_reserved_words.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Build tiles by following the top-level style.
* - The programmble block, e.g., clb, is placed on the top-left corner
* - The connection blocks and switch block are placed on the right and bottom
*sides
*******************************************************************/
static int build_fabric_tile_style_top_left(FabricTile& fabric_tile,
const DeviceGrid& grids,
const DeviceRRGSB& device_rr_gsb,
const bool& verbose) {
int status_code = CMD_EXEC_SUCCESS;
/* Walk through all the device rr_gsb and create tile one by one */
for (size_t ix = 0; ix < grids.width(); ++ix) {
for (size_t iy = 0; iy < grids.height(); ++iy) {
t_physical_tile_type_ptr phy_tile_type = grids.get_physical_type(ix, iy);
bool skip_add_pb = false;
vtr::Point<size_t> curr_tile_coord(ix, iy);
vtr::Point<size_t> curr_gsb_coord(ix, iy - 1);
FabricTileId curr_tile_id = FabricTileId::INVALID();
/* For EMPTY grid, routing blocks may still be required if there is a gsb
*/
if (true == is_empty_type(phy_tile_type)) {
skip_add_pb = true;
if (!device_rr_gsb.is_gsb_exist(curr_gsb_coord)) {
VTR_LOGV(verbose, "Skip tile[%lu][%lu] as it is empty\n",
curr_tile_coord.x(), curr_tile_coord.y());
continue;
}
/* Need to create a new tile here */
VTR_LOGV(verbose,
"Create tile[%lu][%lu] which only has routing but not a "
"programmable block\n",
curr_tile_coord.x(), curr_tile_coord.y());
curr_tile_id = fabric_tile.create_tile(curr_tile_coord);
} else if ((0 < grids.get_width_offset(ix, iy)) ||
(0 < grids.get_height_offset(ix, iy))) {
/* Skip width, height > 1 tiles (mostly heterogeneous blocks) */
/* Find the root of this grid, the instance id should be valid.
* We just copy it here
*/
vtr::Point<size_t> root_tile_coord(
ix - grids.get_width_offset(ix, iy),
iy - grids.get_height_offset(ix, iy));
skip_add_pb = true;
VTR_LOGV(verbose,
"Tile[%lu][%lu] contains a heterogeneous block which is "
"rooted from tile[%lu][%lu]\n",
curr_tile_coord.x(), curr_tile_coord.y(), root_tile_coord.x(),
root_tile_coord.y());
curr_tile_id = fabric_tile.find_tile(root_tile_coord);
} else {
/* Need to create a new tile here */
VTR_LOGV(verbose, "Create a regular tile[%lu][%lu]\n",
curr_tile_coord.x(), curr_tile_coord.y());
curr_tile_id = fabric_tile.create_tile(curr_tile_coord);
}
/* Ensure that we have a valid id */
if (!fabric_tile.valid_tile_id(curr_tile_id)) {
VTR_LOG_ERROR("Failed to get a valid id for tile[%lu][%lu]!\n", ix, iy);
return CMD_EXEC_FATAL_ERROR;
}
/* Add components: pb, cbx, cby, and sb if exists */
if (!skip_add_pb) {
fabric_tile.add_pb_coordinate(curr_tile_id, curr_tile_coord,
curr_gsb_coord);
}
/* The gsb coordinate is different than the grid coordinate when the
* top-left style is considered
*
* +----------+ +----------+
* | Grid | | CBx |
* | [x][y] | | [x][y] |
* +----------+ +----------+
* +----------+ +----------+
* | CBy | | SB |
* | [x][y-1] | | [x][y-1] |
* +----------+ +----------+
*
*/
if (!device_rr_gsb.is_gsb_exist(curr_gsb_coord)) {
continue;
}
const RRGSB& curr_rr_gsb = device_rr_gsb.get_gsb(curr_gsb_coord);
for (t_rr_type cb_type : {CHANX, CHANY}) {
if (curr_rr_gsb.is_cb_exist(cb_type)) {
fabric_tile.add_cb_coordinate(curr_tile_id, cb_type,
curr_rr_gsb.get_sb_coordinate());
}
}
if (curr_rr_gsb.is_sb_exist()) {
fabric_tile.add_sb_coordinate(curr_tile_id,
curr_rr_gsb.get_sb_coordinate());
}
}
}
return status_code;
}
/********************************************************************
* Build tile-level information for a given FPGA fabric, w.r.t. to configuration
*******************************************************************/
int build_fabric_tile(FabricTile& fabric_tile, const TileConfig& tile_config,
const DeviceGrid& grids, const DeviceRRGSB& device_rr_gsb,
const bool& verbose) {
vtr::ScopedStartFinishTimer timer(
"Build tile-level information for the FPGA fabric");
int status_code = CMD_EXEC_SUCCESS;
fabric_tile.init(vtr::Point<size_t>(grids.width(), grids.height()));
/* Depending on the selected style, follow different approaches */
if (tile_config.style() == TileConfig::e_style::TOP_LEFT) {
status_code = build_fabric_tile_style_top_left(fabric_tile, grids,
device_rr_gsb, verbose);
} else {
/* Error out for styles that are not supported yet! */
VTR_LOG_ERROR("Tile style '%s' is not supported yet!\n",
tile_config.style_to_string().c_str());
status_code = CMD_EXEC_FATAL_ERROR;
}
if (status_code != CMD_EXEC_SUCCESS) {
return CMD_EXEC_FATAL_ERROR;
}
/* Build unique tiles to compress the number of tile modules to be built in
* later steps */
status_code = fabric_tile.build_unique_tiles(grids, device_rr_gsb);
VTR_LOGV(verbose, "Extracted %lu uniques tiles from the FPGA fabric\n",
fabric_tile.unique_tiles().size());
return status_code;
}
} /* end namespace openfpga */

View File

@ -0,0 +1,28 @@
#ifndef BUILD_FABRIC_TILE_H
#define BUILD_FABRIC_TILE_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <string>
#include "device_grid.h"
#include "device_rr_gsb.h"
#include "fabric_tile.h"
#include "tile_config.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
int build_fabric_tile(FabricTile& fabric_tile, const TileConfig& tile_config,
const DeviceGrid& grids, const DeviceRRGSB& device_rr_gsb,
const bool& verbose);
} /* end namespace openfpga */
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,40 @@
#ifndef BUILD_TILE_MODULES_H
#define BUILD_TILE_MODULES_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <string>
#include "circuit_library.h"
#include "config_protocol.h"
#include "decoder_library.h"
#include "device_grid.h"
#include "device_rr_gsb.h"
#include "fabric_tile.h"
#include "module_manager.h"
#include "rr_graph_view.h"
#include "vpr_device_annotation.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
int build_tile_modules(ModuleManager& module_manager,
DecoderLibrary& decoder_lib,
const FabricTile& fabric_tile, const DeviceGrid& grids,
const VprDeviceAnnotation& vpr_device_annotation,
const DeviceRRGSB& device_rr_gsb,
const RRGraphView& rr_graph_view,
const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const e_config_protocol_type& sram_orgz_type,
const bool& frame_view, const bool& verbose);
} /* end namespace openfpga */
#endif

View File

@ -16,6 +16,8 @@
/* Headers from openfpgashell library */
#include "build_module_graph_utils.h"
#include "build_top_module.h"
#include "build_top_module_child_fine_grained_instance.h"
#include "build_top_module_child_tile_instance.h"
#include "build_top_module_connection.h"
#include "build_top_module_directs.h"
#include "build_top_module_memory.h"
@ -32,394 +34,6 @@
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Add a instance of a grid module to the top module
*******************************************************************/
static size_t add_top_module_grid_instance(
ModuleManager& module_manager, const ModuleId& top_module,
t_physical_tile_type_ptr grid_type, const e_side& border_side,
const vtr::Point<size_t>& grid_coord) {
/* 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), border_side);
ModuleId grid_module = module_manager.find_module(grid_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(grid_module));
/* Record the instance id */
size_t grid_instance = module_manager.num_instance(top_module, grid_module);
/* Add the module to top_module */
module_manager.add_child_module(top_module, grid_module, false);
/* Set an unique name to the instance
* Note: it is your risk to gurantee the name is unique!
*/
std::string instance_name = generate_grid_block_instance_name(
grid_module_name_prefix, std::string(grid_type->name),
is_io_type(grid_type), border_side, grid_coord);
module_manager.set_child_instance_name(top_module, grid_module, grid_instance,
instance_name);
return grid_instance;
}
/********************************************************************
* Add all the grids as sub-modules across the fabric
* The grid modules are created for each unique type of grid (based
* on the type in data structure data_structure
* Here, we will iterate over the full fabric (coordinates)
* and instanciate the grid modules
*
* Return an 2-D array of instance ids of the grid modules that
* have been added
*
* This function assumes an island-style floorplanning for FPGA fabric
*
*
* +-----------------------------------+
* | I/O grids |
* | TOP side |
* +-----------------------------------+
*
* +-----------+ +-----------------------------------+ +------------+
* | | | | | |
* | I/O grids | | Core grids | | I/O grids |
* | LEFT side | | (CLB, Heterogeneous blocks, etc.) | | RIGHT side |
* | | | | | |
* +-----------+ +-----------------------------------+ +------------+
*
* +-----------------------------------+
* | I/O grids |
* | BOTTOM side |
* +-----------------------------------+
*
*******************************************************************/
static vtr::Matrix<size_t> add_top_module_grid_instances(
ModuleManager& module_manager, const ModuleId& top_module,
const DeviceGrid& grids) {
vtr::ScopedStartFinishTimer timer("Add grid instances to top module");
/* Reserve an array for the instance ids */
vtr::Matrix<size_t> grid_instance_ids({grids.width(), grids.height()});
grid_instance_ids.fill(size_t(-1));
/* Instanciate I/O grids */
/* Create the coordinate range for each side of FPGA fabric */
std::map<e_side, std::vector<vtr::Point<size_t>>> io_coordinates =
generate_perimeter_grid_coordinates(grids);
for (const e_side& io_side : FPGA_SIDES_CLOCKWISE) {
for (const vtr::Point<size_t>& io_coordinate : io_coordinates[io_side]) {
t_physical_tile_type_ptr phy_tile_type =
grids.get_physical_type(io_coordinate.x(), io_coordinate.y());
/* Bypass EMPTY grid */
if (true == is_empty_type(phy_tile_type)) {
continue;
}
/* Skip width, height > 1 tiles (mostly heterogeneous blocks) */
if ((0 < grids.get_width_offset(io_coordinate.x(), io_coordinate.y())) ||
(0 < grids.get_height_offset(io_coordinate.x(), io_coordinate.y()))) {
/* Find the root of this grid, the instance id should be valid.
* We just copy it here
*/
vtr::Point<size_t> root_grid_coord(
io_coordinate.x() -
grids.get_width_offset(io_coordinate.x(), io_coordinate.y()),
io_coordinate.y() -
grids.get_height_offset(io_coordinate.x(), io_coordinate.y()));
VTR_ASSERT(size_t(-1) !=
grid_instance_ids[root_grid_coord.x()][root_grid_coord.y()]);
grid_instance_ids[io_coordinate.x()][io_coordinate.y()] =
grid_instance_ids[root_grid_coord.x()][root_grid_coord.y()];
continue;
}
/* Add a grid module to top_module*/
grid_instance_ids[io_coordinate.x()][io_coordinate.y()] =
add_top_module_grid_instance(module_manager, top_module, phy_tile_type,
io_side, io_coordinate);
}
}
/* Instanciate core grids
* IMPORTANT: sequence matters here, it impacts the I/O indexing.
* We should follow the same sequence as the build_io_location_map()!
* If you change the sequence of walking through grids here, you should change
* it in the build_io_location map()!
*/
for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
t_physical_tile_type_ptr phy_tile_type = grids.get_physical_type(ix, iy);
/* Bypass EMPTY grid */
if (true == is_empty_type(phy_tile_type)) {
continue;
}
/* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
if ((0 < grids.get_width_offset(ix, iy)) ||
(0 < grids.get_height_offset(ix, iy))) {
/* Find the root of this grid, the instance id should be valid.
* We just copy it here
*/
vtr::Point<size_t> root_grid_coord(
ix - grids.get_width_offset(ix, iy),
iy - grids.get_height_offset(ix, iy));
VTR_ASSERT(size_t(-1) !=
grid_instance_ids[root_grid_coord.x()][root_grid_coord.y()]);
grid_instance_ids[ix][iy] =
grid_instance_ids[root_grid_coord.x()][root_grid_coord.y()];
continue;
}
/* Add a grid module to top_module*/
vtr::Point<size_t> grid_coord(ix, iy);
grid_instance_ids[ix][iy] = add_top_module_grid_instance(
module_manager, top_module, phy_tile_type, NUM_SIDES, grid_coord);
}
}
return grid_instance_ids;
}
/********************************************************************
* Add switch blocks across the FPGA fabric to the top-level module
* Return an 2-D array of instance ids of the switch blocks that
* have been added
*******************************************************************/
static vtr::Matrix<size_t> add_top_module_switch_block_instances(
ModuleManager& module_manager, const ModuleId& top_module,
const DeviceRRGSB& device_rr_gsb, const bool& compact_routing_hierarchy) {
vtr::ScopedStartFinishTimer timer("Add switch block instances to top module");
vtr::Point<size_t> sb_range = device_rr_gsb.get_gsb_range();
/* Reserve an array for the instance ids */
vtr::Matrix<size_t> sb_instance_ids({sb_range.x(), sb_range.y()});
sb_instance_ids.fill(size_t(-1));
for (size_t ix = 0; ix < sb_range.x(); ++ix) {
for (size_t iy = 0; iy < sb_range.y(); ++iy) {
/* If we use compact routing hierarchy, we should instanciate the unique
* module of SB */
const RRGSB& rr_gsb = device_rr_gsb.get_gsb(ix, iy);
if (false == rr_gsb.is_sb_exist()) {
continue;
}
vtr::Point<size_t> sb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
if (true == compact_routing_hierarchy) {
vtr::Point<size_t> sb_coord(ix, iy);
const RRGSB& unique_mirror =
device_rr_gsb.get_sb_unique_module(sb_coord);
sb_coordinate.set_x(unique_mirror.get_sb_x());
sb_coordinate.set_y(unique_mirror.get_sb_y());
}
std::string sb_module_name =
generate_switch_block_module_name(sb_coordinate);
ModuleId sb_module = module_manager.find_module(sb_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(sb_module));
/* Record the instance id */
sb_instance_ids[rr_gsb.get_sb_x()][rr_gsb.get_sb_y()] =
module_manager.num_instance(top_module, sb_module);
/* Add the module to top_module */
module_manager.add_child_module(top_module, sb_module, false);
/* Set an unique name to the instance
* Note: it is your risk to gurantee the name is unique!
*/
module_manager.set_child_instance_name(
top_module, sb_module,
sb_instance_ids[rr_gsb.get_sb_x()][rr_gsb.get_sb_y()],
generate_switch_block_module_name(
vtr::Point<size_t>(rr_gsb.get_sb_x(), rr_gsb.get_sb_y())));
}
}
return sb_instance_ids;
}
/********************************************************************
* Add switch blocks across the FPGA fabric to the top-level module
*******************************************************************/
static vtr::Matrix<size_t> add_top_module_connection_block_instances(
ModuleManager& module_manager, const ModuleId& top_module,
const DeviceRRGSB& device_rr_gsb, const t_rr_type& cb_type,
const bool& compact_routing_hierarchy) {
vtr::ScopedStartFinishTimer timer(
"Add connection block instances to top module");
vtr::Point<size_t> cb_range = device_rr_gsb.get_gsb_range();
/* Reserve an array for the instance ids */
vtr::Matrix<size_t> cb_instance_ids({cb_range.x(), cb_range.y()});
cb_instance_ids.fill(size_t(-1));
for (size_t ix = 0; ix < cb_range.x(); ++ix) {
for (size_t iy = 0; iy < cb_range.y(); ++iy) {
/* Check if the connection block exists in the device!
* Some of them do NOT exist due to heterogeneous blocks (height > 1)
* We will skip those modules
*/
const RRGSB& rr_gsb = device_rr_gsb.get_gsb(ix, iy);
vtr::Point<size_t> cb_coordinate(rr_gsb.get_cb_x(cb_type),
rr_gsb.get_cb_y(cb_type));
if (false == rr_gsb.is_cb_exist(cb_type)) {
continue;
}
/* If we use compact routing hierarchy, we should instanciate the unique
* module of SB */
if (true == compact_routing_hierarchy) {
vtr::Point<size_t> cb_coord(ix, iy);
/* Note: use GSB coordinate when inquire for unique modules!!! */
const RRGSB& unique_mirror =
device_rr_gsb.get_cb_unique_module(cb_type, cb_coord);
cb_coordinate.set_x(unique_mirror.get_cb_x(cb_type));
cb_coordinate.set_y(unique_mirror.get_cb_y(cb_type));
}
std::string cb_module_name =
generate_connection_block_module_name(cb_type, cb_coordinate);
ModuleId cb_module = module_manager.find_module(cb_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(cb_module));
/* Record the instance id */
cb_instance_ids[rr_gsb.get_cb_x(cb_type)][rr_gsb.get_cb_y(cb_type)] =
module_manager.num_instance(top_module, cb_module);
/* Add the module to top_module */
module_manager.add_child_module(top_module, cb_module, false);
/* Set an unique name to the instance
* Note: it is your risk to gurantee the name is unique!
*/
std::string cb_instance_name = generate_connection_block_module_name(
cb_type,
vtr::Point<size_t>(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)));
module_manager.set_child_instance_name(
top_module, cb_module,
cb_instance_ids[rr_gsb.get_cb_x(cb_type)][rr_gsb.get_cb_y(cb_type)],
cb_instance_name);
}
}
return cb_instance_ids;
}
/********************************************************************
* Add the I/O children to the top-level module, which impacts the I/O indexing
* This is the default function to build the I/O sequence/indexing
* The I/O children is added in a maze shape
* The function supports I/Os in the center of grids, starting from the
*bottom-left corner and ending at the center
*
* +----------------------+
* |+--------------------+|
* ||+------------------+||
* |||+----------------+|||
* ||||+-------------->||||
* ||||+---------------+|||
* |||+-----------------+||
* ||+-------------------+|
* |+---------------------+
* ^
* io[0]
*******************************************************************/
static void add_top_module_io_children(
ModuleManager& module_manager, const ModuleId& top_module,
const DeviceGrid& grids, const vtr::Matrix<size_t>& grid_instance_ids) {
/* Create the coordinate range for the perimeter I/Os of FPGA fabric */
std::map<e_side, std::vector<vtr::Point<size_t>>> io_coordinates =
generate_perimeter_grid_coordinates(grids);
for (const e_side& io_side : FPGA_SIDES_CLOCKWISE) {
for (const vtr::Point<size_t>& io_coord : io_coordinates[io_side]) {
t_physical_tile_type_ptr grid_type =
grids.get_physical_type(io_coord.x(), io_coord.y());
/* Bypass EMPTY grid */
if (true == is_empty_type(grid_type)) {
continue;
}
/* Skip width, height > 1 tiles (mostly heterogeneous blocks) */
if ((0 < grids.get_width_offset(io_coord.x(), io_coord.y())) ||
(0 < grids.get_height_offset(io_coord.x(), io_coord.y()))) {
continue;
}
/* 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), io_side);
ModuleId grid_module = module_manager.find_module(grid_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(grid_module));
/* Add a I/O children to top_module*/
module_manager.add_io_child(top_module, grid_module,
grid_instance_ids[io_coord.x()][io_coord.y()],
vtr::Point<int>(io_coord.x(), io_coord.y()));
}
}
/* Walk through the center grids */
size_t xmin = 1;
size_t xmax = grids.width() - 2;
size_t ymin = 1;
size_t ymax = grids.height() - 2;
std::vector<vtr::Point<size_t>> coords;
while (xmin < xmax && ymin < ymax) {
for (size_t iy = ymin; iy < ymax + 1; iy++) {
coords.push_back(vtr::Point<size_t>(xmin, iy));
}
for (size_t ix = xmin + 1; ix < xmax + 1; ix++) {
coords.push_back(vtr::Point<size_t>(ix, ymax));
}
for (size_t iy = ymax - 1; iy > ymin; iy--) {
coords.push_back(vtr::Point<size_t>(xmax, iy));
}
for (size_t ix = xmax; ix > xmin; ix--) {
coords.push_back(vtr::Point<size_t>(ix, ymin));
}
xmin++;
ymin++;
xmax--;
ymax--;
}
/* If height is odd, add the missing horizental line */
if ((grids.height() - 2) % 2 == 1) {
if (ymin == ymax) {
for (size_t ix = xmin; ix < xmax + 1; ix++) {
coords.push_back(vtr::Point<size_t>(ix, ymin));
}
}
}
/* If width is odd, add the missing vertical line */
if ((grids.width() - 2) % 2 == 1) {
if (xmin == xmax) {
for (size_t iy = ymin; iy < ymax + 1; iy++) {
coords.push_back(vtr::Point<size_t>(xmin, iy));
}
}
}
/* Now walk through the coordinates */
for (vtr::Point<size_t> coord : coords) {
t_physical_tile_type_ptr grid_type =
grids.get_physical_type(coord.x(), coord.y());
/* Bypass EMPTY grid */
if (true == is_empty_type(grid_type)) {
continue;
}
/* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
if ((0 < grids.get_width_offset(coord.x(), coord.y())) ||
(0 < grids.get_height_offset(coord.x(), coord.y()))) {
continue;
}
/* 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));
/* Add a I/O children to top_module*/
module_manager.add_io_child(top_module, grid_module,
grid_instance_ids[coord.x()][coord.y()],
vtr::Point<int>(coord.x(), coord.y()));
}
}
/********************************************************************
* Print the top-level module for the FPGA fabric in Verilog format
* This function will
@ -440,9 +54,10 @@ int build_top_module(
const TileAnnotation& tile_annotation, const RRGraphView& rr_graph,
const DeviceRRGSB& device_rr_gsb, const TileDirect& tile_direct,
const ArchDirect& arch_direct, const ConfigProtocol& config_protocol,
const CircuitModelId& sram_model, const bool& frame_view,
const bool& compact_routing_hierarchy, const bool& duplicate_grid_pin,
const FabricKey& fabric_key, const bool& generate_random_fabric_key) {
const CircuitModelId& sram_model, const FabricTile& fabric_tile,
const bool& frame_view, const bool& compact_routing_hierarchy,
const bool& duplicate_grid_pin, const FabricKey& fabric_key,
const bool& generate_random_fabric_key, const bool& verbose) {
vtr::ScopedStartFinishTimer timer("Build FPGA fabric module");
int status = CMD_EXEC_SUCCESS;
@ -455,101 +70,23 @@ int build_top_module(
/* Label module usage */
module_manager.set_module_usage(top_module, ModuleManager::MODULE_TOP);
std::map<t_rr_type, vtr::Matrix<size_t>> cb_instance_ids;
/* Add sub modules, which are grid, SB and CBX/CBY modules as instances */
/* Add all the grids across the fabric */
vtr::Matrix<size_t> grid_instance_ids =
add_top_module_grid_instances(module_manager, top_module, grids);
/* Add all the SBs across the fabric */
vtr::Matrix<size_t> sb_instance_ids = add_top_module_switch_block_instances(
module_manager, top_module, device_rr_gsb, compact_routing_hierarchy);
/* Add all the CBX and CBYs across the fabric */
cb_instance_ids[CHANX] = add_top_module_connection_block_instances(
module_manager, top_module, device_rr_gsb, CHANX,
compact_routing_hierarchy);
cb_instance_ids[CHANY] = add_top_module_connection_block_instances(
module_manager, top_module, device_rr_gsb, CHANY,
compact_routing_hierarchy);
/* Update I/O children list */
add_top_module_io_children(module_manager, top_module, grids,
grid_instance_ids);
/* Add nets when we need a complete fabric modeling,
* which is required by downstream functions
*/
if (false == frame_view) {
/* Reserve nets to be memory efficient */
reserve_module_manager_module_nets(module_manager, top_module);
/* Add module nets to connect the sub modules */
add_top_module_nets_connect_grids_and_gsbs(
module_manager, top_module, vpr_device_annotation, grids,
grid_instance_ids, rr_graph, device_rr_gsb, sb_instance_ids,
cb_instance_ids, compact_routing_hierarchy, duplicate_grid_pin);
/* Add inter-CLB direct connections */
add_top_module_nets_tile_direct_connections(
module_manager, top_module, circuit_lib, vpr_device_annotation, grids,
grid_instance_ids, tile_direct, arch_direct);
}
/* Add global ports from grid ports that are defined as global in tile
* annotation */
status = add_top_module_global_ports_from_grid_modules(
module_manager, top_module, tile_annotation, vpr_device_annotation, grids,
rr_graph, device_rr_gsb, cb_instance_ids, grid_instance_ids, clk_ntwk,
rr_clock_lookup);
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
/* Add GPIO ports from the sub-modules under this Verilog module
* For top-level module, we follow a special sequencing for I/O modules. So we
* rebuild the I/O children list here
*/
add_module_gpio_ports_from_child_modules(module_manager, top_module);
/* Organize the list of memory modules and instances
* If we have an empty fabric key, we organize the memory modules as routine
* Otherwise, we will load the fabric key directly
*/
if (true == fabric_key.empty()) {
organize_top_module_memory_modules(
module_manager, top_module, circuit_lib, config_protocol, sram_model,
grids, grid_instance_ids, device_rr_gsb, sb_instance_ids, cb_instance_ids,
compact_routing_hierarchy);
if (fabric_tile.empty()) {
status = build_top_module_fine_grained_child_instances(
module_manager, top_module, blwl_sr_banks, circuit_lib, clk_ntwk,
rr_clock_lookup, vpr_device_annotation, grids, tile_annotation, rr_graph,
device_rr_gsb, tile_direct, arch_direct, config_protocol, sram_model,
frame_view, compact_routing_hierarchy, duplicate_grid_pin, fabric_key);
} else {
VTR_ASSERT_SAFE(false == fabric_key.empty());
/* Throw a fatal error when the fabric key has a mismatch in region
* organization. between architecture file and fabric key
*/
if (size_t(config_protocol.num_regions()) != fabric_key.regions().size()) {
VTR_LOG_ERROR(
"Fabric key has a different number of configurable regions (='%ld') "
"than architecture definition (=%d)!\n",
fabric_key.regions().size(), config_protocol.num_regions());
return CMD_EXEC_FATAL_ERROR;
}
/* TODO: Build the tile instances under the top module */
status = build_top_module_tile_child_instances(
module_manager, top_module, blwl_sr_banks, circuit_lib, clk_ntwk,
rr_clock_lookup, vpr_device_annotation, grids, tile_annotation, rr_graph,
device_rr_gsb, tile_direct, arch_direct, fabric_tile, config_protocol,
sram_model, fabric_key, frame_view, verbose);
}
status = load_top_module_memory_modules_from_fabric_key(
module_manager, top_module, circuit_lib, config_protocol, fabric_key);
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
status = load_top_module_shift_register_banks_from_fabric_key(
fabric_key, blwl_sr_banks);
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
/* Update the memory organization in sub module (non-top) */
status = load_submodules_memory_modules_from_fabric_key(
module_manager, circuit_lib, config_protocol, fabric_key);
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
if (status != CMD_EXEC_SUCCESS) {
return CMD_EXEC_FATAL_ERROR;
}
/* Shuffle the configurable children in a random sequence */

View File

@ -15,6 +15,7 @@
#include "device_grid.h"
#include "device_rr_gsb.h"
#include "fabric_key.h"
#include "fabric_tile.h"
#include "memory_bank_shift_register_banks.h"
#include "module_manager.h"
#include "rr_clock_spatial_lookup.h"
@ -40,9 +41,10 @@ int build_top_module(
const TileAnnotation& tile_annotation, const RRGraphView& rr_graph,
const DeviceRRGSB& device_rr_gsb, const TileDirect& tile_direct,
const ArchDirect& arch_direct, const ConfigProtocol& config_protocol,
const CircuitModelId& sram_model, const bool& frame_view,
const bool& compact_routing_hierarchy, const bool& duplicate_grid_pin,
const FabricKey& fabric_key, const bool& generate_random_fabric_key);
const CircuitModelId& sram_model, const FabricTile& fabric_tile,
const bool& frame_view, const bool& compact_routing_hierarchy,
const bool& duplicate_grid_pin, const FabricKey& fabric_key,
const bool& generate_random_fabric_key, const bool& verbose);
} /* end namespace openfpga */

View File

@ -0,0 +1,540 @@
/********************************************************************
* This file includes functions that are used to print the top-level
* module for the FPGA fabric in Verilog format
*******************************************************************/
#include <algorithm>
#include <map>
/* Headers from vtrutil library */
#include "vtr_assert.h"
#include "vtr_log.h"
#include "vtr_time.h"
/* Headers from vpr library */
#include "vpr_utils.h"
/* Headers from openfpgashell library */
#include "build_module_graph_utils.h"
#include "build_top_module_child_fine_grained_instance.h"
#include "build_top_module_connection.h"
#include "build_top_module_directs.h"
#include "build_top_module_memory.h"
#include "build_top_module_memory_bank.h"
#include "build_top_module_utils.h"
#include "command_exit_codes.h"
#include "module_manager_memory_utils.h"
#include "module_manager_utils.h"
#include "openfpga_device_grid_utils.h"
#include "openfpga_naming.h"
#include "openfpga_reserved_words.h"
#include "rr_gsb_utils.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Add a instance of a grid module to the top module
*******************************************************************/
static size_t add_top_module_grid_instance(
ModuleManager& module_manager, const ModuleId& top_module,
t_physical_tile_type_ptr grid_type, const e_side& border_side,
const vtr::Point<size_t>& grid_coord) {
/* 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), border_side);
ModuleId grid_module = module_manager.find_module(grid_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(grid_module));
/* Record the instance id */
size_t grid_instance = module_manager.num_instance(top_module, grid_module);
/* Add the module to top_module */
module_manager.add_child_module(top_module, grid_module, false);
/* Set an unique name to the instance
* Note: it is your risk to gurantee the name is unique!
*/
std::string instance_name = generate_grid_block_instance_name(
grid_module_name_prefix, std::string(grid_type->name),
is_io_type(grid_type), border_side, grid_coord);
module_manager.set_child_instance_name(top_module, grid_module, grid_instance,
instance_name);
return grid_instance;
}
/********************************************************************
* Add all the grids as sub-modules across the fabric
* The grid modules are created for each unique type of grid (based
* on the type in data structure data_structure
* Here, we will iterate over the full fabric (coordinates)
* and instanciate the grid modules
*
* Return an 2-D array of instance ids of the grid modules that
* have been added
*
* This function assumes an island-style floorplanning for FPGA fabric
*
*
* +-----------------------------------+
* | I/O grids |
* | TOP side |
* +-----------------------------------+
*
* +-----------+ +-----------------------------------+ +------------+
* | | | | | |
* | I/O grids | | Core grids | | I/O grids |
* | LEFT side | | (CLB, Heterogeneous blocks, etc.) | | RIGHT side |
* | | | | | |
* +-----------+ +-----------------------------------+ +------------+
*
* +-----------------------------------+
* | I/O grids |
* | BOTTOM side |
* +-----------------------------------+
*
*******************************************************************/
static vtr::Matrix<size_t> add_top_module_grid_instances(
ModuleManager& module_manager, const ModuleId& top_module,
const DeviceGrid& grids) {
vtr::ScopedStartFinishTimer timer("Add grid instances to top module");
/* Reserve an array for the instance ids */
vtr::Matrix<size_t> grid_instance_ids({grids.width(), grids.height()});
grid_instance_ids.fill(size_t(-1));
/* Instanciate I/O grids */
/* Create the coordinate range for each side of FPGA fabric */
std::map<e_side, std::vector<vtr::Point<size_t>>> io_coordinates =
generate_perimeter_grid_coordinates(grids);
for (const e_side& io_side : FPGA_SIDES_CLOCKWISE) {
for (const vtr::Point<size_t>& io_coordinate : io_coordinates[io_side]) {
t_physical_tile_type_ptr phy_tile_type =
grids.get_physical_type(io_coordinate.x(), io_coordinate.y());
/* Bypass EMPTY grid */
if (true == is_empty_type(phy_tile_type)) {
continue;
}
/* Skip width, height > 1 tiles (mostly heterogeneous blocks) */
if ((0 < grids.get_width_offset(io_coordinate.x(), io_coordinate.y())) ||
(0 < grids.get_height_offset(io_coordinate.x(), io_coordinate.y()))) {
/* Find the root of this grid, the instance id should be valid.
* We just copy it here
*/
vtr::Point<size_t> root_grid_coord(
io_coordinate.x() -
grids.get_width_offset(io_coordinate.x(), io_coordinate.y()),
io_coordinate.y() -
grids.get_height_offset(io_coordinate.x(), io_coordinate.y()));
VTR_ASSERT(size_t(-1) !=
grid_instance_ids[root_grid_coord.x()][root_grid_coord.y()]);
grid_instance_ids[io_coordinate.x()][io_coordinate.y()] =
grid_instance_ids[root_grid_coord.x()][root_grid_coord.y()];
continue;
}
/* Add a grid module to top_module*/
grid_instance_ids[io_coordinate.x()][io_coordinate.y()] =
add_top_module_grid_instance(module_manager, top_module, phy_tile_type,
io_side, io_coordinate);
}
}
/* Instanciate core grids
* IMPORTANT: sequence matters here, it impacts the I/O indexing.
* We should follow the same sequence as the build_io_location_map()!
* If you change the sequence of walking through grids here, you should change
* it in the build_io_location map()!
*/
for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
t_physical_tile_type_ptr phy_tile_type = grids.get_physical_type(ix, iy);
/* Bypass EMPTY grid */
if (true == is_empty_type(phy_tile_type)) {
continue;
}
/* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
if ((0 < grids.get_width_offset(ix, iy)) ||
(0 < grids.get_height_offset(ix, iy))) {
/* Find the root of this grid, the instance id should be valid.
* We just copy it here
*/
vtr::Point<size_t> root_grid_coord(
ix - grids.get_width_offset(ix, iy),
iy - grids.get_height_offset(ix, iy));
VTR_ASSERT(size_t(-1) !=
grid_instance_ids[root_grid_coord.x()][root_grid_coord.y()]);
grid_instance_ids[ix][iy] =
grid_instance_ids[root_grid_coord.x()][root_grid_coord.y()];
continue;
}
/* Add a grid module to top_module*/
vtr::Point<size_t> grid_coord(ix, iy);
grid_instance_ids[ix][iy] = add_top_module_grid_instance(
module_manager, top_module, phy_tile_type, NUM_SIDES, grid_coord);
}
}
return grid_instance_ids;
}
/********************************************************************
* Add switch blocks across the FPGA fabric to the top-level module
* Return an 2-D array of instance ids of the switch blocks that
* have been added
*******************************************************************/
static vtr::Matrix<size_t> add_top_module_switch_block_instances(
ModuleManager& module_manager, const ModuleId& top_module,
const DeviceRRGSB& device_rr_gsb, const bool& compact_routing_hierarchy) {
vtr::ScopedStartFinishTimer timer("Add switch block instances to top module");
vtr::Point<size_t> sb_range = device_rr_gsb.get_gsb_range();
/* Reserve an array for the instance ids */
vtr::Matrix<size_t> sb_instance_ids({sb_range.x(), sb_range.y()});
sb_instance_ids.fill(size_t(-1));
for (size_t ix = 0; ix < sb_range.x(); ++ix) {
for (size_t iy = 0; iy < sb_range.y(); ++iy) {
/* If we use compact routing hierarchy, we should instanciate the unique
* module of SB */
const RRGSB& rr_gsb = device_rr_gsb.get_gsb(ix, iy);
if (false == rr_gsb.is_sb_exist()) {
continue;
}
vtr::Point<size_t> sb_coordinate(rr_gsb.get_sb_x(), rr_gsb.get_sb_y());
if (true == compact_routing_hierarchy) {
vtr::Point<size_t> sb_coord(ix, iy);
const RRGSB& unique_mirror =
device_rr_gsb.get_sb_unique_module(sb_coord);
sb_coordinate.set_x(unique_mirror.get_sb_x());
sb_coordinate.set_y(unique_mirror.get_sb_y());
}
std::string sb_module_name =
generate_switch_block_module_name(sb_coordinate);
ModuleId sb_module = module_manager.find_module(sb_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(sb_module));
/* Record the instance id */
sb_instance_ids[rr_gsb.get_sb_x()][rr_gsb.get_sb_y()] =
module_manager.num_instance(top_module, sb_module);
/* Add the module to top_module */
module_manager.add_child_module(top_module, sb_module, false);
/* Set an unique name to the instance
* Note: it is your risk to gurantee the name is unique!
*/
module_manager.set_child_instance_name(
top_module, sb_module,
sb_instance_ids[rr_gsb.get_sb_x()][rr_gsb.get_sb_y()],
generate_switch_block_module_name(
vtr::Point<size_t>(rr_gsb.get_sb_x(), rr_gsb.get_sb_y())));
}
}
return sb_instance_ids;
}
/********************************************************************
* Add switch blocks across the FPGA fabric to the top-level module
*******************************************************************/
static vtr::Matrix<size_t> add_top_module_connection_block_instances(
ModuleManager& module_manager, const ModuleId& top_module,
const DeviceRRGSB& device_rr_gsb, const t_rr_type& cb_type,
const bool& compact_routing_hierarchy) {
vtr::ScopedStartFinishTimer timer(
"Add connection block instances to top module");
vtr::Point<size_t> cb_range = device_rr_gsb.get_gsb_range();
/* Reserve an array for the instance ids */
vtr::Matrix<size_t> cb_instance_ids({cb_range.x(), cb_range.y()});
cb_instance_ids.fill(size_t(-1));
for (size_t ix = 0; ix < cb_range.x(); ++ix) {
for (size_t iy = 0; iy < cb_range.y(); ++iy) {
/* Check if the connection block exists in the device!
* Some of them do NOT exist due to heterogeneous blocks (height > 1)
* We will skip those modules
*/
const RRGSB& rr_gsb = device_rr_gsb.get_gsb(ix, iy);
vtr::Point<size_t> cb_coordinate(rr_gsb.get_cb_x(cb_type),
rr_gsb.get_cb_y(cb_type));
if (false == rr_gsb.is_cb_exist(cb_type)) {
continue;
}
/* If we use compact routing hierarchy, we should instanciate the unique
* module of SB */
if (true == compact_routing_hierarchy) {
vtr::Point<size_t> cb_coord(ix, iy);
/* Note: use GSB coordinate when inquire for unique modules!!! */
const RRGSB& unique_mirror =
device_rr_gsb.get_cb_unique_module(cb_type, cb_coord);
cb_coordinate.set_x(unique_mirror.get_cb_x(cb_type));
cb_coordinate.set_y(unique_mirror.get_cb_y(cb_type));
}
std::string cb_module_name =
generate_connection_block_module_name(cb_type, cb_coordinate);
ModuleId cb_module = module_manager.find_module(cb_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(cb_module));
/* Record the instance id */
cb_instance_ids[rr_gsb.get_cb_x(cb_type)][rr_gsb.get_cb_y(cb_type)] =
module_manager.num_instance(top_module, cb_module);
/* Add the module to top_module */
module_manager.add_child_module(top_module, cb_module, false);
/* Set an unique name to the instance
* Note: it is your risk to gurantee the name is unique!
*/
std::string cb_instance_name = generate_connection_block_module_name(
cb_type,
vtr::Point<size_t>(rr_gsb.get_cb_x(cb_type), rr_gsb.get_cb_y(cb_type)));
module_manager.set_child_instance_name(
top_module, cb_module,
cb_instance_ids[rr_gsb.get_cb_x(cb_type)][rr_gsb.get_cb_y(cb_type)],
cb_instance_name);
}
}
return cb_instance_ids;
}
/********************************************************************
* Add the I/O children to the top-level module, which impacts the I/O indexing
* This is the default function to build the I/O sequence/indexing
* The I/O children is added in a maze shape
* The function supports I/Os in the center of grids, starting from the
*bottom-left corner and ending at the center
*
* +----------------------+
* |+--------------------+|
* ||+------------------+||
* |||+----------------+|||
* ||||+-------------->||||
* ||||+---------------+|||
* |||+-----------------+||
* ||+-------------------+|
* |+---------------------+
* ^
* io[0]
*******************************************************************/
static void add_top_module_io_children(
ModuleManager& module_manager, const ModuleId& top_module,
const DeviceGrid& grids, const vtr::Matrix<size_t>& grid_instance_ids) {
/* Create the coordinate range for the perimeter I/Os of FPGA fabric */
std::map<e_side, std::vector<vtr::Point<size_t>>> io_coordinates =
generate_perimeter_grid_coordinates(grids);
for (const e_side& io_side : FPGA_SIDES_CLOCKWISE) {
for (const vtr::Point<size_t>& io_coord : io_coordinates[io_side]) {
t_physical_tile_type_ptr grid_type =
grids.get_physical_type(io_coord.x(), io_coord.y());
/* Bypass EMPTY grid */
if (true == is_empty_type(grid_type)) {
continue;
}
/* Skip width, height > 1 tiles (mostly heterogeneous blocks) */
if ((0 < grids.get_width_offset(io_coord.x(), io_coord.y())) ||
(0 < grids.get_height_offset(io_coord.x(), io_coord.y()))) {
continue;
}
/* 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), io_side);
ModuleId grid_module = module_manager.find_module(grid_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(grid_module));
/* Add a I/O children to top_module*/
module_manager.add_io_child(top_module, grid_module,
grid_instance_ids[io_coord.x()][io_coord.y()],
vtr::Point<int>(io_coord.x(), io_coord.y()));
}
}
/* Walk through the center grids */
size_t xmin = 1;
size_t xmax = grids.width() - 2;
size_t ymin = 1;
size_t ymax = grids.height() - 2;
std::vector<vtr::Point<size_t>> coords;
while (xmin < xmax && ymin < ymax) {
for (size_t iy = ymin; iy < ymax + 1; iy++) {
coords.push_back(vtr::Point<size_t>(xmin, iy));
}
for (size_t ix = xmin + 1; ix < xmax + 1; ix++) {
coords.push_back(vtr::Point<size_t>(ix, ymax));
}
for (size_t iy = ymax - 1; iy > ymin; iy--) {
coords.push_back(vtr::Point<size_t>(xmax, iy));
}
for (size_t ix = xmax; ix > xmin; ix--) {
coords.push_back(vtr::Point<size_t>(ix, ymin));
}
xmin++;
ymin++;
xmax--;
ymax--;
}
/* If height is odd, add the missing horizental line */
if ((grids.height() - 2) % 2 == 1) {
if (ymin == ymax) {
for (size_t ix = xmin; ix < xmax + 1; ix++) {
coords.push_back(vtr::Point<size_t>(ix, ymin));
}
}
}
/* If width is odd, add the missing vertical line */
if ((grids.width() - 2) % 2 == 1) {
if (xmin == xmax) {
for (size_t iy = ymin; iy < ymax + 1; iy++) {
coords.push_back(vtr::Point<size_t>(xmin, iy));
}
}
}
/* Now walk through the coordinates */
for (vtr::Point<size_t> coord : coords) {
t_physical_tile_type_ptr grid_type =
grids.get_physical_type(coord.x(), coord.y());
/* Bypass EMPTY grid */
if (true == is_empty_type(grid_type)) {
continue;
}
/* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
if ((0 < grids.get_width_offset(coord.x(), coord.y())) ||
(0 < grids.get_height_offset(coord.x(), coord.y()))) {
continue;
}
/* 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));
/* Add a I/O children to top_module*/
module_manager.add_io_child(top_module, grid_module,
grid_instance_ids[coord.x()][coord.y()],
vtr::Point<int>(coord.x(), coord.y()));
}
}
/********************************************************************
* Add the fine-grained instances to the top module of FPGA fabric
* The fine-grained instances include programmable blocks, connection blocks and
*switch blocks, each of which is an instance under the top module
*******************************************************************/
int build_top_module_fine_grained_child_instances(
ModuleManager& module_manager, const ModuleId& top_module,
MemoryBankShiftRegisterBanks& blwl_sr_banks,
const CircuitLibrary& circuit_lib, const ClockNetwork& clk_ntwk,
const RRClockSpatialLookup& rr_clock_lookup,
const VprDeviceAnnotation& vpr_device_annotation, const DeviceGrid& grids,
const TileAnnotation& tile_annotation, const RRGraphView& rr_graph,
const DeviceRRGSB& device_rr_gsb, const TileDirect& tile_direct,
const ArchDirect& arch_direct, const ConfigProtocol& config_protocol,
const CircuitModelId& sram_model, const bool& frame_view,
const bool& compact_routing_hierarchy, const bool& duplicate_grid_pin,
const FabricKey& fabric_key) {
int status = CMD_EXEC_SUCCESS;
std::map<t_rr_type, vtr::Matrix<size_t>> cb_instance_ids;
/* Add sub modules, which are grid, SB and CBX/CBY modules as instances */
/* Add all the grids across the fabric */
vtr::Matrix<size_t> grid_instance_ids =
add_top_module_grid_instances(module_manager, top_module, grids);
/* Add all the SBs across the fabric */
vtr::Matrix<size_t> sb_instance_ids = add_top_module_switch_block_instances(
module_manager, top_module, device_rr_gsb, compact_routing_hierarchy);
/* Add all the CBX and CBYs across the fabric */
cb_instance_ids[CHANX] = add_top_module_connection_block_instances(
module_manager, top_module, device_rr_gsb, CHANX,
compact_routing_hierarchy);
cb_instance_ids[CHANY] = add_top_module_connection_block_instances(
module_manager, top_module, device_rr_gsb, CHANY,
compact_routing_hierarchy);
/* Update I/O children list */
add_top_module_io_children(module_manager, top_module, grids,
grid_instance_ids);
/* Add nets when we need a complete fabric modeling,
* which is required by downstream functions
*/
if (false == frame_view) {
/* Reserve nets to be memory efficient */
reserve_module_manager_module_nets(module_manager, top_module);
/* Add module nets to connect the sub modules */
add_top_module_nets_connect_grids_and_gsbs(
module_manager, top_module, vpr_device_annotation, grids,
grid_instance_ids, rr_graph, device_rr_gsb, sb_instance_ids,
cb_instance_ids, compact_routing_hierarchy, duplicate_grid_pin);
/* Add inter-CLB direct connections */
add_top_module_nets_tile_direct_connections(
module_manager, top_module, circuit_lib, vpr_device_annotation, grids,
grid_instance_ids, tile_direct, arch_direct);
}
/* Add global ports from grid ports that are defined as global in tile
* annotation */
status = add_top_module_global_ports_from_grid_modules(
module_manager, top_module, tile_annotation, vpr_device_annotation, grids,
rr_graph, device_rr_gsb, cb_instance_ids, grid_instance_ids, clk_ntwk,
rr_clock_lookup);
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
/* Add GPIO ports from the sub-modules under this Verilog module
* For top-level module, we follow a special sequencing for I/O modules. So we
* rebuild the I/O children list here
*/
add_module_gpio_ports_from_child_modules(module_manager, top_module);
/* Organize the list of memory modules and instances
* If we have an empty fabric key, we organize the memory modules as routine
* Otherwise, we will load the fabric key directly
*/
if (true == fabric_key.empty()) {
organize_top_module_memory_modules(
module_manager, top_module, circuit_lib, config_protocol, sram_model,
grids, grid_instance_ids, device_rr_gsb, sb_instance_ids, cb_instance_ids,
compact_routing_hierarchy);
} else {
VTR_ASSERT_SAFE(false == fabric_key.empty());
/* Throw a fatal error when the fabric key has a mismatch in region
* organization. between architecture file and fabric key
*/
if (size_t(config_protocol.num_regions()) != fabric_key.regions().size()) {
VTR_LOG_ERROR(
"Fabric key has a different number of configurable regions (='%ld') "
"than architecture definition (=%d)!\n",
fabric_key.regions().size(), config_protocol.num_regions());
return CMD_EXEC_FATAL_ERROR;
}
status = load_top_module_memory_modules_from_fabric_key(
module_manager, top_module, circuit_lib, config_protocol, fabric_key);
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
status = load_top_module_shift_register_banks_from_fabric_key(
fabric_key, blwl_sr_banks);
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
/* Update the memory organization in sub module (non-top) */
status = load_submodules_memory_modules_from_fabric_key(
module_manager, circuit_lib, config_protocol, fabric_key);
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
}
return CMD_EXEC_SUCCESS;
}
} /* end namespace openfpga */

View File

@ -0,0 +1,50 @@
#ifndef BUILD_TOP_MODULE_CHILD_FINE_GRAINED_INSTANCE_H
#define BUILD_TOP_MODULE_CHILD_FINE_GRAINED_INSTANCE_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <string>
#include "arch_direct.h"
#include "circuit_library.h"
#include "clock_network.h"
#include "config_protocol.h"
#include "decoder_library.h"
#include "device_grid.h"
#include "device_rr_gsb.h"
#include "fabric_key.h"
#include "fabric_tile.h"
#include "memory_bank_shift_register_banks.h"
#include "module_manager.h"
#include "rr_clock_spatial_lookup.h"
#include "rr_graph_view.h"
#include "tile_annotation.h"
#include "tile_direct.h"
#include "vpr_device_annotation.h"
#include "vtr_geometry.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
int build_top_module_fine_grained_child_instances(
ModuleManager& module_manager, const ModuleId& top_module,
MemoryBankShiftRegisterBanks& blwl_sr_banks,
const CircuitLibrary& circuit_lib, const ClockNetwork& clk_ntwk,
const RRClockSpatialLookup& rr_clock_lookup,
const VprDeviceAnnotation& vpr_device_annotation, const DeviceGrid& grids,
const TileAnnotation& tile_annotation, const RRGraphView& rr_graph,
const DeviceRRGSB& device_rr_gsb, const TileDirect& tile_direct,
const ArchDirect& arch_direct, const ConfigProtocol& config_protocol,
const CircuitModelId& sram_model, const bool& frame_view,
const bool& compact_routing_hierarchy, const bool& duplicate_grid_pin,
const FabricKey& fabric_key);
} /* end namespace openfpga */
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,49 @@
#ifndef BUILD_TOP_MODULE_CHILD_TILE_INSTANCE_H
#define BUILD_TOP_MODULE_CHILD_TILE_INSTANCE_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <string>
#include "arch_direct.h"
#include "circuit_library.h"
#include "clock_network.h"
#include "config_protocol.h"
#include "decoder_library.h"
#include "device_grid.h"
#include "device_rr_gsb.h"
#include "fabric_key.h"
#include "fabric_tile.h"
#include "memory_bank_shift_register_banks.h"
#include "module_manager.h"
#include "rr_clock_spatial_lookup.h"
#include "rr_graph_view.h"
#include "tile_annotation.h"
#include "tile_direct.h"
#include "vpr_device_annotation.h"
#include "vtr_geometry.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
int build_top_module_tile_child_instances(
ModuleManager& module_manager, const ModuleId& top_module,
MemoryBankShiftRegisterBanks& blwl_sr_banks,
const CircuitLibrary& circuit_lib, const ClockNetwork& clk_ntwk,
const RRClockSpatialLookup& rr_clock_lookup,
const VprDeviceAnnotation& vpr_device_annotation, const DeviceGrid& grids,
const TileAnnotation& tile_annotation, const RRGraphView& rr_graph,
const DeviceRRGSB& device_rr_gsb, const TileDirect& tile_direct,
const ArchDirect& arch_direct, const FabricTile& fabric_tile,
const ConfigProtocol& config_protocol, const CircuitModelId& sram_model,
const FabricKey& fabric_key, const bool& frame_view, const bool& verbose);
} /* end namespace openfpga */
#endif

View File

@ -262,7 +262,7 @@ static void organize_top_module_tile_memory_modules(
* - This function should NOT modify configurable children
*
*******************************************************************/
static void build_top_module_configurable_regions(
void build_top_module_configurable_regions(
ModuleManager& module_manager, const ModuleId& top_module,
const ConfigProtocol& config_protocol) {
vtr::ScopedStartFinishTimer timer(

View File

@ -37,6 +37,10 @@ void organize_top_module_memory_modules(
const std::map<t_rr_type, vtr::Matrix<size_t>>& cb_instance_ids,
const bool& compact_routing_hierarchy);
void build_top_module_configurable_regions(
ModuleManager& module_manager, const ModuleId& top_module,
const ConfigProtocol& config_protocol);
void shuffle_top_module_configurable_children(
ModuleManager& module_manager, const ModuleId& top_module,
const ConfigProtocol& config_protocol);

View File

@ -11,6 +11,7 @@
/* Module builder headers */
#include "build_top_module_utils.h"
#include "openfpga_rr_graph_utils.h"
/* begin namespace openfpga */
namespace openfpga {
@ -36,6 +37,41 @@ std::string generate_grid_block_module_name_in_top_module(
border_side);
}
/********************************************************************
* Generate the port name for a grid block, by considering
* 1. its pin index
* 2. side on the grid
* 3. relative position in the physical tile
*
* This function is mainly used in the top-level module generation
* Note that it may be useful for other modules but not tried yet!
*******************************************************************/
std::string generate_grid_module_port_name_in_top_module(
const DeviceGrid& grids, const vtr::Point<size_t>& grid_coordinate,
const size_t& sink_grid_pin_index,
const VprDeviceAnnotation& vpr_device_annotation, const RRGraphView& rr_graph,
const RRNodeId& inode) {
t_physical_tile_type_ptr grid_type_descriptor =
grids.get_physical_type(grid_coordinate.x(), grid_coordinate.y());
size_t sink_grid_pin_width =
grid_type_descriptor->pin_width_offset[sink_grid_pin_index];
size_t sink_grid_pin_height =
grid_type_descriptor->pin_height_offset[sink_grid_pin_index];
BasicPort sink_grid_pin_info =
vpr_device_annotation.physical_tile_pin_port_info(grid_type_descriptor,
sink_grid_pin_index);
VTR_ASSERT(true == sink_grid_pin_info.is_valid());
int subtile_index = vpr_device_annotation.physical_tile_pin_subtile_index(
grid_type_descriptor, sink_grid_pin_index);
VTR_ASSERT(OPEN != subtile_index &&
subtile_index < grid_type_descriptor->capacity);
std::string sink_grid_port_name = generate_grid_port_name(
sink_grid_pin_width, sink_grid_pin_height, subtile_index,
get_rr_graph_single_node_side(rr_graph, inode), sink_grid_pin_info);
return sink_grid_port_name;
}
/********************************************************************
* Find the cb_type of a GSB in the top-level module
* depending on the side of SB

View File

@ -9,6 +9,7 @@
#include "device_grid.h"
#include "rr_gsb.h"
#include "vpr_device_annotation.h"
#include "vtr_geometry.h"
/********************************************************************
@ -22,6 +23,12 @@ std::string generate_grid_block_module_name_in_top_module(
const std::string& prefix, const DeviceGrid& grids,
const vtr::Point<size_t>& grid_coord);
std::string generate_grid_module_port_name_in_top_module(
const DeviceGrid& grids, const vtr::Point<size_t>& grid_coordinate,
const size_t& sink_grid_pin_index,
const VprDeviceAnnotation& vpr_device_annotation, const RRGraphView& rr_graph,
const RRNodeId& inode);
t_rr_type find_top_module_cb_type_by_sb_side(const e_side& sb_side);
vtr::Point<size_t> find_top_module_gsb_coordinate_by_sb_side(

View File

@ -197,20 +197,22 @@ BitstreamManager build_device_bitstream(const VprContext& vpr_ctx,
/* Create bitstream from grids */
VTR_LOGV(verbose, "Building grid bitstream...\n");
build_grid_bitstream(
bitstream_manager, top_block, openfpga_ctx.module_graph(),
openfpga_ctx.arch().circuit_lib, openfpga_ctx.mux_lib(),
vpr_ctx.device().grid, vpr_ctx.atom(), openfpga_ctx.vpr_device_annotation(),
openfpga_ctx.vpr_clustering_annotation(),
openfpga_ctx.vpr_placement_annotation(),
openfpga_ctx.vpr_bitstream_annotation(), verbose);
build_grid_bitstream(bitstream_manager, top_block,
openfpga_ctx.module_graph(), openfpga_ctx.fabric_tile(),
openfpga_ctx.arch().circuit_lib, openfpga_ctx.mux_lib(),
vpr_ctx.device().grid, vpr_ctx.atom(),
openfpga_ctx.vpr_device_annotation(),
openfpga_ctx.vpr_clustering_annotation(),
openfpga_ctx.vpr_placement_annotation(),
openfpga_ctx.vpr_bitstream_annotation(), verbose);
VTR_LOGV(verbose, "Done\n");
/* Create bitstream from routing architectures */
VTR_LOGV(verbose, "Building routing bitstream...\n");
build_routing_bitstream(
bitstream_manager, top_block, openfpga_ctx.module_graph(),
openfpga_ctx.arch().circuit_lib, openfpga_ctx.mux_lib(), vpr_ctx.atom(),
openfpga_ctx.fabric_tile(), openfpga_ctx.arch().circuit_lib,
openfpga_ctx.mux_lib(), vpr_ctx.atom(),
openfpga_ctx.vpr_device_annotation(), openfpga_ctx.vpr_routing_annotation(),
vpr_ctx.device().rr_graph, openfpga_ctx.device_rr_gsb(),
openfpga_ctx.flow_manager().compress_routing(), verbose);

View File

@ -39,7 +39,7 @@ static void rec_build_module_fabric_dependent_chain_bitstream(
const ModuleManager& module_manager, const ModuleId& top_module,
const ModuleId& parent_module, const ConfigRegionId& config_region,
FabricBitstream& fabric_bitstream,
const FabricBitRegionId& fabric_bitstream_region) {
const FabricBitRegionId& fabric_bitstream_region, const bool& verbose) {
/* Depth-first search: if we have any children in the parent_block,
* we dive to the next level first!
*/
@ -69,7 +69,7 @@ static void rec_build_module_fabric_dependent_chain_bitstream(
rec_build_module_fabric_dependent_chain_bitstream(
bitstream_manager, child_block, module_manager, top_module,
child_module, config_region, fabric_bitstream,
fabric_bitstream_region);
fabric_bitstream_region, verbose);
}
} else {
for (size_t child_id = 0;
@ -87,6 +87,11 @@ static void rec_build_module_fabric_dependent_chain_bitstream(
/* Find the child block that matches the instance name! */
ConfigBlockId child_block =
bitstream_manager.find_child_block(parent_block, instance_name);
VTR_LOGV(verbose,
"Try to find a configurable block corresponding to module "
"'%s' in FPGA fabric under its parent block '%s'\n",
instance_name.c_str(),
bitstream_manager.block_name(parent_block).c_str());
/* We must have one valid block id! */
VTR_ASSERT(true == bitstream_manager.valid_block_id(child_block));
@ -94,7 +99,7 @@ static void rec_build_module_fabric_dependent_chain_bitstream(
rec_build_module_fabric_dependent_chain_bitstream(
bitstream_manager, child_block, module_manager, top_module,
child_module, config_region, fabric_bitstream,
fabric_bitstream_region);
fabric_bitstream_region, verbose);
}
}
/* Ensure that there should be no configuration bits in the parent block */
@ -534,7 +539,7 @@ static void build_module_fabric_dependent_bitstream(
const ConfigProtocol& config_protocol, const CircuitLibrary& circuit_lib,
const BitstreamManager& bitstream_manager, const ConfigBlockId& top_block,
const ModuleManager& module_manager, const ModuleId& top_module,
FabricBitstream& fabric_bitstream) {
FabricBitstream& fabric_bitstream, const bool& verbose) {
switch (config_protocol.type()) {
case CONFIG_MEM_STANDALONE: {
/* Reserve bits before build-up */
@ -546,7 +551,7 @@ static void build_module_fabric_dependent_bitstream(
fabric_bitstream.add_region();
rec_build_module_fabric_dependent_chain_bitstream(
bitstream_manager, top_block, module_manager, top_module, top_module,
config_region, fabric_bitstream, fabric_bitstream_region);
config_region, fabric_bitstream, fabric_bitstream_region, verbose);
}
break;
@ -561,7 +566,7 @@ static void build_module_fabric_dependent_bitstream(
fabric_bitstream.add_region();
rec_build_module_fabric_dependent_chain_bitstream(
bitstream_manager, top_block, module_manager, top_module, top_module,
config_region, fabric_bitstream, fabric_bitstream_region);
config_region, fabric_bitstream, fabric_bitstream_region, verbose);
fabric_bitstream.reverse_region_bits(fabric_bitstream_region);
}
break;
@ -791,7 +796,7 @@ FabricBitstream build_fabric_dependent_bitstream(
/* Start build-up formally */
build_module_fabric_dependent_bitstream(
config_protocol, circuit_lib, bitstream_manager, top_block, module_manager,
top_module, fabric_bitstream);
top_module, fabric_bitstream, verbose);
VTR_LOGV(verbose, "Built %lu configuration bits for fabric\n",
fabric_bitstream.num_bits());

View File

@ -819,9 +819,10 @@ static void build_physical_block_bitstream(
*******************************************************************/
void build_grid_bitstream(
BitstreamManager& bitstream_manager, const ConfigBlockId& top_block,
const ModuleManager& module_manager, const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib, const DeviceGrid& grids,
const AtomContext& atom_ctx, const VprDeviceAnnotation& device_annotation,
const ModuleManager& module_manager, const FabricTile& fabric_tile,
const CircuitLibrary& circuit_lib, const MuxLibrary& mux_lib,
const DeviceGrid& grids, const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
const VprClusteringAnnotation& cluster_annotation,
const VprPlacementAnnotation& place_annotation,
const VprBitstreamAnnotation& bitstream_annotation, const bool& verbose) {
@ -841,8 +842,22 @@ void build_grid_bitstream(
}
/* Add a grid module to top_module*/
vtr::Point<size_t> grid_coord(ix, iy);
/* TODO: If the fabric tile is not empty, find the tile module and create
* the block accordingly. Also to support future hierarchy changes, when
* creating the blocks, trace backward until reach the current top block.
* If any block is missing during the back tracing, create it. */
ConfigBlockId parent_block = top_block;
FabricTileId curr_tile =
fabric_tile.find_tile_by_pb_coordinate(grid_coord);
if (fabric_tile.valid_tile_id(curr_tile)) {
vtr::Point<size_t> tile_coord = fabric_tile.tile_coordinate(curr_tile);
std::string tile_inst_name = generate_tile_module_name(tile_coord);
parent_block = bitstream_manager.find_or_create_child_block(
top_block, tile_inst_name);
}
build_physical_block_bitstream(
bitstream_manager, top_block, module_manager, circuit_lib, mux_lib,
bitstream_manager, parent_block, module_manager, circuit_lib, mux_lib,
atom_ctx, device_annotation, cluster_annotation, place_annotation,
bitstream_annotation, grids, grid_coord, NUM_SIDES);
}
@ -868,8 +883,22 @@ void build_grid_bitstream(
(0 < grids.get_height_offset(io_coordinate.x(), io_coordinate.y()))) {
continue;
}
/* TODO: If the fabric tile is not empty, find the tile module and create
* the block accordingly. Also to support future hierarchy changes, when
* creating the blocks, trace backward until reach the current top block.
* If any block is missing during the back tracing, create it. */
ConfigBlockId parent_block = top_block;
FabricTileId curr_tile =
fabric_tile.find_tile_by_pb_coordinate(io_coordinate);
if (fabric_tile.valid_tile_id(curr_tile)) {
vtr::Point<size_t> tile_coord = fabric_tile.tile_coordinate(curr_tile);
std::string tile_inst_name = generate_tile_module_name(tile_coord);
parent_block = bitstream_manager.find_or_create_child_block(
top_block, tile_inst_name);
}
build_physical_block_bitstream(
bitstream_manager, top_block, module_manager, circuit_lib, mux_lib,
bitstream_manager, parent_block, module_manager, circuit_lib, mux_lib,
atom_ctx, device_annotation, cluster_annotation, place_annotation,
bitstream_annotation, grids, io_coordinate, io_side);
}

View File

@ -9,6 +9,7 @@
#include "bitstream_manager.h"
#include "circuit_library.h"
#include "device_grid.h"
#include "fabric_tile.h"
#include "module_manager.h"
#include "mux_library.h"
#include "vpr_bitstream_annotation.h"
@ -26,9 +27,10 @@ namespace openfpga {
void build_grid_bitstream(
BitstreamManager& bitstream_manager, const ConfigBlockId& top_block,
const ModuleManager& module_manager, const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib, const DeviceGrid& grids,
const AtomContext& atom_ctx, const VprDeviceAnnotation& device_annotation,
const ModuleManager& module_manager, const FabricTile& fabric_tile,
const CircuitLibrary& circuit_lib, const MuxLibrary& mux_lib,
const DeviceGrid& grids, const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
const VprClusteringAnnotation& cluster_annotation,
const VprPlacementAnnotation& place_annotation,
const VprBitstreamAnnotation& bitstream_annotation, const bool& verbose);

View File

@ -433,9 +433,9 @@ static void build_connection_block_bitstream(
static void build_connection_block_bitstreams(
BitstreamManager& bitstream_manager,
const ConfigBlockId& top_configurable_block,
const ModuleManager& module_manager, const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib, const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
const ModuleManager& module_manager, const FabricTile& fabric_tile,
const CircuitLibrary& circuit_lib, const MuxLibrary& mux_lib,
const AtomContext& atom_ctx, const VprDeviceAnnotation& device_annotation,
const VprRoutingAnnotation& routing_annotation, const RRGraphView& rr_graph,
const DeviceRRGSB& device_rr_gsb, const bool& compact_routing_hierarchy,
const t_rr_type& cb_type, const bool& verbose) {
@ -491,13 +491,26 @@ static void build_connection_block_bitstreams(
continue;
}
/* TODO: If the fabric tile is not empty, find the tile module and create
* the block accordingly. Also to support future hierarchy changes, when
* creating the blocks, trace backward until reach the current top block.
* If any block is missing during the back tracing, create it. */
ConfigBlockId parent_block = top_configurable_block;
FabricTileId curr_tile = fabric_tile.find_tile_by_cb_coordinate(
cb_type, vtr::Point<size_t>(ix, iy));
if (fabric_tile.valid_tile_id(curr_tile)) {
vtr::Point<size_t> tile_coord = fabric_tile.tile_coordinate(curr_tile);
std::string tile_inst_name = generate_tile_module_name(tile_coord);
parent_block = bitstream_manager.find_or_create_child_block(
top_configurable_block, tile_inst_name);
}
/* 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 */
bitstream_manager.add_child_block(top_configurable_block,
cb_configurable_block);
bitstream_manager.add_child_block(parent_block, cb_configurable_block);
/* Reserve child blocks for new created block */
bitstream_manager.reserve_child_blocks(
@ -524,9 +537,9 @@ static void build_connection_block_bitstreams(
void build_routing_bitstream(
BitstreamManager& bitstream_manager,
const ConfigBlockId& top_configurable_block,
const ModuleManager& module_manager, const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib, const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
const ModuleManager& module_manager, const FabricTile& fabric_tile,
const CircuitLibrary& circuit_lib, const MuxLibrary& mux_lib,
const AtomContext& atom_ctx, const VprDeviceAnnotation& device_annotation,
const VprRoutingAnnotation& routing_annotation, const RRGraphView& rr_graph,
const DeviceRRGSB& device_rr_gsb, const bool& compact_routing_hierarchy,
const bool& verbose) {
@ -573,13 +586,25 @@ void build_routing_bitstream(
continue;
}
/* TODO: If the fabric tile is not empty, find the tile module and create
* the block accordingly. Also to support future hierarchy changes, when
* creating the blocks, trace backward until reach the current top block.
* If any block is missing during the back tracing, create it. */
ConfigBlockId parent_block = top_configurable_block;
FabricTileId curr_tile = fabric_tile.find_tile_by_sb_coordinate(sb_coord);
if (fabric_tile.valid_tile_id(curr_tile)) {
vtr::Point<size_t> tile_coord = fabric_tile.tile_coordinate(curr_tile);
std::string tile_inst_name = generate_tile_module_name(tile_coord);
parent_block = bitstream_manager.find_or_create_child_block(
top_configurable_block, tile_inst_name);
}
/* 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 */
bitstream_manager.add_child_block(top_configurable_block,
sb_configurable_block);
bitstream_manager.add_child_block(parent_block, sb_configurable_block);
/* Reserve child blocks for new created block */
bitstream_manager.reserve_child_blocks(
@ -605,17 +630,17 @@ void build_routing_bitstream(
VTR_LOG("Generating bitstream for X-direction Connection blocks ...");
build_connection_block_bitstreams(
bitstream_manager, top_configurable_block, module_manager, circuit_lib,
mux_lib, atom_ctx, device_annotation, routing_annotation, rr_graph,
device_rr_gsb, compact_routing_hierarchy, CHANX, verbose);
bitstream_manager, top_configurable_block, module_manager, fabric_tile,
circuit_lib, mux_lib, atom_ctx, device_annotation, routing_annotation,
rr_graph, device_rr_gsb, compact_routing_hierarchy, CHANX, verbose);
VTR_LOG("Done\n");
VTR_LOG("Generating bitstream for Y-direction Connection blocks ...");
build_connection_block_bitstreams(
bitstream_manager, top_configurable_block, module_manager, circuit_lib,
mux_lib, atom_ctx, device_annotation, routing_annotation, rr_graph,
device_rr_gsb, compact_routing_hierarchy, CHANY, verbose);
bitstream_manager, top_configurable_block, module_manager, fabric_tile,
circuit_lib, mux_lib, atom_ctx, device_annotation, routing_annotation,
rr_graph, device_rr_gsb, compact_routing_hierarchy, CHANY, verbose);
VTR_LOG("Done\n");
}

View File

@ -12,6 +12,7 @@
#include "bitstream_manager.h"
#include "circuit_library.h"
#include "device_rr_gsb.h"
#include "fabric_tile.h"
#include "module_manager.h"
#include "mux_library.h"
#include "vpr_context.h"
@ -28,9 +29,9 @@ namespace openfpga {
void build_routing_bitstream(
BitstreamManager& bitstream_manager,
const ConfigBlockId& top_configurable_block,
const ModuleManager& module_manager, const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib, const AtomContext& atom_ctx,
const VprDeviceAnnotation& device_annotation,
const ModuleManager& module_manager, const FabricTile& fabric_tile,
const CircuitLibrary& circuit_lib, const MuxLibrary& mux_lib,
const AtomContext& atom_ctx, const VprDeviceAnnotation& device_annotation,
const VprRoutingAnnotation& routing_annotation, const RRGraphView& rr_graph,
const DeviceRRGSB& device_rr_gsb, const bool& compact_routing_hierarchy,
const bool& verbose);

View File

@ -13,6 +13,7 @@
#include <iomanip>
/* Headers from vtrutil library */
#include "command_exit_codes.h"
#include "vtr_assert.h"
#include "vtr_log.h"
#include "vtr_time.h"
@ -338,15 +339,19 @@ static void print_pnr_sdc_compact_routing_disable_switch_block_outputs(
* 3. Design constraints for Connection Blocks
* 4. Design constraints for breaking the combinational loops in FPGA fabric
*******************************************************************/
void print_pnr_sdc(const PnrSdcOption& sdc_options,
const DeviceContext& device_ctx,
const VprDeviceAnnotation& device_annotation,
const DeviceRRGSB& device_rr_gsb,
const ModuleManager& module_manager,
const MuxLibrary& mux_lib, const CircuitLibrary& circuit_lib,
const FabricGlobalPortInfo& global_ports,
const SimulationSetting& sim_setting,
const bool& compact_routing_hierarchy) {
int print_pnr_sdc(
const PnrSdcOption& sdc_options, const DeviceContext& device_ctx,
const VprDeviceAnnotation& device_annotation, const FabricTile& fabric_tile,
const DeviceRRGSB& device_rr_gsb, const ModuleManager& module_manager,
const MuxLibrary& mux_lib, const CircuitLibrary& circuit_lib,
const FabricGlobalPortInfo& global_ports,
const SimulationSetting& sim_setting, const bool& compact_routing_hierarchy) {
/* Fabric tile is not supported yet, error out */
if (!fabric_tile.empty()) {
VTR_LOG_ERROR("Tile-based modules are not supported yet!\n");
return CMD_EXEC_FATAL_ERROR;
}
std::string top_module_name = generate_fpga_top_module_name();
ModuleId top_module = module_manager.find_module(top_module_name);
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
@ -453,6 +458,8 @@ void print_pnr_sdc(const PnrSdcOption& sdc_options,
print_pnr_sdc_grid_hierarchy(sdc_options.sdc_dir(), device_ctx,
device_annotation, module_manager, top_module);
}
return CMD_EXEC_SUCCESS;
}
} /* end namespace openfpga */

View File

@ -10,6 +10,7 @@
#include "circuit_library.h"
#include "device_rr_gsb.h"
#include "fabric_global_port_info.h"
#include "fabric_tile.h"
#include "module_manager.h"
#include "mux_library.h"
#include "pnr_sdc_option.h"
@ -24,15 +25,13 @@
/* begin namespace openfpga */
namespace openfpga {
void print_pnr_sdc(const PnrSdcOption& sdc_options,
const DeviceContext& device_ctx,
const VprDeviceAnnotation& device_annotation,
const DeviceRRGSB& device_rr_gsb,
const ModuleManager& module_manager,
const MuxLibrary& mux_lib, const CircuitLibrary& circuit_lib,
const FabricGlobalPortInfo& global_ports,
const SimulationSetting& sim_setting,
const bool& compact_routing_hierarchy);
int print_pnr_sdc(
const PnrSdcOption& sdc_options, const DeviceContext& device_ctx,
const VprDeviceAnnotation& device_annotation, const FabricTile& fabric_tile,
const DeviceRRGSB& device_rr_gsb, const ModuleManager& module_manager,
const MuxLibrary& mux_lib, const CircuitLibrary& circuit_lib,
const FabricGlobalPortInfo& global_ports,
const SimulationSetting& sim_setting, const bool& compact_routing_hierarchy);
} /* end namespace openfpga */

View File

@ -23,6 +23,7 @@
#include "verilog_routing.h"
#include "verilog_simulation_info_writer.h"
#include "verilog_submodule.h"
#include "verilog_tile.h"
#include "verilog_top_module.h"
#include "verilog_top_testbench.h"
@ -53,15 +54,18 @@ namespace openfpga {
* We should think clearly about how to handle them for both Verilog and SPICE
*generators!
********************************************************************/
void fpga_fabric_verilog(
int fpga_fabric_verilog(
ModuleManager &module_manager, NetlistManager &netlist_manager,
const MemoryBankShiftRegisterBanks &blwl_sr_banks,
const CircuitLibrary &circuit_lib, const MuxLibrary &mux_lib,
const DecoderLibrary &decoder_lib, const DeviceContext &device_ctx,
const VprDeviceAnnotation &device_annotation,
const DeviceRRGSB &device_rr_gsb, const FabricVerilogOption &options) {
const DeviceRRGSB &device_rr_gsb, const FabricTile &fabric_tile,
const FabricVerilogOption &options) {
vtr::ScopedStartFinishTimer timer("Write Verilog netlists for FPGA fabric\n");
int status_code = CMD_EXEC_SUCCESS;
std::string src_dir_path = format_dir_path(options.output_directory());
/* Create directories */
@ -83,6 +87,13 @@ void fpga_fabric_verilog(
std::string rr_dir_path = src_dir_path + std::string(DEFAULT_RR_DIR_NAME);
create_directory(rr_dir_path);
/* Sub directory under SRC directory to contain all the tile netlists
*/
std::string tile_dir_path = src_dir_path + std::string(DEFAULT_TILE_DIR_NAME);
if (!fabric_tile.empty()) {
create_directory(tile_dir_path);
}
/* Print Verilog files containing preprocessing flags */
print_verilog_preprocessing_flags_netlist(std::string(src_dir_path), options);
@ -115,6 +126,16 @@ void fpga_fabric_verilog(
device_ctx, device_annotation, lb_dir_path,
std::string(DEFAULT_LB_DIR_NAME), options, options.verbose_output());
/* Generate tiles */
if (!fabric_tile.empty()) {
status_code = print_verilog_tiles(
netlist_manager, const_cast<const ModuleManager &>(module_manager),
tile_dir_path, fabric_tile, options);
if (status_code != CMD_EXEC_SUCCESS) {
return CMD_EXEC_FATAL_ERROR;
}
}
/* Generate FPGA fabric */
print_verilog_core_module(netlist_manager,
const_cast<const ModuleManager &>(module_manager),
@ -132,6 +153,8 @@ void fpga_fabric_verilog(
*/
VTR_LOGV(options.verbose_output(), "Written %lu Verilog modules in total\n",
module_manager.num_modules());
return CMD_EXEC_SUCCESS;
}
/********************************************************************

View File

@ -16,6 +16,7 @@
#include "device_rr_gsb.h"
#include "fabric_bitstream.h"
#include "fabric_global_port_info.h"
#include "fabric_tile.h"
#include "fabric_verilog_options.h"
#include "io_location_map.h"
#include "io_name_map.h"
@ -37,13 +38,14 @@
/* begin namespace openfpga */
namespace openfpga {
void fpga_fabric_verilog(
int fpga_fabric_verilog(
ModuleManager& module_manager, NetlistManager& netlist_manager,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const CircuitLibrary& circuit_lib, const MuxLibrary& mux_lib,
const DecoderLibrary& decoder_lib, const DeviceContext& device_ctx,
const VprDeviceAnnotation& device_annotation,
const DeviceRRGSB& device_rr_gsb, const FabricVerilogOption& options);
const DeviceRRGSB& device_rr_gsb, const FabricTile& fabric_tile,
const FabricVerilogOption& options);
int fpga_verilog_full_testbench(
const ModuleManager& module_manager,

View File

@ -138,6 +138,15 @@ void print_verilog_fabric_include_netlist(const NetlistManager& netlist_manager,
}
fp << std::endl;
/* Include all the tile modules */
print_verilog_comment(
fp, std::string("------ Include tile module netlists -----"));
for (const NetlistId& nlist_id :
netlist_manager.netlists_by_type(NetlistManager::TILE_MODULE_NETLIST)) {
print_verilog_include_netlist(fp, netlist_manager.netlist_name(nlist_id));
}
fp << std::endl;
/* Include FPGA top module */
print_verilog_comment(
fp, std::string("------ Include fabric top-level netlists -----"));

View File

@ -0,0 +1,110 @@
/********************************************************************
* This file includes functions that are used to print the top-level
* module for the FPGA fabric in Verilog format
*******************************************************************/
#include "verilog_tile.h"
#include <algorithm>
#include <fstream>
#include <map>
#include "command_exit_codes.h"
#include "openfpga_digest.h"
#include "openfpga_naming.h"
#include "verilog_constants.h"
#include "verilog_module_writer.h"
#include "verilog_writer_utils.h"
#include "vtr_assert.h"
#include "vtr_log.h"
#include "vtr_time.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Print the tile module for the FPGA fabric in Verilog format
*******************************************************************/
static int print_verilog_tile_module_netlist(
NetlistManager& netlist_manager, const ModuleManager& module_manager,
const std::string& verilog_dir, const FabricTile& fabric_tile,
const FabricTileId& fabric_tile_id, const FabricVerilogOption& options) {
/* Create a module as the top-level fabric, and add it to the module manager
*/
vtr::Point<size_t> tile_coord = fabric_tile.tile_coordinate(fabric_tile_id);
std::string tile_module_name = generate_tile_module_name(tile_coord);
ModuleId tile_module = module_manager.find_module(tile_module_name);
if (!module_manager.valid_module_id(tile_module)) {
return CMD_EXEC_FATAL_ERROR;
}
/* Start printing out Verilog netlists */
/* Create the file name for Verilog netlist */
std::string verilog_fname(generate_tile_module_netlist_name(
tile_module_name, std::string(VERILOG_NETLIST_FILE_POSTFIX)));
std::string verilog_fpath(verilog_dir + verilog_fname);
VTR_LOG("Writing Verilog netlist '%s' for tile module '%s'...",
verilog_fpath.c_str(), tile_module_name.c_str());
/* Create the file stream */
std::fstream fp;
fp.open(verilog_fpath, std::fstream::out | std::fstream::trunc);
check_file_stream(verilog_fpath.c_str(), fp);
print_verilog_file_header(fp, std::string("Tile Verilog module for FPGA"),
options.time_stamp());
/* Write the module content in Verilog format */
write_verilog_module_to_file(fp, module_manager, tile_module,
options.explicit_port_mapping(),
options.default_net_type());
/* Add an empty line as a splitter */
fp << std::endl;
/* Close file handler */
fp.close();
/* Add fname to the netlist name list */
NetlistId nlist_id = NetlistId::INVALID();
if (options.use_relative_path()) {
nlist_id = netlist_manager.add_netlist(verilog_fname);
} else {
nlist_id = netlist_manager.add_netlist(verilog_fpath);
}
VTR_ASSERT(nlist_id);
netlist_manager.set_netlist_type(nlist_id,
NetlistManager::TILE_MODULE_NETLIST);
VTR_LOG("Done\n");
return CMD_EXEC_SUCCESS;
}
/********************************************************************
* Print all the tile modules for the FPGA fabric in Verilog format
*******************************************************************/
int print_verilog_tiles(NetlistManager& netlist_manager,
const ModuleManager& module_manager,
const std::string& verilog_dir,
const FabricTile& fabric_tile,
const FabricVerilogOption& options) {
vtr::ScopedStartFinishTimer timer("Build tile modules for the FPGA fabric");
int status_code = CMD_EXEC_SUCCESS;
/* Build a module for each unique tile */
for (FabricTileId fabric_tile_id : fabric_tile.unique_tiles()) {
status_code = print_verilog_tile_module_netlist(
netlist_manager, module_manager, verilog_dir, fabric_tile, fabric_tile_id,
options);
if (status_code != CMD_EXEC_SUCCESS) {
return CMD_EXEC_FATAL_ERROR;
}
}
return status_code;
}
} /* end namespace openfpga */

View File

@ -0,0 +1,29 @@
#ifndef VERILOG_TILE_H
#define VERILOG_TILE_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <string>
#include "fabric_tile.h"
#include "fabric_verilog_options.h"
#include "module_manager.h"
#include "netlist_manager.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
int print_verilog_tiles(NetlistManager& netlist_manager,
const ModuleManager& module_manager,
const std::string& verilog_dir,
const FabricTile& fabric_tile,
const FabricVerilogOption& options);
} /* end namespace openfpga */
#endif

View File

@ -61,4 +61,63 @@ generate_perimeter_grid_coordinates(const DeviceGrid& grids) {
return io_coordinates;
}
/********************************************************************
* Create a list of the coordinates for the tiles on the device perimeter
* It follows a clockwise sequence when including the coordinates.
* Note that different from the function for grids, this function include corner
*tiles! Detailed sequence is as follows:
* - Top-left
* - TOP side, from left most to the right
* - Top-right
* - Right side, from top to the bottom
* - Bottom-right
* - Bottom side, from right to the left
* - Bottom-left
* - Left side, from bottom to top
*
* Note:
* - This function offers a standard sequence to walk through the
* grids on the perimeter of an FPGA device
* When sequence matters, this function should be used to ensure
* consistency between functions.
*******************************************************************/
std::map<e_side, std::vector<vtr::Point<size_t>>>
generate_perimeter_tile_coordinates(const DeviceGrid& grids) {
/* Search the border side */
/* Create the coordinate range for each side of FPGA fabric */
std::vector<e_side> fpga_sides{TOP, RIGHT, BOTTOM, LEFT};
std::map<e_side, std::vector<vtr::Point<size_t>>> io_coordinates;
/* Top-left */
io_coordinates[TOP].push_back(vtr::Point<size_t>(0, grids.height() - 1));
/* TOP side*/
for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
io_coordinates[TOP].push_back(vtr::Point<size_t>(ix, grids.height() - 1));
}
/* Top-Right */
io_coordinates[RIGHT].push_back(
vtr::Point<size_t>(grids.width() - 1, grids.height() - 1));
/* RIGHT side */
for (size_t iy = grids.height() - 2; iy > 0; --iy) {
io_coordinates[RIGHT].push_back(vtr::Point<size_t>(grids.width() - 1, iy));
}
/* Bottom-right */
io_coordinates[BOTTOM].push_back(vtr::Point<size_t>(grids.width() - 1, 0));
/* BOTTOM side*/
for (size_t ix = grids.width() - 2; ix > 0; --ix) {
io_coordinates[BOTTOM].push_back(vtr::Point<size_t>(ix, 0));
}
/* Bottom-left */
io_coordinates[BOTTOM].push_back(vtr::Point<size_t>(0, 0));
/* LEFT side */
for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
io_coordinates[LEFT].push_back(vtr::Point<size_t>(0, iy));
}
return io_coordinates;
}
} /* end namespace openfpga */

View File

@ -24,6 +24,9 @@ constexpr std::array<e_side, 4> FPGA_SIDES_CLOCKWISE{TOP, RIGHT, BOTTOM, LEFT};
std::map<e_side, std::vector<vtr::Point<size_t>>>
generate_perimeter_grid_coordinates(const DeviceGrid& grids);
std::map<e_side, std::vector<vtr::Point<size_t>>>
generate_perimeter_tile_coordinates(const DeviceGrid& grids);
} /* end namespace openfpga */
#endif

View File

@ -0,0 +1,72 @@
# Run VPR for the 'and' design
#--write_rr_graph example_rr_graph.xml
vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} --clock_modeling route
# Read OpenFPGA architecture definition
read_openfpga_arch -f ${OPENFPGA_ARCH_FILE}
# Read OpenFPGA simulation settings
read_openfpga_simulation_setting -f ${OPENFPGA_SIM_SETTING_FILE}
# Annotate the OpenFPGA architecture to VPR data base
# to debug use --verbose options
link_openfpga_arch --activity_file ${ACTIVITY_FILE} --sort_gsb_chan_node_in_edges
# Check and correct any naming conflicts in the BLIF netlist
check_netlist_naming_conflict --fix --report ./netlist_renaming.xml
# Apply fix-up to Look-Up Table truth tables based on packing results
lut_truth_table_fixup
# Build the module graph
# - Enabled compression on routing architecture modules
# - Enable pin duplication on grid modules
build_fabric --compress_routing --group_tile ${OPENFPGA_GROUP_TILE_CONFIG_FILE} #--verbose
# Write the fabric hierarchy of module graph to a file
# This is used by hierarchical PnR flows
write_fabric_hierarchy --file ./fabric_hierarchy.txt
# Repack the netlist to physical pbs
# This must be done before bitstream generator and testbench generation
# Strongly recommend it is done after all the fix-up have been applied
repack #--verbose
# Build the bitstream
# - Output the fabric-independent bitstream to a file
build_architecture_bitstream --verbose --write_file fabric_independent_bitstream.xml
# Build fabric-dependent bitstream
build_fabric_bitstream --verbose
# Write fabric-dependent bitstream
write_fabric_bitstream --file fabric_bitstream.bit --format plain_text
# Write the Verilog netlist for FPGA fabric
# - Enable the use of explicit port mapping in Verilog netlist
write_fabric_verilog --file ./SRC --explicit_port_mapping --include_timing --print_user_defined_template --verbose
# Write the Verilog testbench for FPGA fabric
# - We suggest the use of same output directory as fabric Verilog netlists
# - Must specify the reference benchmark file if you want to output any testbenches
# - Enable top-level testbench which is a full verification including programming circuit and core logic of FPGA
# - Enable pre-configured top-level testbench which is a fast verification skipping programming phase
# - Simulation ini file is optional and is needed only when you need to interface different HDL simulators using openfpga flow-run scripts
write_full_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} --explicit_port_mapping --include_signal_init --bitstream fabric_bitstream.bit
# Write the SDC files for PnR backend
# - Turn on every options here
# FIXME: Not supported yet.
#write_pnr_sdc --file ./SDC
# Write SDC to disable timing for configure ports
write_sdc_disable_timing_configure_ports --file ./SDC/disable_configure_ports.sdc
# Write the SDC to run timing analysis for a mapped FPGA fabric
write_analysis_sdc --file ./SDC_analysis
# Finish and exit OpenFPGA
exit
# Note :
# To run verification at the end of the flow maintain source in ./SRC directory

View File

@ -0,0 +1,73 @@
# Run VPR for the 'and' design
#--write_rr_graph example_rr_graph.xml
vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} --clock_modeling route
# Read OpenFPGA architecture definition
read_openfpga_arch -f ${OPENFPGA_ARCH_FILE}
# Read OpenFPGA simulation settings
read_openfpga_simulation_setting -f ${OPENFPGA_SIM_SETTING_FILE}
# Annotate the OpenFPGA architecture to VPR data base
# to debug use --verbose options
link_openfpga_arch --activity_file ${ACTIVITY_FILE} --sort_gsb_chan_node_in_edges
# Check and correct any naming conflicts in the BLIF netlist
check_netlist_naming_conflict --fix --report ./netlist_renaming.xml
# Apply fix-up to Look-Up Table truth tables based on packing results
lut_truth_table_fixup
# Build the module graph
# - Enabled compression on routing architecture modules
# - Enable pin duplication on grid modules
build_fabric --compress_routing --group_tile ${OPENFPGA_GROUP_TILE_CONFIG_FILE} #--verbose
# Write the fabric hierarchy of module graph to a file
# This is used by hierarchical PnR flows
write_fabric_hierarchy --file ./fabric_hierarchy.txt
# Repack the netlist to physical pbs
# This must be done before bitstream generator and testbench generation
# Strongly recommend it is done after all the fix-up have been applied
repack #--verbose
# Build the bitstream
# - Output the fabric-independent bitstream to a file
build_architecture_bitstream --verbose --write_file fabric_independent_bitstream.xml
# Build fabric-dependent bitstream
build_fabric_bitstream --verbose
# Write fabric-dependent bitstream
write_fabric_bitstream --file fabric_bitstream.bit --format plain_text
# Write the Verilog netlist for FPGA fabric
# - Enable the use of explicit port mapping in Verilog netlist
write_fabric_verilog --file ./SRC --explicit_port_mapping --include_timing --print_user_defined_template --verbose
# Write the Verilog testbench for FPGA fabric
# - We suggest the use of same output directory as fabric Verilog netlists
# - Must specify the reference benchmark file if you want to output any testbenches
# - Enable top-level testbench which is a full verification including programming circuit and core logic of FPGA
# - Enable pre-configured top-level testbench which is a fast verification skipping programming phase
# - Simulation ini file is optional and is needed only when you need to interface different HDL simulators using openfpga flow-run scripts
write_preconfigured_fabric_wrapper --embed_bitstream iverilog --file ./SRC --explicit_port_mapping
write_preconfigured_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} --explicit_port_mapping
# Write the SDC files for PnR backend
# - Turn on every options here
# FIXME: Not supported yet.
#write_pnr_sdc --file ./SDC
# Write SDC to disable timing for configure ports
write_sdc_disable_timing_configure_ports --file ./SDC/disable_configure_ports.sdc
# Write the SDC to run timing analysis for a mapped FPGA fabric
write_analysis_sdc --file ./SDC_analysis
# Finish and exit OpenFPGA
exit
# Note :
# To run verification at the end of the flow maintain source in ./SRC directory

View File

@ -175,6 +175,10 @@ echo -e "Testing tiles with I/O in center grid";
run-task basic_tests/tile_organization/tileable_io $@
echo -e "Testing tiles with I/O consisting of subtiles";
run-task basic_tests/tile_organization/io_subtile $@
echo -e "Testing tile grouping on a homogeneous FPGA fabric (Full testbench)";
run-task basic_tests/tile_organization/homo_fabric_tile $@
echo -e "Testing tile grouping on a homogeneous FPGA fabric (Preconfigured testbench)";
run-task basic_tests/tile_organization/homo_fabric_tile_preconfig $@
echo -e "Testing global port definition from tiles";
run-task basic_tests/global_tile_ports/global_tile_clock $@

View File

@ -48,6 +48,8 @@
`include "routing/cby_0__1_.v"
`include "routing/cby_1__1_.v"
// ------ Include tile module netlists -----
// ------ Include fabric top-level netlists -----
`include "fpga_top.v"

View File

@ -55,6 +55,8 @@
`include "routing/cby_1__1_.v"
`include "routing/cby_4__1_.v"
// ------ Include tile module netlists -----
// ------ Include fabric top-level netlists -----
`include "fpga_top.v"

View File

@ -58,6 +58,8 @@
`include "routing/cby_1__1_.v"
`include "routing/cby_2__1_.v"
// ------ Include tile module netlists -----
// ------ Include fabric top-level netlists -----
`include "fpga_top.v"

View File

@ -0,0 +1,35 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# 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/group_tile_full_testbench_example_script.openfpga
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_cc_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
openfpga_group_tile_config_file=${PATH:TASK_DIR}/config/tile_config.xml
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_TileOrgzTl_40nm.xml
[BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/or2/or2.v
[SYNTHESIS_PARAM]
bench_read_verilog_options_common = -nolatches
bench0_top = or2
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
end_flow_with_test=

View File

@ -0,0 +1 @@
<tiles style="top_left"/>

View File

@ -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/group_tile_preconfig_testbench_example_script.openfpga
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_cc_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
openfpga_group_tile_config_file=${PATH:TASK_DIR}/config/tile_config.xml
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_TileOrgzTl_40nm.xml
[BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/or2/or2.v
[SYNTHESIS_PARAM]
bench_read_verilog_options_common = -nolatches
bench0_top = or2
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
end_flow_with_test=
vpr_fpga_verilog_formal_verification_top_netlist=

View File

@ -0,0 +1 @@
<tiles style="top_left"/>