Merge pull request #1265 from lnis-uofu/xt_fabric_tile
Support tile module when building CCFF-based FPGA fabric
This commit is contained in:
commit
c011641fa0
Binary file not shown.
After Width: | Height: | Size: 99 KiB |
|
@ -37,3 +37,5 @@ OpenFPGA widely uses XML format for interchangable files
|
|||
clock_network
|
||||
|
||||
io_naming_file
|
||||
|
||||
tile_config_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 |
|
@ -3,6 +3,8 @@
|
|||
FPGA-Verilog
|
||||
------------
|
||||
|
||||
.. _cmd_write_fabric_verilog:
|
||||
|
||||
write_fabric_verilog
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -9,3 +9,4 @@ add_subdirectory(libfpgabitstream)
|
|||
add_subdirectory(libpcf)
|
||||
add_subdirectory(libbusgroup)
|
||||
add_subdirectory(libionamemap)
|
||||
add_subdirectory(libtileconfig)
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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/";
|
||||
|
|
|
@ -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)
|
|
@ -0,0 +1 @@
|
|||
<tiles style="top_left"/>
|
|
@ -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 */
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -42,6 +42,7 @@ target_link_libraries(libopenfpga
|
|||
libvtrutil
|
||||
libbusgroup
|
||||
libionamemap
|
||||
libtileconfig
|
||||
libpugixml
|
||||
libvpr)
|
||||
|
||||
|
|
|
@ -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*/
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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*/
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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() =
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
*********************************************************************/
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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 "
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
@ -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
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
@ -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
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 -----"));
|
||||
|
|
|
@ -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 */
|
|
@ -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
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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 $@
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
|
@ -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=
|
|
@ -0,0 +1 @@
|
|||
<tiles style="top_left"/>
|
|
@ -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=
|
|
@ -0,0 +1 @@
|
|||
<tiles style="top_left"/>
|
Loading…
Reference in New Issue