Merge pull request #1236 from lnis-uofu/xt_io_naming
fpga_core wrapper now supports custom I/O names
This commit is contained in:
commit
a6e2366cc9
Binary file not shown.
After Width: | Height: | Size: 69 KiB |
|
@ -35,3 +35,5 @@ OpenFPGA widely uses XML format for interchangable files
|
|||
pin_table_file
|
||||
|
||||
clock_network
|
||||
|
||||
io_naming_file
|
||||
|
|
|
@ -0,0 +1,98 @@
|
|||
.. _file_formats_io_naming_file:
|
||||
|
||||
Fabric I/O Naming (.xml)
|
||||
------------------------
|
||||
|
||||
The XML-based description language is used to describe
|
||||
|
||||
- I/O names for an FPGA fabric when creating a top-level wrapper
|
||||
- I/O connections between the fabric and top-level wrappers
|
||||
|
||||
Using the description language, users can customize the I/O names for each pin/port of an FPGA fabric, including dummy pins (not from an FPGA fabric but required for system integration).
|
||||
|
||||
Under the root node ``<ports>``, naming rules can be defined line-by-line through syntax ``<port>``.
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<ports>
|
||||
<port top_name="<string>" core_name="<string>" is_dummy="<bool>" direction="<string>"/>
|
||||
</ports>
|
||||
|
||||
.. note:: If you do not need to rename a port of an FPGA fabric, there is no need to define it explicitly in the naming rules. OpenFPGA can infer it.
|
||||
|
||||
Please be aware of the following restrictions:
|
||||
|
||||
.. note:: Please note that when naming rules should be applied to a port at its full size. For example, given a port of ``in[0:31]``, naming rules should cover all the 32 bits.
|
||||
|
||||
.. note:: Please note that we currently only supports port splitting at the top-level wrapper. For example, there is a port ``a[0:9]`` from the FPGA fabric, it can be split to ``a0[0:4]`` and ``a1[0:4]`` at the top-level wrapper.
|
||||
|
||||
.. warning:: Port grouping is **NOT** supported yet. For example, there are ports ``b[0:7]`` and ``c[0:7]`` from the FPGA fabric, it can **NOT** be grouped to a port ``bnc[0:15]`` at the top-level wrapper.
|
||||
|
||||
Syntax
|
||||
``````
|
||||
|
||||
Detailed syntax are presented as follows.
|
||||
|
||||
.. option:: top_name="<string>"
|
||||
|
||||
Define the port name and width which will appear in the top-level wrapper. For example,
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
top_name="a[0:2]"
|
||||
|
||||
.. option:: core_name="<string>"
|
||||
|
||||
Define the port name and width which exists in the current FPGA fabric. For example,
|
||||
|
||||
.. note:: You can find the available ports in the current top-level module of FPGA netlists. See details in :ref:`fabric_netlists`.
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
core_name="gfpga_pad_GPIO_PAD[0:2]"
|
||||
|
||||
.. option:: is_dummy="<bool>"
|
||||
|
||||
Define if the port is a dummy one in the top-level wrapper, which does not connect to any pin/port of the current FPGA fabric. For example,
|
||||
|
||||
.. note:: When a dummy port is defined. ``core_name`` is not required.
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
is_dummy="true"
|
||||
|
||||
.. option:: direction="<string>"
|
||||
|
||||
Direction can be ``input`` | ``output`` | ``inout``. Only applicable to dummy ports. For example,
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
direction="input"
|
||||
|
||||
Example
|
||||
```````
|
||||
|
||||
:numref:`fig_fpga_core_wrapper` shows an example of a top-level wrapper with naming rules, which is built on top of an existing FPGA core fabric.
|
||||
There is a dummy input port at the top-level wrapper.
|
||||
|
||||
.. _fig_fpga_core_wrapper:
|
||||
|
||||
.. figure:: figures/fpga_core_wrapper.png
|
||||
:width: 100%
|
||||
:alt: Illustration of a top-level wrapper on an existing FPGA core fabric
|
||||
|
||||
Example of a top-level wrapper: how it interfaces between SoC and an existing FPGA core fabric
|
||||
|
||||
The I/O naming in the :numref:`fig_fpga_core_wrapper` can be described in the following XML:
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<ports>
|
||||
<port top_name="pclk0[0:3]" core_name="prog_clk[0:3]"/>
|
||||
<port top_name="pclk1[0:3]" core_name="prog_clk[4:7]"/>
|
||||
<port top_name="right_io[0:23]" core_name="pad[0:23]"/>
|
||||
<port top_name="bottom_io[0:7]" core_name="pad[24:31]"/>
|
||||
<port top_name="pvt_sense[0:0]" is_dummy="true" direction="input"/>
|
||||
</ports>
|
||||
|
||||
Note that since port ``reset[0:0]`` require no name changes, it is not required to be defined in the XML.
|
|
@ -49,6 +49,10 @@ write_full_testbench
|
|||
|
||||
The output directory for all the testbench netlists. We suggest the use of same output directory as fabric Verilog netlists. For example, ``--file /temp/testbench``
|
||||
|
||||
.. option:: --dut_module <string>
|
||||
|
||||
Specify the name of *Design Under Test* (DUT) module to be considered in the testbench. Can be either ``fpga_top`` or ``fpga_core. By default, it is ``fpga_top``.
|
||||
|
||||
.. option:: --bitstream <string>
|
||||
|
||||
The bitstream file to be loaded to the full testbench, which should be in the same file format that OpenFPGA can outputs (See detailes in :ref:`file_formats_fabric_bitstream_plain_text`). For example, ``--bitstream and2.bit``
|
||||
|
@ -120,6 +124,10 @@ write_preconfigured_fabric_wrapper
|
|||
|
||||
Specify the fabric Verilog file if they are not in the same directory as the testbenches to be generated. If not specified, OpenFPGA will assume that the fabric netlists are the in the same directory as testbenches and assign default names. For example, ``--file /temp/fabric/fabric_netlists.v``
|
||||
|
||||
.. option:: --dut_module <string>
|
||||
|
||||
Specify the name of *Design Under Test* (DUT) module to be considered in the testbench. Can be either ``fpga_top`` or ``fpga_core. By default, it is ``fpga_top``.
|
||||
|
||||
.. option:: --pin_constraints_file <string> or -pcf <string>
|
||||
|
||||
Specify the *Pin Constraints File* (PCF) if you want to custom stimulus in testbenches. For example, ``-pin_constraints_file pin_constraints.xml``
|
||||
|
@ -175,6 +183,10 @@ write_mock_fpga_wrapper
|
|||
|
||||
The output directory for the netlists. We suggest the use of same output directory as fabric Verilog netlists. For example, ``--file /temp/testbench``
|
||||
|
||||
.. option:: --top_module <string>
|
||||
|
||||
Specify the name of top-level module to be considered in the wrapper. Can be either ``fpga_top`` or ``fpga_core. By default, it is ``fpga_top``.
|
||||
|
||||
.. option:: --pin_constraints_file <string> or -pcf <string>
|
||||
|
||||
Specify the *Pin Constraints File* (PCF) if you want to custom stimulus in testbenches. For example, ``-pin_constraints_file pin_constraints.xml``
|
||||
|
|
|
@ -288,11 +288,14 @@ add_fpga_core_to_fabric
|
|||
|
||||
Add a wrapper module ``fpga_core`` as an intermediate layer to FPGA fabric. After this command, the existing module ``fpga_top`` will remain the top-level module while there is a new module ``fpga_core`` under it. Under fpga_core, there will be the detailed building blocks.
|
||||
|
||||
.. option:: --io_naming <string>
|
||||
|
||||
This is optional. Specify the I/O naming rules when connecting I/Os of ``fpga_core`` module to the top-level module ``fpga_top``. If not defined, the ``fpga_top`` will be the same as ``fpga_core`` w.r.t. ports. See details about the file format of I/O naming rules in :ref:`file_formats_io_naming_file`.
|
||||
|
||||
.. option:: --instance_name <string>
|
||||
|
||||
This is optional. Specify the instance name to be used when instanciate the ``fpga_core`` module under the top-level module ``fpga_top``. If not defined, by default it is ``fpga_core_inst``.
|
||||
|
||||
|
||||
.. option:: --frame_view
|
||||
|
||||
Create only frame views of the module graph. When enabled, top-level module will not include any nets. This option is made for save runtime and memory.
|
||||
|
|
|
@ -8,3 +8,4 @@ add_subdirectory(libfabrickey)
|
|||
add_subdirectory(libfpgabitstream)
|
||||
add_subdirectory(libpcf)
|
||||
add_subdirectory(libbusgroup)
|
||||
add_subdirectory(libionamemap)
|
||||
|
|
|
@ -19,15 +19,23 @@ namespace openfpga {
|
|||
* Return a vector of the block ids, where the top-level block
|
||||
* locates in the head, while the leaf block locates in the tail
|
||||
* top, next, ... , block
|
||||
* Optionally, the top block name in the path can be specified. Useful to trim
|
||||
*the hierarchy with a given range
|
||||
*******************************************************************/
|
||||
std::vector<ConfigBlockId> find_bitstream_manager_block_hierarchy(
|
||||
const BitstreamManager& bitstream_manager, const ConfigBlockId& block) {
|
||||
const BitstreamManager& bitstream_manager, const ConfigBlockId& block,
|
||||
const std::string& top_block_name) {
|
||||
std::vector<ConfigBlockId> block_hierarchy;
|
||||
ConfigBlockId temp_block = block;
|
||||
|
||||
/* Generate a tree of parent block */
|
||||
while (true == bitstream_manager.valid_block_id(temp_block)) {
|
||||
block_hierarchy.push_back(temp_block);
|
||||
/* Check if we have reached the designated top block */
|
||||
if (!top_block_name.empty() &&
|
||||
bitstream_manager.block_name(temp_block) == top_block_name) {
|
||||
break;
|
||||
}
|
||||
/* Go to upper level */
|
||||
temp_block = bitstream_manager.block_parent(temp_block);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,8 @@
|
|||
namespace openfpga {
|
||||
|
||||
std::vector<ConfigBlockId> find_bitstream_manager_block_hierarchy(
|
||||
const BitstreamManager& bitstream_manager, const ConfigBlockId& block);
|
||||
const BitstreamManager& bitstream_manager, const ConfigBlockId& block,
|
||||
const std::string& top_block_name = "");
|
||||
|
||||
std::vector<ConfigBlockId> find_bitstream_manager_top_blocks(
|
||||
const BitstreamManager& bitstream_manager);
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
cmake_minimum_required(VERSION 3.9)
|
||||
|
||||
project("libionamemap")
|
||||
|
||||
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(libionamemap STATIC
|
||||
${LIB_HEADERS}
|
||||
${LIB_SOURCES})
|
||||
target_include_directories(libionamemap PUBLIC ${LIB_INCLUDE_DIRS})
|
||||
set_target_properties(libionamemap PROPERTIES PREFIX "") #Avoid extra 'lib' prefix
|
||||
|
||||
#Specify link-time dependancies
|
||||
target_link_libraries(libionamemap
|
||||
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} libionamemap)
|
||||
endforeach(testsourcefile ${EXEC_SOURCES})
|
||||
|
||||
install(TARGETS libionamemap DESTINATION bin)
|
|
@ -0,0 +1,8 @@
|
|||
<ports>
|
||||
<port core_name="prog_clock[0]" top_name="prog_clk0"/>
|
||||
<port core_name="prog_clock[1]" top_name="prog_clk1"/>
|
||||
<port core_name="gfpga_io_pad[0:31]" top_name="top_io[0:31]"/>
|
||||
<port core_name="gfpga_io_pad[32:47]" top_name="right_io[32:47]"/>
|
||||
<port core_name="gfpga_io_pad[48:55]" top_name="bottom_io[48:55]"/>
|
||||
<port top_name="pvt_sense" is_dummy="true" direction="input"/>
|
||||
</ports>
|
|
@ -0,0 +1,348 @@
|
|||
/******************************************************************************
|
||||
* Memember functions for data structure IoLocationMap
|
||||
******************************************************************************/
|
||||
/* Headers from vtrutil library */
|
||||
#include "io_name_map.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "command_exit_codes.h"
|
||||
#include "openfpga_port_parser.h"
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
#include "vtr_time.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
IoNameMap::IoNameMap() {
|
||||
DUMMY_PORT_DIR_STRING_ = {"input", "output", "inout"};
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
* Public Accessors
|
||||
*************************************************/
|
||||
std::vector<BasicPort> IoNameMap::fpga_top_ports() const {
|
||||
std::vector<BasicPort> ports;
|
||||
|
||||
for (auto it = top2core_io_name_map_.begin();
|
||||
it != top2core_io_name_map_.end(); ++it) {
|
||||
ports.push_back(str2port(it->first));
|
||||
}
|
||||
|
||||
return ports;
|
||||
}
|
||||
|
||||
BasicPort IoNameMap::fpga_core_port(const BasicPort& fpga_top_port) const {
|
||||
BasicPort core_port;
|
||||
/* First, find the pin name matching */
|
||||
auto result_key = top2core_io_name_keys_.find(fpga_top_port.get_name());
|
||||
if (result_key == top2core_io_name_keys_.end()) {
|
||||
return core_port; /* Not found, return invalid port */
|
||||
}
|
||||
/* Second, find the exact key */
|
||||
std::string top_port_key;
|
||||
for (std::string cand : result_key->second) {
|
||||
BasicPort cand_port = str2port(cand);
|
||||
/* if the top port is part of the cand port, e.g., clk[1] vs. clk[0:2], the
|
||||
* candidate is the key that we want! */
|
||||
if (cand_port.contained(fpga_top_port)) {
|
||||
top_port_key = cand;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (top_port_key.empty()) {
|
||||
return core_port; /* Not found, return invalid port */
|
||||
}
|
||||
auto result = top2core_io_name_map_.find(top_port_key);
|
||||
if (result != top2core_io_name_map_.end() && result->second.is_valid()) {
|
||||
BasicPort top_port_pool = str2port(top_port_key);
|
||||
BasicPort fpga_top_port_lsb(fpga_top_port.get_name(),
|
||||
fpga_top_port.get_lsb(),
|
||||
fpga_top_port.get_lsb());
|
||||
BasicPort fpga_top_port_msb(fpga_top_port.get_name(),
|
||||
fpga_top_port.get_msb(),
|
||||
fpga_top_port.get_msb());
|
||||
size_t ipin_anchor_lsb = top_port_pool.find_ipin(fpga_top_port_lsb);
|
||||
size_t ipin_anchor_msb = top_port_pool.find_ipin(fpga_top_port_msb);
|
||||
/* Now find the exact pin and spot the core port with pin index */
|
||||
if (ipin_anchor_lsb < top_port_pool.get_width() &&
|
||||
ipin_anchor_msb < top_port_pool.get_width()) {
|
||||
core_port.set_name(result->second.get_name());
|
||||
core_port.set_lsb(result->second.pins()[ipin_anchor_lsb]);
|
||||
core_port.set_msb(result->second.pins()[ipin_anchor_msb]);
|
||||
}
|
||||
}
|
||||
return core_port;
|
||||
}
|
||||
|
||||
BasicPort IoNameMap::fpga_top_port(const BasicPort& fpga_core_port) const {
|
||||
BasicPort top_port;
|
||||
/* First, find the pin name matching */
|
||||
auto result_key = core2top_io_name_keys_.find(fpga_core_port.get_name());
|
||||
if (result_key == core2top_io_name_keys_.end()) {
|
||||
return top_port; /* Not found, return invalid port */
|
||||
}
|
||||
/* Second, find the exact key */
|
||||
std::string core_port_key;
|
||||
for (std::string cand : result_key->second) {
|
||||
BasicPort cand_port = str2port(cand);
|
||||
/* if the top port is part of the cand port, e.g., clk[1] vs. clk[0:2], the
|
||||
* candidate is the key that we want! */
|
||||
if (cand_port.contained(fpga_core_port)) {
|
||||
core_port_key = cand;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (core_port_key.empty()) {
|
||||
return top_port; /* Not found, return invalid port */
|
||||
}
|
||||
auto result = core2top_io_name_map_.find(core_port_key);
|
||||
if (result != core2top_io_name_map_.end() && result->second.is_valid()) {
|
||||
BasicPort core_port_pool = str2port(core_port_key);
|
||||
BasicPort fpga_core_port_lsb(fpga_core_port.get_name(),
|
||||
fpga_core_port.get_lsb(),
|
||||
fpga_core_port.get_lsb());
|
||||
BasicPort fpga_core_port_msb(fpga_core_port.get_name(),
|
||||
fpga_core_port.get_msb(),
|
||||
fpga_core_port.get_msb());
|
||||
size_t ipin_anchor_lsb = core_port_pool.find_ipin(fpga_core_port);
|
||||
size_t ipin_anchor_msb = core_port_pool.find_ipin(fpga_core_port);
|
||||
/* Now find the exact pin and spot the core port with pin index */
|
||||
if (ipin_anchor_lsb < core_port_pool.get_width() &&
|
||||
ipin_anchor_msb < core_port_pool.get_width()) {
|
||||
top_port.set_name(result->second.get_name());
|
||||
top_port.set_lsb(result->second.pins()[ipin_anchor_lsb]);
|
||||
top_port.set_msb(result->second.pins()[ipin_anchor_msb]);
|
||||
}
|
||||
}
|
||||
return top_port;
|
||||
}
|
||||
|
||||
IoNameMap::e_port_mapping_status IoNameMap::fpga_core_port_mapping_status(
|
||||
const BasicPort& fpga_core_port, const bool& verbose) const {
|
||||
/* First, find the pin name matching */
|
||||
auto result_key = core2top_io_name_keys_.find(fpga_core_port.get_name());
|
||||
if (result_key == core2top_io_name_keys_.end()) {
|
||||
return IoNameMap::e_port_mapping_status::NONE;
|
||||
}
|
||||
/* Second, find the exact port. Create a scoreboard and check every pin.
|
||||
* Expect only one hit per pin. Error on any pin which has been hit twice
|
||||
* (indicate overlapped ports). Error on any pin which has no hit (indicate
|
||||
* partially unmapped) */
|
||||
std::vector<int8_t> scoreboard(fpga_core_port.get_width(), 0);
|
||||
for (std::string cand : result_key->second) {
|
||||
BasicPort cand_port = str2port(cand);
|
||||
for (auto pin : cand_port.pins()) {
|
||||
scoreboard[pin - fpga_core_port.get_lsb()]++;
|
||||
}
|
||||
}
|
||||
for (int8_t bit : scoreboard) {
|
||||
if (bit == 0) {
|
||||
VTR_LOGV_ERROR(verbose,
|
||||
"Unmapped pin '%lu' of fpga_core port '%s'! Partially "
|
||||
"mapping is not allowed\n",
|
||||
fpga_core_port.pins()[bit + fpga_core_port.get_lsb()],
|
||||
fpga_core_port.to_verilog_string().c_str());
|
||||
return IoNameMap::e_port_mapping_status::PARTIAL;
|
||||
}
|
||||
if (bit > 1) {
|
||||
VTR_LOGV_ERROR(verbose,
|
||||
"Overlapped %d times on pin '%lu' of fpga_core port '%s' "
|
||||
"when mapping!\n",
|
||||
bit, fpga_core_port.pins()[bit + fpga_core_port.get_lsb()],
|
||||
fpga_core_port.to_verilog_string().c_str());
|
||||
return IoNameMap::e_port_mapping_status::OVERLAPPED;
|
||||
}
|
||||
}
|
||||
return IoNameMap::e_port_mapping_status::FULL;
|
||||
}
|
||||
|
||||
bool IoNameMap::fpga_top_port_is_dummy(const BasicPort& fpga_top_port) const {
|
||||
return !fpga_core_port(fpga_top_port).is_valid();
|
||||
}
|
||||
|
||||
IoNameMap::e_dummy_port_direction IoNameMap::fpga_top_dummy_port_direction(
|
||||
const BasicPort& fpga_top_port) const {
|
||||
for (auto& kv : dummy_port_direction_) {
|
||||
BasicPort cand = str2port(kv.first);
|
||||
if (cand.contained(fpga_top_port)) {
|
||||
return kv.second;
|
||||
}
|
||||
}
|
||||
/* Return an invalid port type */
|
||||
return IoNameMap::e_dummy_port_direction::NUM_TYPES;
|
||||
}
|
||||
|
||||
bool IoNameMap::empty() const {
|
||||
return top2core_io_name_keys_.empty() && top2core_io_name_map_.empty() &&
|
||||
core2top_io_name_keys_.empty() && core2top_io_name_map_.empty() &&
|
||||
dummy_port_direction_.empty();
|
||||
}
|
||||
|
||||
int IoNameMap::set_io_pair(const BasicPort& fpga_top_port,
|
||||
const BasicPort& fpga_core_port) {
|
||||
/* Ensure the two ports are matching in size */
|
||||
if (fpga_top_port.get_width() != fpga_core_port.get_width()) {
|
||||
VTR_LOG_ERROR(
|
||||
"Unable to pair two ports 'fpga_top.%s[%lu:%lu]' and "
|
||||
"'fpga_core.%s[%lu:%lu]' which are in the same size!\n",
|
||||
fpga_top_port.get_name().c_str(), fpga_top_port.get_lsb(),
|
||||
fpga_top_port.get_msb(), fpga_core_port.get_name().c_str(),
|
||||
fpga_core_port.get_lsb(), fpga_core_port.get_msb());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
VTR_ASSERT_SAFE(fpga_top_port.get_width() != fpga_core_port.get_width());
|
||||
/* Register in the key first, and then add to the exact name mapping */
|
||||
{
|
||||
std::string top_port_str = port2str(fpga_top_port);
|
||||
auto result_key = top2core_io_name_keys_.find(fpga_top_port.get_name());
|
||||
if (result_key == top2core_io_name_keys_.end()) {
|
||||
/* Add to the key registery */
|
||||
top2core_io_name_keys_[fpga_top_port.get_name()].push_back(top_port_str);
|
||||
top2core_io_name_map_[top_port_str] = fpga_core_port;
|
||||
} else {
|
||||
/* Ensure that the key is not duplicated */
|
||||
if (std::find(result_key->second.begin(), result_key->second.end(),
|
||||
top_port_str) == result_key->second.end()) {
|
||||
top2core_io_name_keys_[fpga_top_port.get_name()].push_back(
|
||||
top_port_str);
|
||||
top2core_io_name_map_[top_port_str] = fpga_core_port;
|
||||
} else {
|
||||
/* Throw a warning since we have to overwrite */
|
||||
VTR_LOG_WARN(
|
||||
"Overwrite the top-to-core pin mapping: top pin '%s' to core pin "
|
||||
"'%s' (previously was '%s')!\n",
|
||||
top_port_str.c_str(), port2str(fpga_core_port).c_str(),
|
||||
port2str(top2core_io_name_map_[top_port_str]).c_str());
|
||||
top2core_io_name_map_[top_port_str] = fpga_core_port;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Now, do similar to the core port */
|
||||
{
|
||||
std::string core_port_str = port2str(fpga_core_port);
|
||||
auto result_key = core2top_io_name_keys_.find(fpga_core_port.get_name());
|
||||
if (result_key == core2top_io_name_keys_.end()) {
|
||||
/* Add to the key registery */
|
||||
core2top_io_name_keys_[fpga_core_port.get_name()].push_back(
|
||||
core_port_str);
|
||||
core2top_io_name_map_[core_port_str] = fpga_top_port;
|
||||
} else {
|
||||
/* Ensure that the key is not duplicated */
|
||||
if (std::find(result_key->second.begin(), result_key->second.end(),
|
||||
core_port_str) == result_key->second.end()) {
|
||||
core2top_io_name_keys_[fpga_core_port.get_name()].push_back(
|
||||
core_port_str);
|
||||
core2top_io_name_map_[core_port_str] = fpga_top_port;
|
||||
} else {
|
||||
/* Throw a warning since we have to overwrite */
|
||||
VTR_LOG_WARN(
|
||||
"Overwrite the core-to-top pin mapping: core pin '%s' to top pin "
|
||||
"'%s' (previously was '%s')!\n",
|
||||
core_port_str.c_str(), port2str(fpga_top_port).c_str(),
|
||||
port2str(core2top_io_name_map_[core_port_str]).c_str());
|
||||
core2top_io_name_map_[core_port_str] = fpga_top_port;
|
||||
}
|
||||
}
|
||||
}
|
||||
return CMD_EXEC_SUCCESS;
|
||||
}
|
||||
|
||||
int IoNameMap::set_dummy_io(const BasicPort& fpga_top_port,
|
||||
const e_dummy_port_direction& direction) {
|
||||
/* Must be a true dummy port, none of its pins have been paired! */
|
||||
std::string top_port_str = port2str(fpga_top_port);
|
||||
/* First, find the pin name matching */
|
||||
auto result_key = top2core_io_name_keys_.find(fpga_top_port.get_name());
|
||||
if (result_key == top2core_io_name_keys_.end()) {
|
||||
/* Add to the key registery */
|
||||
top2core_io_name_keys_[fpga_top_port.get_name()].push_back(top_port_str);
|
||||
top2core_io_name_map_[top_port_str] = BasicPort();
|
||||
} else {
|
||||
/* Ensure that the key is not duplicated */
|
||||
if (std::find(result_key->second.begin(), result_key->second.end(),
|
||||
top_port_str) == result_key->second.end()) {
|
||||
top2core_io_name_keys_[fpga_top_port.get_name()].push_back(top_port_str);
|
||||
top2core_io_name_map_[top_port_str] = BasicPort();
|
||||
} else {
|
||||
/* Throw a error because the dummy pin should NOT be mapped before! */
|
||||
VTR_LOG_ERROR(
|
||||
"Dummy port '%s' of fpga_top is already mapped "
|
||||
"to a valid pin '%s' of fpga_core!\n",
|
||||
port2str(fpga_top_port).c_str(),
|
||||
port2str(top2core_io_name_map_[top_port_str]).c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
/* Add the direction list */
|
||||
bool dir_defined = false;
|
||||
for (auto& kv : dummy_port_direction_) {
|
||||
BasicPort cand = str2port(kv.first);
|
||||
if (cand.contained(fpga_top_port)) {
|
||||
if (kv.second != direction) {
|
||||
/* Throw a error because the dummy pin should NOT be mapped before! */
|
||||
VTR_LOG_ERROR(
|
||||
"Dummy port '%s' of fpga_top is already assigned to a different "
|
||||
"direction through another dummy port definition '%s'!\n",
|
||||
port2str(fpga_top_port).c_str(), port2str(cand).c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
dir_defined = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!dir_defined) {
|
||||
dummy_port_direction_[top_port_str] = direction;
|
||||
}
|
||||
return CMD_EXEC_SUCCESS;
|
||||
}
|
||||
|
||||
std::string IoNameMap::port2str(const BasicPort& port) const {
|
||||
return port.to_verilog_string();
|
||||
}
|
||||
|
||||
BasicPort IoNameMap::str2port(const std::string& port_str) const {
|
||||
return PortParser(port_str).port();
|
||||
}
|
||||
|
||||
std::string IoNameMap::dummy_port_dir_all2str() const {
|
||||
std::string full_types = "[";
|
||||
for (int itype = size_t(IoNameMap::e_dummy_port_direction::INPUT);
|
||||
itype != size_t(IoNameMap::e_dummy_port_direction::NUM_TYPES); ++itype) {
|
||||
full_types += std::string(DUMMY_PORT_DIR_STRING_[itype]) + std::string("|");
|
||||
}
|
||||
full_types.pop_back();
|
||||
full_types += "]";
|
||||
return full_types;
|
||||
}
|
||||
|
||||
IoNameMap::e_dummy_port_direction IoNameMap::str2dummy_port_dir(
|
||||
const std::string& dir_str, const bool& verbose) const {
|
||||
for (int itype = size_t(IoNameMap::e_dummy_port_direction::INPUT);
|
||||
itype != size_t(IoNameMap::e_dummy_port_direction::NUM_TYPES); ++itype) {
|
||||
if (dir_str == std::string(DUMMY_PORT_DIR_STRING_[itype])) {
|
||||
return static_cast<IoNameMap::e_dummy_port_direction>(itype);
|
||||
}
|
||||
}
|
||||
VTR_LOGV_ERROR(verbose, "Invalid direction for dummy port! Expect %s\n",
|
||||
dummy_port_dir_all2str().c_str());
|
||||
return IoNameMap::e_dummy_port_direction::NUM_TYPES;
|
||||
}
|
||||
|
||||
std::string IoNameMap::dummy_port_dir2str(const e_dummy_port_direction& dir,
|
||||
const bool& verbose) const {
|
||||
if (!valid_dummy_port_direction(dir)) {
|
||||
VTR_LOGV_ERROR(verbose, "Invalid direction for dummy port! Expect %s\n",
|
||||
dummy_port_dir_all2str().c_str());
|
||||
return std::string();
|
||||
}
|
||||
return std::string(DUMMY_PORT_DIR_STRING_[size_t(dir)]);
|
||||
}
|
||||
|
||||
bool IoNameMap::valid_dummy_port_direction(
|
||||
const IoNameMap::e_dummy_port_direction& direction) const {
|
||||
return direction != IoNameMap::e_dummy_port_direction::NUM_TYPES;
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,111 @@
|
|||
#ifndef IO_NAME_MAP_H
|
||||
#define IO_NAME_MAP_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files required by the data structure definition
|
||||
*******************************************************************/
|
||||
#include <map>
|
||||
|
||||
#include "openfpga_port.h"
|
||||
|
||||
/* Begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/**
|
||||
* @brief I/O name map is a data structure to show mapping between the ports
|
||||
* of fpga_top and fpga_core, which are the two possible top-level modules that
|
||||
* modeling a complete FPGA fabric Using the data structure, developers can find
|
||||
* - the corresponding port of fpga_core, with a given port of fpga_top
|
||||
* - the corresponding port of fpga_top, with a given port of fpga_core
|
||||
*/
|
||||
class IoNameMap {
|
||||
public: /* Types */
|
||||
enum class e_dummy_port_direction { INPUT = 0, OUTPUT, INOUT, NUM_TYPES };
|
||||
enum class e_port_mapping_status {
|
||||
NONE = 0,
|
||||
PARTIAL,
|
||||
FULL,
|
||||
OVERLAPPED,
|
||||
NUM_TYPES
|
||||
};
|
||||
|
||||
public: /* Constructors */
|
||||
IoNameMap();
|
||||
|
||||
public: /* Public accessors */
|
||||
/** @brief Get all the fpga top ports */
|
||||
std::vector<BasicPort> fpga_top_ports() const;
|
||||
/** @brief With a given port at fpga_top, find the corresponding I/O at
|
||||
* fpga_core. Return an invalid port if not found */
|
||||
BasicPort fpga_core_port(const BasicPort& fpga_top_port) const;
|
||||
/** @brief With a given port at fpga_core, find the corresponding I/O at
|
||||
* fpga_top. Return an invalid port if not found */
|
||||
BasicPort fpga_top_port(const BasicPort& fpga_core_port) const;
|
||||
/** @brief Identify if the fpga_top port is dummy or not */
|
||||
bool fpga_top_port_is_dummy(const BasicPort& fpga_top_port) const;
|
||||
/** @brief Get the direction of a dummy port */
|
||||
e_dummy_port_direction fpga_top_dummy_port_direction(
|
||||
const BasicPort& fpga_top_port) const;
|
||||
/** @brief Check if a core port, by considering its port name only, has been
|
||||
* fully/partially/no mapped to fpga top. For example, there is a core port
|
||||
* 'a[0:3]', while only 'a[0]' is mapped to the fpga top. We can use the port
|
||||
* name find it quickly
|
||||
*/
|
||||
e_port_mapping_status fpga_core_port_mapping_status(
|
||||
const BasicPort& fpga_core_port, const bool& verbose = false) const;
|
||||
/** @brief Identify if there are any naming rules inside */
|
||||
bool empty() 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_io_pair(const BasicPort& fpga_top_port,
|
||||
const BasicPort& fpga_core_port);
|
||||
/** @brief Add a dummy port at the fpga top, which is not mapped any port at
|
||||
* fpga_core */
|
||||
int set_dummy_io(const BasicPort& fpga_top_port,
|
||||
const e_dummy_port_direction& direction);
|
||||
|
||||
public: /* Public utility */
|
||||
/** @brief Parse the dummy port direction from string to valid type. Parser
|
||||
* error can be turned on */
|
||||
e_dummy_port_direction str2dummy_port_dir(const std::string& dir_str,
|
||||
const bool& verbose = false) const;
|
||||
/** @brief Output the string representing dummy port direction */
|
||||
std::string dummy_port_dir2str(const e_dummy_port_direction& dir,
|
||||
const bool& verbose = false) const;
|
||||
/** @brief Validate the dummy port direction */
|
||||
bool valid_dummy_port_direction(
|
||||
const e_dummy_port_direction& direction) const;
|
||||
|
||||
private: /* Internal utility */
|
||||
/* Convert a port info to string, which can be used to store keys */
|
||||
std::string port2str(const BasicPort& port) const;
|
||||
/* Convert a string to port, which can be used to echo internal info */
|
||||
BasicPort str2port(const std::string& port_str) const;
|
||||
/* Generate a string include all the valid directions of the dummy port.
|
||||
* Useful for printing debugging messages */
|
||||
std::string dummy_port_dir_all2str() const;
|
||||
|
||||
private: /* Internal Data */
|
||||
/* fpga_top -> fpga_core io_name_keys. Use the port name to find all the port
|
||||
* details. For instance: prog_clk -> ["prog_clk[0:1]", "prog_clk[2:3]"] The
|
||||
* keys are then used to spot the fpga core ports in the io_name_map_. For
|
||||
* instance: "prog_clk[0:1]" -> pclk[0:1]
|
||||
*/
|
||||
std::map<std::string, std::vector<std::string>> top2core_io_name_keys_;
|
||||
std::map<std::string, BasicPort> top2core_io_name_map_;
|
||||
|
||||
std::map<std::string, std::vector<std::string>> core2top_io_name_keys_;
|
||||
std::map<std::string, BasicPort> core2top_io_name_map_;
|
||||
|
||||
std::map<std::string, e_dummy_port_direction> dummy_port_direction_;
|
||||
|
||||
/* Constants */
|
||||
std::array<const char*, size_t(e_dummy_port_direction::NUM_TYPES)>
|
||||
DUMMY_PORT_DIR_STRING_;
|
||||
};
|
||||
|
||||
} /* End namespace openfpga*/
|
||||
|
||||
#endif
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef IO_NAME_MAP_XML_CONSTANTS_H
|
||||
#define IO_NAME_MAP_XML_CONSTANTS_H
|
||||
|
||||
/* Constants required by XML parser */
|
||||
|
||||
constexpr const char* XML_IO_NAME_MAP_ROOT_NAME = "ports";
|
||||
constexpr const char* XML_IO_NAME_MAP_NODE_NAME = "port";
|
||||
constexpr const char* XML_IO_NAME_MAP_ATTRIBUTE_TOP_NAME = "top_name";
|
||||
constexpr const char* XML_IO_NAME_MAP_ATTRIBUTE_CORE_NAME = "core_name";
|
||||
constexpr const char* XML_IO_NAME_MAP_ATTRIBUTE_IS_DUMMY = "is_dummy";
|
||||
constexpr const char* XML_IO_NAME_MAP_ATTRIBUTE_DIRECTION = "direction";
|
||||
|
||||
constexpr std::array<const char*, 3>
|
||||
XML_IO_NAME_MAP_DUMMY_PORT_DIRECTION_STRING = {
|
||||
{"input", "output", "inout"}}; // String versions of side orientations
|
||||
|
||||
#endif
|
|
@ -0,0 +1,104 @@
|
|||
/********************************************************************
|
||||
* 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 libopenfpga util library */
|
||||
#include "openfpga_port_parser.h"
|
||||
|
||||
/* Headers from libarchfpga */
|
||||
#include "arch_error.h"
|
||||
#include "command_exit_codes.h"
|
||||
#include "io_name_map_xml_constants.h"
|
||||
#include "read_xml_io_name_map.h"
|
||||
#include "read_xml_util.h"
|
||||
|
||||
namespace openfpga { // Begin namespace openfpga
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes of a <port> to an object of I/O naming
|
||||
*******************************************************************/
|
||||
static int read_xml_io_map_port(pugi::xml_node& xml_port,
|
||||
const pugiutil::loc_data& loc_data,
|
||||
IoNameMap& io_name_map) {
|
||||
/* Parse fpga top port information */
|
||||
std::string top_name =
|
||||
get_attribute(xml_port, XML_IO_NAME_MAP_ATTRIBUTE_TOP_NAME, loc_data)
|
||||
.as_string();
|
||||
BasicPort top_port = openfpga::PortParser(top_name).port();
|
||||
|
||||
/* For dummy port, create the dummy io */
|
||||
bool is_dummy = get_attribute(xml_port, XML_IO_NAME_MAP_ATTRIBUTE_IS_DUMMY,
|
||||
loc_data, pugiutil::ReqOpt::OPTIONAL)
|
||||
.as_bool(false);
|
||||
if (is_dummy) {
|
||||
std::string dir_str =
|
||||
get_attribute(xml_port, XML_IO_NAME_MAP_ATTRIBUTE_DIRECTION, loc_data)
|
||||
.as_string();
|
||||
IoNameMap::e_dummy_port_direction dummy_port_dir =
|
||||
io_name_map.str2dummy_port_dir(dir_str, true);
|
||||
if (!io_name_map.valid_dummy_port_direction(dummy_port_dir)) {
|
||||
VTR_LOG_ERROR("Invalid direction for dummy port '%s'!\n",
|
||||
top_port.to_verilog_string().c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
return io_name_map.set_dummy_io(top_port,
|
||||
dummy_port_dir); /* Early return */
|
||||
}
|
||||
|
||||
/* This is not a dummy io, create the io mapping */
|
||||
std::string core_name =
|
||||
get_attribute(xml_port, XML_IO_NAME_MAP_ATTRIBUTE_CORE_NAME, loc_data)
|
||||
.as_string();
|
||||
BasicPort core_port = openfpga::PortParser(core_name).port();
|
||||
|
||||
return io_name_map.set_io_pair(top_port, core_port);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Parse XML codes about <ports> to an object of ClockNetwork
|
||||
*******************************************************************/
|
||||
int read_xml_io_name_map(const char* fname, IoNameMap& io_name_map) {
|
||||
vtr::ScopedStartFinishTimer timer("Read I/O naming 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_IO_NAME_MAP_ROOT_NAME, loc_data);
|
||||
|
||||
for (pugi::xml_node xml_port : xml_root.children()) {
|
||||
/* Error out if the XML child has an invalid name! */
|
||||
if (xml_port.name() != std::string(XML_IO_NAME_MAP_NODE_NAME)) {
|
||||
bad_tag(xml_port, loc_data, xml_root, {XML_IO_NAME_MAP_NODE_NAME});
|
||||
}
|
||||
status = read_xml_io_map_port(xml_port, loc_data, io_name_map);
|
||||
if (status != CMD_EXEC_SUCCESS) {
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
} 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_IO_NAME_MAP_H
|
||||
#define READ_XML_IO_NAME_MAP_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include "io_name_map.h"
|
||||
#include "pugixml.hpp"
|
||||
#include "pugixml_util.hpp"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
namespace openfpga { // Begin namespace openfpga
|
||||
|
||||
int read_xml_io_name_map(const char* fname, IoNameMap& io_name_map);
|
||||
|
||||
} // End of namespace openfpga
|
||||
|
||||
#endif
|
|
@ -0,0 +1,106 @@
|
|||
/********************************************************************
|
||||
* 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 openfpga util library */
|
||||
#include "openfpga_digest.h"
|
||||
|
||||
/* Headers from arch openfpga library */
|
||||
#include "write_xml_utils.h"
|
||||
|
||||
/* Headers from pin constraint library */
|
||||
#include "io_name_map_xml_constants.h"
|
||||
#include "write_xml_io_name_map.h"
|
||||
|
||||
namespace openfpga { // Begin namespace openfpga
|
||||
|
||||
/********************************************************************
|
||||
* A writer to output a I/O name mapping 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
|
||||
*******************************************************************/
|
||||
static int write_xml_io_map_port(std::fstream& fp, const IoNameMap& io_name_map,
|
||||
const BasicPort& fpga_top_port) {
|
||||
/* Validate the file stream */
|
||||
if (false == openfpga::valid_file_stream(fp)) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
openfpga::write_tab_to_file(fp, 1);
|
||||
fp << "<" << XML_IO_NAME_MAP_NODE_NAME << "";
|
||||
write_xml_attribute(fp, XML_IO_NAME_MAP_ATTRIBUTE_TOP_NAME,
|
||||
generate_xml_port_name(fpga_top_port).c_str());
|
||||
|
||||
if (io_name_map.fpga_top_port_is_dummy(fpga_top_port)) {
|
||||
write_xml_attribute(fp, XML_IO_NAME_MAP_ATTRIBUTE_IS_DUMMY, "true");
|
||||
IoNameMap::e_dummy_port_direction dir =
|
||||
io_name_map.fpga_top_dummy_port_direction(fpga_top_port);
|
||||
write_xml_attribute(fp, XML_IO_NAME_MAP_ATTRIBUTE_DIRECTION,
|
||||
io_name_map.dummy_port_dir2str(dir, true).c_str());
|
||||
} else {
|
||||
BasicPort fpga_core_port = io_name_map.fpga_core_port(fpga_top_port);
|
||||
write_xml_attribute(fp, XML_IO_NAME_MAP_ATTRIBUTE_CORE_NAME,
|
||||
generate_xml_port_name(fpga_core_port).c_str());
|
||||
}
|
||||
fp << ">"
|
||||
<< "\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* 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_io_name_map(const char* fname, const IoNameMap& io_name_map) {
|
||||
vtr::ScopedStartFinishTimer timer("Write I/O naming 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);
|
||||
|
||||
/* Write the root node */
|
||||
fp << "<" << XML_IO_NAME_MAP_ROOT_NAME;
|
||||
fp << ">"
|
||||
<< "\n";
|
||||
|
||||
int err_code = 0;
|
||||
|
||||
/* Write each port */
|
||||
for (BasicPort fpga_top_port : io_name_map.fpga_top_ports()) {
|
||||
/* Write bus */
|
||||
err_code = write_xml_io_map_port(fp, io_name_map, fpga_top_port);
|
||||
if (0 != err_code) {
|
||||
return err_code;
|
||||
}
|
||||
}
|
||||
|
||||
/* Finish writing the root node */
|
||||
fp << "</" << XML_IO_NAME_MAP_ROOT_NAME << ">"
|
||||
<< "\n";
|
||||
|
||||
/* Close the file stream */
|
||||
fp.close();
|
||||
|
||||
return err_code;
|
||||
}
|
||||
|
||||
} // End of namespace openfpga
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef WRITE_XML_IO_NAME_MAP_H
|
||||
#define WRITE_XML_IO_NAME_MAP_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include <fstream>
|
||||
|
||||
#include "io_name_map.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
namespace openfpga { // Begin namespace openfpga
|
||||
|
||||
int write_xml_io_name_map(const char* fname, const IoNameMap& io_name_map);
|
||||
|
||||
} // End of namespace openfpga
|
||||
|
||||
#endif
|
|
@ -0,0 +1,38 @@
|
|||
/********************************************************************
|
||||
* 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_io_name_map.h"
|
||||
#include "write_xml_io_name_map.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::IoNameMap io_name_map;
|
||||
status = openfpga::read_xml_io_name_map(argv[1], io_name_map);
|
||||
if (status != 0) {
|
||||
return status;
|
||||
}
|
||||
VTR_LOG("Parsed %lu fpga top ports from XML.\n",
|
||||
io_name_map.fpga_top_ports().size());
|
||||
|
||||
/* 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_io_name_map(argv[2], io_name_map);
|
||||
VTR_LOG("Write the I/O name mapping to an XML file: %s.\n", argv[2]);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
|
@ -111,6 +111,25 @@ std::string BasicPort::to_verilog_string() const {
|
|||
std::to_string(get_msb()) + "]";
|
||||
}
|
||||
|
||||
size_t BasicPort::find_ipin(const BasicPort& ref_port) const {
|
||||
/* Port name should match first */
|
||||
if (!this->mergeable(ref_port)) {
|
||||
return get_width(); /* Name does not match, no need to find the pin index,
|
||||
return an invalid range */
|
||||
}
|
||||
/* it should be only a pin (width = 1) */
|
||||
if (!ref_port.is_valid() || ref_port.get_width() != 1) {
|
||||
return get_width(); /* Return an invalid range */
|
||||
}
|
||||
/* Must cache the pin list otherwise the begin() and end() are not constant */
|
||||
auto pin_list = pins();
|
||||
auto it = std::find(pin_list.begin(), pin_list.end(), ref_port.get_lsb());
|
||||
if (it == pin_list.end()) {
|
||||
return get_width(); /* Out of range, return an invalid range */
|
||||
}
|
||||
return it - pin_list.begin();
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Overloaded operators
|
||||
***********************************************************************/
|
||||
|
|
|
@ -37,6 +37,10 @@ class BasicPort {
|
|||
size_t get_origin_port_width() const;
|
||||
std::string to_verilog_string()
|
||||
const; /* Generate verilog-style string, e.g., a[0:1] */
|
||||
/** @brief Find the index of the pin in the reference port w.r.t. to this
|
||||
* port. For example, given a reference pin 'a[1]', this port is 'a[0:2]', the
|
||||
* pin is the second pin in the port. As a result, the index will be 1. */
|
||||
size_t find_ipin(const BasicPort& ref_port) const;
|
||||
|
||||
public: /* Mutators */
|
||||
void set(const BasicPort& basic_port); /* copy */
|
||||
|
|
|
@ -41,6 +41,7 @@ target_link_libraries(libopenfpga
|
|||
libpcf
|
||||
libvtrutil
|
||||
libbusgroup
|
||||
libionamemap
|
||||
libpugixml
|
||||
libvpr)
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "build_device_module.h"
|
||||
#include "build_fabric_global_port_info.h"
|
||||
#include "build_fabric_io_location_map.h"
|
||||
#include "build_fpga_core_wrapper_module.h"
|
||||
#include "command.h"
|
||||
#include "command_context.h"
|
||||
#include "command_exit_codes.h"
|
||||
|
@ -16,6 +17,7 @@
|
|||
#include "globals.h"
|
||||
#include "openfpga_naming.h"
|
||||
#include "read_xml_fabric_key.h"
|
||||
#include "read_xml_io_name_map.h"
|
||||
#include "vtr_log.h"
|
||||
#include "vtr_time.h"
|
||||
|
||||
|
@ -249,9 +251,16 @@ int add_fpga_core_to_fabric_template(T& openfpga_ctx, const Command& cmd,
|
|||
core_inst_name = cmd_context.option_value(cmd, opt_inst_name);
|
||||
}
|
||||
|
||||
/* Handle I/O naming rules if defined */
|
||||
CommandOptionId opt_io_naming = cmd.option("io_naming");
|
||||
if (true == cmd_context.option_enable(cmd, opt_io_naming)) {
|
||||
read_xml_io_name_map(cmd_context.option_value(cmd, opt_io_naming).c_str(),
|
||||
openfpga_ctx.mutable_io_name_map());
|
||||
}
|
||||
|
||||
return add_fpga_core_to_device_module_graph(
|
||||
openfpga_ctx.mutable_module_graph(), core_inst_name, frame_view,
|
||||
verbose_output);
|
||||
openfpga_ctx.mutable_module_graph(), openfpga_ctx.io_name_map(),
|
||||
core_inst_name, frame_view, verbose_output);
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "fabric_bitstream.h"
|
||||
#include "fabric_global_port_info.h"
|
||||
#include "io_location_map.h"
|
||||
#include "io_name_map.h"
|
||||
#include "memory_bank_shift_register_banks.h"
|
||||
#include "module_manager.h"
|
||||
#include "mux_library.h"
|
||||
|
@ -104,6 +105,7 @@ class OpenfpgaContext : public Context {
|
|||
const openfpga::IoLocationMap& io_location_map() const {
|
||||
return io_location_map_;
|
||||
}
|
||||
const openfpga::IoNameMap& io_name_map() const { return io_name_map_; }
|
||||
const openfpga::FabricGlobalPortInfo& fabric_global_port_info() const {
|
||||
return fabric_global_port_info_;
|
||||
}
|
||||
|
@ -162,6 +164,7 @@ class OpenfpgaContext : public Context {
|
|||
openfpga::IoLocationMap& mutable_io_location_map() {
|
||||
return io_location_map_;
|
||||
}
|
||||
openfpga::IoNameMap& mutable_io_name_map() { return io_name_map_; }
|
||||
openfpga::FabricGlobalPortInfo& mutable_fabric_global_port_info() {
|
||||
return fabric_global_port_info_;
|
||||
}
|
||||
|
@ -216,6 +219,7 @@ class OpenfpgaContext : public Context {
|
|||
/* Fabric module graph */
|
||||
openfpga::ModuleManager module_graph_;
|
||||
openfpga::IoLocationMap io_location_map_;
|
||||
openfpga::IoNameMap io_name_map_;
|
||||
openfpga::FabricGlobalPortInfo fabric_global_port_info_;
|
||||
|
||||
/* Bitstream database */
|
||||
|
|
|
@ -703,6 +703,11 @@ ShellCommandId add_add_fpga_core_to_fabric_command_template(
|
|||
const std::vector<ShellCommandId>& dependent_cmds, const bool& hidden) {
|
||||
Command shell_cmd("add_fpga_core_to_fabric");
|
||||
|
||||
/* Add an option '--io_naming'*/
|
||||
CommandOptionId opt_io_naming = shell_cmd.add_option(
|
||||
"io_naming", false, "specify the file path to the I/O naming rules");
|
||||
shell_cmd.set_option_require_value(opt_io_naming, openfpga::OPT_STRING);
|
||||
|
||||
/* Add an option '--instance_name'*/
|
||||
CommandOptionId opt_inst_name = shell_cmd.add_option(
|
||||
"instance_name", false, "specify the instance of fpga_core under fpga_top");
|
||||
|
|
|
@ -92,6 +92,13 @@ ShellCommandId add_write_full_testbench_command_template(
|
|||
shell_cmd.set_option_short_name(output_opt, "f");
|
||||
shell_cmd.set_option_require_value(output_opt, openfpga::OPT_STRING);
|
||||
|
||||
/* add an option '--dut_module'*/
|
||||
CommandOptionId dut_module_opt = shell_cmd.add_option(
|
||||
"dut_module", false,
|
||||
"specify the module name of DUT to be used in the testbench. Can be either "
|
||||
"fpga_top or fpga_core. By default, it is fpga_top.");
|
||||
shell_cmd.set_option_require_value(dut_module_opt, openfpga::OPT_STRING);
|
||||
|
||||
/* add an option '--bitstream'*/
|
||||
CommandOptionId bitstream_opt = shell_cmd.add_option(
|
||||
"bitstream", true, "specify the bitstream to be loaded in the testbench");
|
||||
|
@ -196,6 +203,13 @@ ShellCommandId add_write_preconfigured_fabric_wrapper_command_template(
|
|||
"specify the file path to the fabric hdl netlist");
|
||||
shell_cmd.set_option_require_value(fabric_netlist_opt, openfpga::OPT_STRING);
|
||||
|
||||
/* add an option '--dut_module'*/
|
||||
CommandOptionId dut_module_opt = shell_cmd.add_option(
|
||||
"dut_module", false,
|
||||
"specify the module name of DUT to be used in the testbench. Can be either "
|
||||
"fpga_top or fpga_core. By default, it is fpga_top.");
|
||||
shell_cmd.set_option_require_value(dut_module_opt, openfpga::OPT_STRING);
|
||||
|
||||
/* add an option '--pin_constraints_file in short '-pcf' */
|
||||
CommandOptionId pcf_opt =
|
||||
shell_cmd.add_option("pin_constraints_file", false,
|
||||
|
@ -275,6 +289,14 @@ ShellCommandId add_write_mock_fpga_wrapper_command_template(
|
|||
shell_cmd.set_option_short_name(pcf_opt, "pcf");
|
||||
shell_cmd.set_option_require_value(pcf_opt, openfpga::OPT_STRING);
|
||||
|
||||
/* add an option '--top_module'*/
|
||||
CommandOptionId top_module_opt =
|
||||
shell_cmd.add_option("top_module", false,
|
||||
"specify the top-level module name to be used in the "
|
||||
"wrapper, which matters the I/O names. Can be either "
|
||||
"fpga_top or fpga_core. By default, it is fpga_top.");
|
||||
shell_cmd.set_option_require_value(top_module_opt, openfpga::OPT_STRING);
|
||||
|
||||
/* add an option '--bus_group_file in short '-bgf' */
|
||||
CommandOptionId bgf_opt = shell_cmd.add_option(
|
||||
"bus_group_file", false, "specify the file path to the group pins to bus");
|
||||
|
@ -297,10 +319,6 @@ ShellCommandId add_write_mock_fpga_wrapper_command_template(
|
|||
shell_cmd.set_option_require_value(default_net_type_opt,
|
||||
openfpga::OPT_STRING);
|
||||
|
||||
/* add an option '--explicit_port_mapping' */
|
||||
shell_cmd.add_option("explicit_port_mapping", false,
|
||||
"use explicit port mapping in verilog netlists");
|
||||
|
||||
/* Add an option '--no_time_stamp' */
|
||||
shell_cmd.add_option("no_time_stamp", false,
|
||||
"Do not print a time stamp in the output files");
|
||||
|
|
|
@ -77,6 +77,7 @@ int write_full_testbench_template(const T& openfpga_ctx, const Command& cmd,
|
|||
const CommandContext& cmd_context) {
|
||||
CommandOptionId opt_output_dir = cmd.option("file");
|
||||
CommandOptionId opt_bitstream = cmd.option("bitstream");
|
||||
CommandOptionId opt_dut_module = cmd.option("dut_module");
|
||||
CommandOptionId opt_fabric_netlist = cmd.option("fabric_netlist_file_path");
|
||||
CommandOptionId opt_pcf = cmd.option("pin_constraints_file");
|
||||
CommandOptionId opt_bgf = cmd.option("bus_group_file");
|
||||
|
@ -116,6 +117,10 @@ int write_full_testbench_template(const T& openfpga_ctx, const Command& cmd,
|
|||
cmd_context.option_value(cmd, opt_default_net_type));
|
||||
}
|
||||
|
||||
if (true == cmd_context.option_enable(cmd, opt_dut_module)) {
|
||||
options.set_dut_module(cmd_context.option_value(cmd, opt_dut_module));
|
||||
}
|
||||
|
||||
/* If pin constraints are enabled by command options, read the file */
|
||||
PinConstraints pin_constraints;
|
||||
if (true == cmd_context.option_enable(cmd, opt_pcf)) {
|
||||
|
@ -135,7 +140,8 @@ int write_full_testbench_template(const T& openfpga_ctx, const Command& cmd,
|
|||
openfpga_ctx.fabric_bitstream(), openfpga_ctx.blwl_shift_register_banks(),
|
||||
g_vpr_ctx.atom(), g_vpr_ctx.placement(), pin_constraints, bus_group,
|
||||
cmd_context.option_value(cmd, opt_bitstream),
|
||||
openfpga_ctx.io_location_map(), openfpga_ctx.fabric_global_port_info(),
|
||||
openfpga_ctx.io_location_map(), openfpga_ctx.io_name_map(),
|
||||
openfpga_ctx.fabric_global_port_info(),
|
||||
openfpga_ctx.vpr_netlist_annotation(), openfpga_ctx.arch().circuit_lib,
|
||||
openfpga_ctx.simulation_setting(), openfpga_ctx.arch().config_protocol,
|
||||
options);
|
||||
|
@ -150,6 +156,7 @@ int write_preconfigured_fabric_wrapper_template(
|
|||
const T& openfpga_ctx, const Command& cmd,
|
||||
const CommandContext& cmd_context) {
|
||||
CommandOptionId opt_output_dir = cmd.option("file");
|
||||
CommandOptionId opt_dut_module = cmd.option("dut_module");
|
||||
CommandOptionId opt_fabric_netlist = cmd.option("fabric_netlist_file_path");
|
||||
CommandOptionId opt_pcf = cmd.option("pin_constraints_file");
|
||||
CommandOptionId opt_bgf = cmd.option("bus_group_file");
|
||||
|
@ -176,6 +183,10 @@ int write_preconfigured_fabric_wrapper_template(
|
|||
cmd_context.option_enable(cmd, opt_include_signal_init));
|
||||
options.set_print_formal_verification_top_netlist(true);
|
||||
|
||||
if (true == cmd_context.option_enable(cmd, opt_dut_module)) {
|
||||
options.set_dut_module(cmd_context.option_value(cmd, opt_dut_module));
|
||||
}
|
||||
|
||||
if (true == cmd_context.option_enable(cmd, opt_default_net_type)) {
|
||||
options.set_default_net_type(
|
||||
cmd_context.option_value(cmd, opt_default_net_type));
|
||||
|
@ -203,7 +214,8 @@ int write_preconfigured_fabric_wrapper_template(
|
|||
return fpga_verilog_preconfigured_fabric_wrapper(
|
||||
openfpga_ctx.module_graph(), openfpga_ctx.bitstream_manager(),
|
||||
g_vpr_ctx.atom(), g_vpr_ctx.placement(), pin_constraints, bus_group,
|
||||
openfpga_ctx.io_location_map(), openfpga_ctx.fabric_global_port_info(),
|
||||
openfpga_ctx.io_location_map(), openfpga_ctx.io_name_map(),
|
||||
openfpga_ctx.fabric_global_port_info(),
|
||||
openfpga_ctx.vpr_netlist_annotation(), openfpga_ctx.arch().circuit_lib,
|
||||
openfpga_ctx.arch().config_protocol, options);
|
||||
}
|
||||
|
@ -216,6 +228,7 @@ template <class T>
|
|||
int write_mock_fpga_wrapper_template(const T& openfpga_ctx, const Command& cmd,
|
||||
const CommandContext& cmd_context) {
|
||||
CommandOptionId opt_output_dir = cmd.option("file");
|
||||
CommandOptionId opt_top_module = cmd.option("top_module");
|
||||
CommandOptionId opt_pcf = cmd.option("pin_constraints_file");
|
||||
CommandOptionId opt_bgf = cmd.option("bus_group_file");
|
||||
CommandOptionId opt_explicit_port_mapping =
|
||||
|
@ -237,6 +250,10 @@ int write_mock_fpga_wrapper_template(const T& openfpga_ctx, const Command& cmd,
|
|||
options.set_time_stamp(!cmd_context.option_enable(cmd, opt_no_time_stamp));
|
||||
options.set_verbose_output(cmd_context.option_enable(cmd, opt_verbose));
|
||||
|
||||
if (true == cmd_context.option_enable(cmd, opt_top_module)) {
|
||||
options.set_dut_module(cmd_context.option_value(cmd, opt_top_module));
|
||||
}
|
||||
|
||||
if (true == cmd_context.option_enable(cmd, opt_default_net_type)) {
|
||||
options.set_default_net_type(
|
||||
cmd_context.option_value(cmd, opt_default_net_type));
|
||||
|
@ -259,7 +276,7 @@ int write_mock_fpga_wrapper_template(const T& openfpga_ctx, const Command& cmd,
|
|||
return fpga_verilog_mock_fpga_wrapper(
|
||||
openfpga_ctx.module_graph(), g_vpr_ctx.atom(), g_vpr_ctx.placement(),
|
||||
pin_constraints, bus_group, openfpga_ctx.io_location_map(),
|
||||
openfpga_ctx.fabric_global_port_info(),
|
||||
openfpga_ctx.io_name_map(), openfpga_ctx.fabric_global_port_info(),
|
||||
openfpga_ctx.vpr_netlist_annotation(), options);
|
||||
}
|
||||
|
||||
|
|
|
@ -127,50 +127,4 @@ int build_device_module_graph(
|
|||
return status;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* The main function to be called for adding the fpga_core wrapper to a FPGA
|
||||
*fabric
|
||||
* - Rename existing fpga_top to fpga_core
|
||||
* - Create a wrapper module 'fpga_top' on the fpga_core
|
||||
*******************************************************************/
|
||||
int add_fpga_core_to_device_module_graph(ModuleManager& module_manager,
|
||||
const std::string& core_inst_name,
|
||||
const bool& frame_view,
|
||||
const bool& verbose) {
|
||||
int status = CMD_EXEC_SUCCESS;
|
||||
|
||||
/* Execute the module graph api */
|
||||
std::string top_module_name = generate_fpga_top_module_name();
|
||||
ModuleId top_module = module_manager.find_module(top_module_name);
|
||||
if (!module_manager.valid_module_id(top_module)) {
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
|
||||
/* Rename existing top module to fpga_core */
|
||||
std::string core_module_name = generate_fpga_core_module_name();
|
||||
module_manager.set_module_name(top_module, core_module_name);
|
||||
VTR_LOGV(verbose, "Rename current top-level module '%s' to '%s'\n",
|
||||
top_module_name.c_str(), core_module_name.c_str());
|
||||
|
||||
/* Create a wrapper module under the existing fpga_top */
|
||||
ModuleId new_top_module = module_manager.create_wrapper_module(
|
||||
top_module, top_module_name, core_inst_name, !frame_view);
|
||||
if (!module_manager.valid_module_id(new_top_module)) {
|
||||
VTR_LOGV_ERROR(verbose,
|
||||
"Failed to create a wrapper module '%s' on top of '%s'!\n",
|
||||
top_module_name.c_str(), core_module_name.c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
VTR_LOGV(verbose, "Created a wrapper module '%s' on top of '%s'\n",
|
||||
top_module_name.c_str(), core_module_name.c_str());
|
||||
|
||||
/* Now fpga_core should be the only configurable child under the top-level
|
||||
* module */
|
||||
module_manager.add_configurable_child(new_top_module, top_module, 0);
|
||||
|
||||
/* TODO: Update the fabric global ports */
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include "fabric_key.h"
|
||||
#include "io_name_map.h"
|
||||
#include "openfpga_context.h"
|
||||
#include "vpr_context.h"
|
||||
|
||||
|
@ -23,11 +24,6 @@ int build_device_module_graph(
|
|||
const bool& duplicate_grid_pin, const FabricKey& fabric_key,
|
||||
const bool& generate_random_fabric_key, const bool& verbose);
|
||||
|
||||
int add_fpga_core_to_device_module_graph(ModuleManager& module_manager,
|
||||
const std::string& core_inst_name,
|
||||
const bool& frame_view,
|
||||
const bool& verbose);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,389 @@
|
|||
/********************************************************************
|
||||
* This file includes the main function to build module graphs
|
||||
* for the FPGA fabric
|
||||
*******************************************************************/
|
||||
|
||||
/* Headers from vtrutil library */
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
#include "vtr_time.h"
|
||||
|
||||
/* Headers from openfpgashell library */
|
||||
#include "build_fpga_core_wrapper_module.h"
|
||||
#include "command_exit_codes.h"
|
||||
#include "openfpga_naming.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/********************************************************************
|
||||
* Add ports to top module based on I/O naming rules:
|
||||
* - Add ports which has been defined in the naming rules
|
||||
* - Add ports from the core module, which does not appear in the naming rules
|
||||
*******************************************************************/
|
||||
static int create_fpga_top_module_ports_using_naming_rules(
|
||||
ModuleManager& module_manager, const ModuleId& wrapper_module,
|
||||
const ModuleId& core_module, const IoNameMap& io_naming,
|
||||
const bool& verbose) {
|
||||
for (BasicPort top_port : io_naming.fpga_top_ports()) {
|
||||
/* For dummy port, just add it. Port type should be defined from io naming
|
||||
* rules */
|
||||
if (io_naming.fpga_top_port_is_dummy(top_port)) {
|
||||
ModuleManager::e_module_port_type port_type =
|
||||
ModuleManager::e_module_port_type::MODULE_INOUT_PORT;
|
||||
if (IoNameMap::e_dummy_port_direction::INPUT ==
|
||||
io_naming.fpga_top_dummy_port_direction(top_port)) {
|
||||
port_type = ModuleManager::e_module_port_type::MODULE_INPUT_PORT;
|
||||
} else if (IoNameMap::e_dummy_port_direction::OUTPUT ==
|
||||
io_naming.fpga_top_dummy_port_direction(top_port)) {
|
||||
port_type = ModuleManager::e_module_port_type::MODULE_OUTPUT_PORT;
|
||||
} else if (IoNameMap::e_dummy_port_direction::INOUT ==
|
||||
io_naming.fpga_top_dummy_port_direction(top_port)) {
|
||||
port_type = ModuleManager::e_module_port_type::MODULE_INOUT_PORT;
|
||||
} else {
|
||||
VTR_LOG_ERROR(
|
||||
"fpga_top dummy port '%s' has an invalid direction. Expect "
|
||||
"[input|output|inout]!\n",
|
||||
top_port.to_verilog_string().c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
module_manager.add_port(wrapper_module, top_port, port_type);
|
||||
VTR_LOGV(verbose,
|
||||
"Add dummy port '%s' to fpga_top by following naming rules\n",
|
||||
top_port.to_verilog_string().c_str());
|
||||
continue; /* Finish for this port addition */
|
||||
}
|
||||
/* Get the port type which should be same as the fpga_core port */
|
||||
BasicPort core_port = io_naming.fpga_core_port(top_port);
|
||||
if (!core_port.is_valid()) {
|
||||
VTR_LOG_ERROR("fpga_top port '%s' is not mapped to any fpga_core port!\n",
|
||||
top_port.to_verilog_string().c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
ModulePortId core_port_id =
|
||||
module_manager.find_module_port(core_module, core_port.get_name());
|
||||
if (!module_manager.valid_module_port_id(core_module, core_port_id)) {
|
||||
VTR_LOG_ERROR(
|
||||
"fpga_top port '%s' is mapped to an invalid fpga_core port '%s'!\n",
|
||||
top_port.to_verilog_string().c_str(),
|
||||
core_port.to_verilog_string().c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
ModuleManager::e_module_port_type top_port_type =
|
||||
module_manager.port_type(core_module, core_port_id);
|
||||
module_manager.add_port(wrapper_module, top_port, top_port_type);
|
||||
VTR_LOGV(verbose,
|
||||
"Add port '%s' to fpga_top (correspond to '%s' of fpga_core) by "
|
||||
"following naming rules\n",
|
||||
top_port.to_verilog_string().c_str(),
|
||||
core_port.to_verilog_string().c_str());
|
||||
}
|
||||
/* Now walk through the ports of fpga_core, if port which is not mapped to
|
||||
* fpga_top should be added */
|
||||
for (ModulePortId core_port_id : module_manager.module_ports(core_module)) {
|
||||
BasicPort core_port = module_manager.module_port(core_module, core_port_id);
|
||||
BasicPort top_port = io_naming.fpga_top_port(core_port);
|
||||
if (top_port.is_valid()) {
|
||||
continue; /* Port has been added in the previous loop, skip now */
|
||||
}
|
||||
/* Throw fatal error if part of the core port is mapped while other part is
|
||||
* not mapped. This is not allowed! */
|
||||
IoNameMap::e_port_mapping_status mapping_status =
|
||||
io_naming.fpga_core_port_mapping_status(core_port, true);
|
||||
if (mapping_status == IoNameMap::e_port_mapping_status::FULL) {
|
||||
continue;
|
||||
}
|
||||
if (mapping_status == IoNameMap::e_port_mapping_status::PARTIAL) {
|
||||
VTR_LOG_ERROR(
|
||||
"fpga_core port '%s' is partially mapped to fpga_top, which is not "
|
||||
"allowed. Please cover the full-sized port in naming rules!\n",
|
||||
core_port.to_verilog_string().c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
if (mapping_status == IoNameMap::e_port_mapping_status::OVERLAPPED) {
|
||||
VTR_LOG_ERROR(
|
||||
"fpga_core port '%s' is overlapped mapped to fpga_top, which is not "
|
||||
"allowed. Please cover the full-sized port in naming rules!\n",
|
||||
core_port.to_verilog_string().c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
VTR_ASSERT(mapping_status == IoNameMap::e_port_mapping_status::NONE);
|
||||
|
||||
/* Add the port now */
|
||||
ModuleManager::e_module_port_type top_port_type =
|
||||
module_manager.port_type(core_module, core_port_id);
|
||||
module_manager.add_port(wrapper_module, core_port, top_port_type);
|
||||
VTR_LOG(
|
||||
"Add port '%s' to fpga_top in the same name as the port of "
|
||||
"fpga_core, since naming rules do not specify\n",
|
||||
core_port.to_verilog_string().c_str());
|
||||
}
|
||||
return CMD_EXEC_SUCCESS;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Add nets between top module and core module based on I/O naming rules:
|
||||
* - Dummy ports do not need any nets
|
||||
* - For ports which are defined in the naming rules, create dedicated
|
||||
*connections
|
||||
* - For ports of the core module, which does not appear in the naming rules,
|
||||
*create direct connections
|
||||
*******************************************************************/
|
||||
static int create_fpga_top_module_nets_using_naming_rules(
|
||||
ModuleManager& module_manager, const ModuleId& wrapper_module,
|
||||
const ModuleId& core_module, const IoNameMap& io_naming,
|
||||
const bool& verbose) {
|
||||
for (BasicPort top_port : io_naming.fpga_top_ports()) {
|
||||
if (io_naming.fpga_top_port_is_dummy(top_port)) {
|
||||
VTR_LOGV("Skip nets for dummy port '%s' at top module\n",
|
||||
top_port.to_verilog_string().c_str());
|
||||
continue;
|
||||
}
|
||||
/* Collect port-level information */
|
||||
ModulePortId top_port_id =
|
||||
module_manager.find_module_port(wrapper_module, top_port.get_name());
|
||||
if (!module_manager.valid_module_port_id(wrapper_module, top_port_id)) {
|
||||
VTR_LOG_ERROR("fpga_top port '%s' is not found at top module!\n",
|
||||
top_port.to_verilog_string().c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
BasicPort core_port = io_naming.fpga_core_port(top_port);
|
||||
if (!core_port.is_valid()) {
|
||||
VTR_LOG_ERROR("fpga_top port '%s' is not mapped to any fpga_core port!\n",
|
||||
top_port.to_verilog_string().c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
ModulePortId core_port_id =
|
||||
module_manager.find_module_port(core_module, core_port.get_name());
|
||||
if (!module_manager.valid_module_port_id(core_module, core_port_id)) {
|
||||
VTR_LOG_ERROR(
|
||||
"fpga_top port '%s' is mapped to an invalid fpga_core port '%s'!\n",
|
||||
top_port.to_verilog_string().c_str(),
|
||||
core_port.to_verilog_string().c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
ModuleManager::e_module_port_type top_port_type =
|
||||
module_manager.port_type(core_module, core_port_id);
|
||||
|
||||
/* Create net for each pin-to-pin connection */
|
||||
if (top_port.get_width() != core_port.get_width()) {
|
||||
VTR_LOG_ERROR(
|
||||
"fpga_top port '%s' does not match the width of fpga_core port '%s'!\n",
|
||||
top_port.to_verilog_string().c_str(),
|
||||
core_port.to_verilog_string().c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
for (size_t ipin = 0; ipin < top_port.pins().size(); ++ipin) {
|
||||
ModuleNetId new_net = module_manager.create_module_net(wrapper_module);
|
||||
if (top_port_type !=
|
||||
ModuleManager::e_module_port_type::MODULE_OUTPUT_PORT) {
|
||||
module_manager.add_module_net_source(wrapper_module, new_net,
|
||||
wrapper_module, 0, top_port_id,
|
||||
top_port.pins()[ipin]);
|
||||
module_manager.add_module_net_sink(wrapper_module, new_net, core_module,
|
||||
0, core_port_id,
|
||||
core_port.pins()[ipin]);
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(top_port_type ==
|
||||
ModuleManager::e_module_port_type::MODULE_OUTPUT_PORT);
|
||||
module_manager.add_module_net_source(wrapper_module, new_net,
|
||||
core_module, 0, core_port_id,
|
||||
core_port.pins()[ipin]);
|
||||
module_manager.add_module_net_sink(wrapper_module, new_net,
|
||||
wrapper_module, 0, top_port_id,
|
||||
top_port.pins()[ipin]);
|
||||
}
|
||||
BasicPort top_pin(top_port.get_name(), top_port.pins()[ipin],
|
||||
top_port.pins()[ipin]);
|
||||
BasicPort core_pin(core_port.get_name(), core_port.pins()[ipin],
|
||||
core_port.pins()[ipin]);
|
||||
VTR_LOGV(
|
||||
verbose,
|
||||
"Add nets to connect between fpga_top '%s' and fpga_core '%s' by "
|
||||
"following naming rules\n",
|
||||
top_pin.to_verilog_string().c_str(),
|
||||
core_pin.to_verilog_string().c_str());
|
||||
}
|
||||
}
|
||||
/* Now walk through the ports of fpga_core, if port which is not mapped to
|
||||
* fpga_top, nets should be added */
|
||||
for (ModulePortId core_port_id : module_manager.module_ports(core_module)) {
|
||||
BasicPort core_port = module_manager.module_port(core_module, core_port_id);
|
||||
BasicPort top_port = io_naming.fpga_top_port(core_port);
|
||||
if (top_port.is_valid()) {
|
||||
continue; /* Port has been added in the previous loop, skip now */
|
||||
}
|
||||
/* Throw fatal error if part of the core port is mapped while other part is
|
||||
* not mapped. This is not allowed! */
|
||||
IoNameMap::e_port_mapping_status mapping_status =
|
||||
io_naming.fpga_core_port_mapping_status(core_port);
|
||||
if (mapping_status == IoNameMap::e_port_mapping_status::FULL) {
|
||||
continue;
|
||||
}
|
||||
if (mapping_status == IoNameMap::e_port_mapping_status::PARTIAL) {
|
||||
VTR_LOG_ERROR(
|
||||
"fpga_core port '%s' is partially mapped to fpga_top, which is not "
|
||||
"allowed. Please cover the full-sized port in naming rules!\n",
|
||||
core_port.to_verilog_string().c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
if (mapping_status == IoNameMap::e_port_mapping_status::OVERLAPPED) {
|
||||
VTR_LOG_ERROR(
|
||||
"fpga_core port '%s' is overlapped mapped to fpga_top, which is not "
|
||||
"allowed. Please cover the full-sized port in naming rules!\n",
|
||||
core_port.to_verilog_string().c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
VTR_ASSERT(mapping_status == IoNameMap::e_port_mapping_status::NONE);
|
||||
ModuleManager::e_module_port_type top_port_type =
|
||||
module_manager.port_type(core_module, core_port_id);
|
||||
/* Collect port-level information */
|
||||
ModulePortId top_port_id =
|
||||
module_manager.find_module_port(wrapper_module, core_port.get_name());
|
||||
top_port = module_manager.module_port(
|
||||
wrapper_module, top_port_id); /* Note: overwrite the top port */
|
||||
if (!module_manager.valid_module_port_id(wrapper_module, top_port_id)) {
|
||||
VTR_LOG_ERROR("fpga_top port '%s' is not found at top module!\n",
|
||||
top_port.to_verilog_string().c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
/* Create net for each pin-to-pin connection */
|
||||
if (top_port.get_width() != core_port.get_width()) {
|
||||
VTR_LOG_ERROR(
|
||||
"fpga_top port '%s' does not match the width of fpga_core port '%s'!\n",
|
||||
top_port.to_verilog_string().c_str(),
|
||||
core_port.to_verilog_string().c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
for (size_t ipin = 0; ipin < core_port.pins().size(); ++ipin) {
|
||||
ModuleNetId new_net = module_manager.create_module_net(wrapper_module);
|
||||
if (top_port_type !=
|
||||
ModuleManager::e_module_port_type::MODULE_OUTPUT_PORT) {
|
||||
module_manager.add_module_net_source(wrapper_module, new_net,
|
||||
wrapper_module, 0, top_port_id,
|
||||
top_port.pins()[ipin]);
|
||||
module_manager.add_module_net_sink(wrapper_module, new_net, core_module,
|
||||
0, core_port_id,
|
||||
core_port.pins()[ipin]);
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(top_port_type ==
|
||||
ModuleManager::e_module_port_type::MODULE_OUTPUT_PORT);
|
||||
module_manager.add_module_net_source(wrapper_module, new_net,
|
||||
core_module, 0, core_port_id,
|
||||
core_port.pins()[ipin]);
|
||||
module_manager.add_module_net_sink(wrapper_module, new_net,
|
||||
wrapper_module, 0, top_port_id,
|
||||
top_port.pins()[ipin]);
|
||||
}
|
||||
BasicPort core_pin(top_port.get_name(), core_port.pins()[ipin],
|
||||
core_port.pins()[ipin]);
|
||||
VTR_LOGV(
|
||||
verbose,
|
||||
"Add nets to connect fpga_top '%s' in the same name as the port of "
|
||||
"fpga_core, since naming rules do not specify\n",
|
||||
core_pin.to_verilog_string().c_str());
|
||||
}
|
||||
}
|
||||
return CMD_EXEC_SUCCESS;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Create a custom fpga_top module by applying naming rules
|
||||
*******************************************************************/
|
||||
static int create_fpga_top_module_using_naming_rules(
|
||||
ModuleManager& module_manager, ModuleId& wrapper_module,
|
||||
const ModuleId& core_module, const std::string& top_module_name,
|
||||
const IoNameMap& io_naming, const std::string& instance_name,
|
||||
const bool& add_nets, const bool& verbose) {
|
||||
/* Create a new module with the given name */
|
||||
wrapper_module = module_manager.add_module(top_module_name);
|
||||
if (!wrapper_module) {
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
/* Add the existing module as an instance */
|
||||
module_manager.add_child_module(wrapper_module, core_module, false);
|
||||
module_manager.set_child_instance_name(wrapper_module, core_module, 0,
|
||||
instance_name);
|
||||
|
||||
/* Add ports */
|
||||
if (CMD_EXEC_SUCCESS !=
|
||||
create_fpga_top_module_ports_using_naming_rules(
|
||||
module_manager, wrapper_module, core_module, io_naming, verbose)) {
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
|
||||
/* Add nets */
|
||||
if (add_nets) {
|
||||
if (CMD_EXEC_SUCCESS !=
|
||||
create_fpga_top_module_nets_using_naming_rules(
|
||||
module_manager, wrapper_module, core_module, io_naming, verbose)) {
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Update the fabric global ports */
|
||||
|
||||
return CMD_EXEC_SUCCESS;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* The main function to be called for adding the fpga_core wrapper to a FPGA
|
||||
*fabric
|
||||
* - Rename existing fpga_top to fpga_core
|
||||
* - Create a wrapper module 'fpga_top' on the fpga_core
|
||||
*******************************************************************/
|
||||
int add_fpga_core_to_device_module_graph(ModuleManager& module_manager,
|
||||
const IoNameMap& io_naming,
|
||||
const std::string& core_inst_name,
|
||||
const bool& frame_view,
|
||||
const bool& verbose) {
|
||||
int status = CMD_EXEC_SUCCESS;
|
||||
|
||||
/* Execute the module graph api */
|
||||
std::string top_module_name = generate_fpga_top_module_name();
|
||||
ModuleId top_module = module_manager.find_module(top_module_name);
|
||||
if (!module_manager.valid_module_id(top_module)) {
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
|
||||
/* Rename existing top module to fpga_core */
|
||||
std::string core_module_name = generate_fpga_core_module_name();
|
||||
module_manager.set_module_name(top_module, core_module_name);
|
||||
VTR_LOGV(verbose, "Rename current top-level module '%s' to '%s'\n",
|
||||
top_module_name.c_str(), core_module_name.c_str());
|
||||
|
||||
/* Create a wrapper module under the existing fpga_top
|
||||
* - if there are no io naming rules, just use the default API to create a
|
||||
* wrapper
|
||||
* - if there are io naming rules, use dedicated function to handle
|
||||
*/
|
||||
ModuleId new_top_module;
|
||||
if (io_naming.empty()) {
|
||||
new_top_module = module_manager.create_wrapper_module(
|
||||
top_module, top_module_name, core_inst_name, !frame_view);
|
||||
} else {
|
||||
status = create_fpga_top_module_using_naming_rules(
|
||||
module_manager, new_top_module, top_module, top_module_name, io_naming,
|
||||
core_inst_name, !frame_view, verbose);
|
||||
if (CMD_EXEC_SUCCESS != status) {
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
}
|
||||
if (!module_manager.valid_module_id(new_top_module)) {
|
||||
VTR_LOGV_ERROR(verbose,
|
||||
"Failed to create a wrapper module '%s' on top of '%s'!\n",
|
||||
top_module_name.c_str(), core_module_name.c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
|
||||
VTR_LOGV(verbose, "Created a wrapper module '%s' on top of '%s'\n",
|
||||
top_module_name.c_str(), core_module_name.c_str());
|
||||
|
||||
/* Now fpga_core should be the only configurable child under the top-level
|
||||
* module */
|
||||
module_manager.add_configurable_child(new_top_module, top_module, 0);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef BUILD_FPGA_CORE_WRAPPER_MODULE_H
|
||||
#define BUILD_FPGA_CORE_WRAPPER_MODULE_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include <string>
|
||||
|
||||
#include "io_name_map.h"
|
||||
#include "module_manager.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
int add_fpga_core_to_device_module_graph(ModuleManager& module_manager,
|
||||
const IoNameMap& io_naming,
|
||||
const std::string& core_inst_name,
|
||||
const bool& frame_view,
|
||||
const bool& verbose);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
|
@ -148,6 +148,7 @@ int fpga_verilog_full_testbench(
|
|||
const AtomContext &atom_ctx, const PlacementContext &place_ctx,
|
||||
const PinConstraints &pin_constraints, const BusGroup &bus_group,
|
||||
const std::string &bitstream_file, const IoLocationMap &io_location_map,
|
||||
const IoNameMap &io_name_map,
|
||||
const FabricGlobalPortInfo &fabric_global_port_info,
|
||||
const VprNetlistAnnotation &netlist_annotation,
|
||||
const CircuitLibrary &circuit_lib,
|
||||
|
@ -174,7 +175,7 @@ int fpga_verilog_full_testbench(
|
|||
print_verilog_full_testbench(
|
||||
module_manager, bitstream_manager, fabric_bitstream, blwl_sr_banks,
|
||||
circuit_lib, config_protocol, fabric_global_port_info, atom_ctx, place_ctx,
|
||||
pin_constraints, bus_group, bitstream_file, io_location_map,
|
||||
pin_constraints, bus_group, bitstream_file, io_location_map, io_name_map,
|
||||
netlist_annotation, netlist_name, top_testbench_file_path,
|
||||
simulation_setting, options);
|
||||
|
||||
|
@ -197,6 +198,7 @@ int fpga_verilog_preconfigured_fabric_wrapper(
|
|||
const BitstreamManager &bitstream_manager, const AtomContext &atom_ctx,
|
||||
const PlacementContext &place_ctx, const PinConstraints &pin_constraints,
|
||||
const BusGroup &bus_group, const IoLocationMap &io_location_map,
|
||||
const IoNameMap &io_name_map,
|
||||
const FabricGlobalPortInfo &fabric_global_port_info,
|
||||
const VprNetlistAnnotation &netlist_annotation,
|
||||
const CircuitLibrary &circuit_lib, const ConfigProtocol &config_protocol,
|
||||
|
@ -221,7 +223,7 @@ int fpga_verilog_preconfigured_fabric_wrapper(
|
|||
status = print_verilog_preconfig_top_module(
|
||||
module_manager, bitstream_manager, config_protocol, circuit_lib,
|
||||
fabric_global_port_info, atom_ctx, place_ctx, pin_constraints, bus_group,
|
||||
io_location_map, netlist_annotation, netlist_name,
|
||||
io_location_map, io_name_map, netlist_annotation, netlist_name,
|
||||
formal_verification_top_netlist_file_path, options);
|
||||
|
||||
return status;
|
||||
|
@ -235,6 +237,7 @@ int fpga_verilog_mock_fpga_wrapper(
|
|||
const ModuleManager &module_manager, const AtomContext &atom_ctx,
|
||||
const PlacementContext &place_ctx, const PinConstraints &pin_constraints,
|
||||
const BusGroup &bus_group, const IoLocationMap &io_location_map,
|
||||
const IoNameMap &io_name_map,
|
||||
const FabricGlobalPortInfo &fabric_global_port_info,
|
||||
const VprNetlistAnnotation &netlist_annotation,
|
||||
const VerilogTestbenchOption &options) {
|
||||
|
@ -259,8 +262,8 @@ int fpga_verilog_mock_fpga_wrapper(
|
|||
std::string netlist_file_path = src_dir_path + netlist_file_name;
|
||||
status = print_verilog_mock_fpga_wrapper(
|
||||
module_manager, fabric_global_port_info, atom_ctx, place_ctx,
|
||||
pin_constraints, bus_group, io_location_map, netlist_annotation,
|
||||
netlist_name, netlist_file_path, options);
|
||||
pin_constraints, bus_group, io_location_map, io_name_map,
|
||||
netlist_annotation, netlist_name, netlist_file_path, options);
|
||||
|
||||
/* Add fname to the netlist name list */
|
||||
NetlistId nlist_id = NetlistId::INVALID();
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "fabric_global_port_info.h"
|
||||
#include "fabric_verilog_options.h"
|
||||
#include "io_location_map.h"
|
||||
#include "io_name_map.h"
|
||||
#include "memory_bank_shift_register_banks.h"
|
||||
#include "module_manager.h"
|
||||
#include "mux_library.h"
|
||||
|
@ -52,6 +53,7 @@ int fpga_verilog_full_testbench(
|
|||
const AtomContext& atom_ctx, const PlacementContext& place_ctx,
|
||||
const PinConstraints& pin_constraints, const BusGroup& bus_group,
|
||||
const std::string& bitstream_file, const IoLocationMap& io_location_map,
|
||||
const IoNameMap& io_name_map,
|
||||
const FabricGlobalPortInfo& fabric_global_port_info,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
|
@ -63,6 +65,7 @@ int fpga_verilog_preconfigured_fabric_wrapper(
|
|||
const BitstreamManager& bitstream_manager, const AtomContext& atom_ctx,
|
||||
const PlacementContext& place_ctx, const PinConstraints& pin_constraints,
|
||||
const BusGroup& bus_group, const IoLocationMap& io_location_map,
|
||||
const IoNameMap& io_name_map,
|
||||
const FabricGlobalPortInfo& fabric_global_port_info,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const CircuitLibrary& circuit_lib, const ConfigProtocol& config_protocol,
|
||||
|
@ -72,6 +75,7 @@ int fpga_verilog_mock_fpga_wrapper(
|
|||
const ModuleManager& module_manager, const AtomContext& atom_ctx,
|
||||
const PlacementContext& place_ctx, const PinConstraints& pin_constraints,
|
||||
const BusGroup& bus_group, const IoLocationMap& io_location_map,
|
||||
const IoNameMap& io_name_map,
|
||||
const FabricGlobalPortInfo& fabric_global_port_info,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const VerilogTestbenchOption& options);
|
||||
|
|
|
@ -44,7 +44,7 @@ static void print_verilog_mock_fpga_wrapper_connect_ios(
|
|||
std::fstream& fp, const ModuleManager& module_manager,
|
||||
const ModuleId& top_module, const AtomContext& atom_ctx,
|
||||
const PlacementContext& place_ctx, const IoLocationMap& io_location_map,
|
||||
const PinConstraints& pin_constraints,
|
||||
const IoNameMap& io_name_map, const PinConstraints& pin_constraints,
|
||||
const FabricGlobalPortInfo& global_ports,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const std::string& net_name_postfix,
|
||||
|
@ -199,10 +199,17 @@ static void print_verilog_mock_fpga_wrapper_connect_ios(
|
|||
print_verilog_comment(
|
||||
fp, std::string("----- Blif Benchmark input " + block_name +
|
||||
" is mapped to FPGA IOPAD " +
|
||||
module_mapped_io_port.get_name() + "[" +
|
||||
std::to_string(io_index) + "] -----"));
|
||||
module_mapped_io_port.to_verilog_string() + " -----"));
|
||||
/* Consider possible I/O naming rules */
|
||||
BasicPort renamed_module_mapped_io_port =
|
||||
io_name_map.fpga_top_port(module_mapped_io_port);
|
||||
if (renamed_module_mapped_io_port.is_valid()) {
|
||||
print_verilog_wire_connection(fp, benchmark_io_port,
|
||||
renamed_module_mapped_io_port, false);
|
||||
} else {
|
||||
print_verilog_wire_connection(fp, benchmark_io_port,
|
||||
module_mapped_io_port, false);
|
||||
}
|
||||
} else {
|
||||
VTR_ASSERT(AtomBlockType::OUTPAD == atom_ctx.nlist.block_type(atom_blk));
|
||||
benchmark_io_port.set_name(
|
||||
|
@ -210,11 +217,18 @@ static void print_verilog_mock_fpga_wrapper_connect_ios(
|
|||
print_verilog_comment(
|
||||
fp, std::string("----- Blif Benchmark output " + block_name +
|
||||
" is mapped to FPGA IOPAD " +
|
||||
module_mapped_io_port.get_name() + "[" +
|
||||
std::to_string(io_index) + "] -----"));
|
||||
module_mapped_io_port.to_verilog_string() + " -----"));
|
||||
/* Consider possible I/O naming rules */
|
||||
BasicPort renamed_module_mapped_io_port =
|
||||
io_name_map.fpga_top_port(module_mapped_io_port);
|
||||
if (renamed_module_mapped_io_port.is_valid()) {
|
||||
print_verilog_wire_connection(fp, renamed_module_mapped_io_port,
|
||||
benchmark_io_port, false);
|
||||
} else {
|
||||
print_verilog_wire_connection(fp, module_mapped_io_port,
|
||||
benchmark_io_port, false);
|
||||
}
|
||||
}
|
||||
|
||||
/* Mark this I/O has been used/wired */
|
||||
io_used[mapped_module_io_info.first][io_index] = true;
|
||||
|
@ -250,9 +264,17 @@ static void print_verilog_mock_fpga_wrapper_connect_ios(
|
|||
|
||||
std::vector<size_t> default_values(module_unused_io_port.get_width(),
|
||||
unused_io_value);
|
||||
/* Consider possible I/O naming rules */
|
||||
BasicPort renamed_module_unused_io_port =
|
||||
io_name_map.fpga_top_port(module_unused_io_port);
|
||||
if (renamed_module_unused_io_port.is_valid()) {
|
||||
print_verilog_wire_constant_values(fp, renamed_module_unused_io_port,
|
||||
default_values);
|
||||
} else {
|
||||
print_verilog_wire_constant_values(fp, module_unused_io_port,
|
||||
default_values);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add an empty line as a splitter */
|
||||
fp << std::endl;
|
||||
|
@ -267,7 +289,7 @@ static void print_verilog_mock_fpga_wrapper_connect_ios(
|
|||
static int print_verilog_mock_fpga_wrapper_connect_global_ports(
|
||||
std::fstream& fp, const ModuleManager& module_manager,
|
||||
const ModuleId& top_module, const PinConstraints& pin_constraints,
|
||||
const FabricGlobalPortInfo& fabric_global_ports,
|
||||
const FabricGlobalPortInfo& fabric_global_ports, const IoNameMap& io_name_map,
|
||||
const std::vector<std::string>& benchmark_clock_port_names) {
|
||||
/* Validate the file stream */
|
||||
valid_file_stream(fp);
|
||||
|
@ -330,8 +352,16 @@ static int print_verilog_mock_fpga_wrapper_connect_global_ports(
|
|||
clock_name_to_connect += std::string(APPINST_PORT_POSTFIX);
|
||||
|
||||
BasicPort benchmark_clock_pin(clock_name_to_connect, 1);
|
||||
print_verilog_wire_connection(fp, benchmark_clock_pin, module_clock_pin,
|
||||
false);
|
||||
/* If io naming is applicable, just consider the renaming port */
|
||||
BasicPort actual_module_clock_pin =
|
||||
io_name_map.fpga_top_port(module_clock_pin);
|
||||
if (!actual_module_clock_pin.is_valid()) {
|
||||
print_verilog_wire_connection(fp, benchmark_clock_pin,
|
||||
module_clock_pin, false);
|
||||
} else {
|
||||
print_verilog_wire_connection(fp, benchmark_clock_pin,
|
||||
actual_module_clock_pin, false);
|
||||
}
|
||||
}
|
||||
/* Finish, go to the next */
|
||||
continue;
|
||||
|
@ -363,8 +393,16 @@ static int print_verilog_mock_fpga_wrapper_connect_global_ports(
|
|||
if ((false == pin_constraints.unconstrained_net(constrained_net_name)) &&
|
||||
(false == pin_constraints.unmapped_net(constrained_net_name))) {
|
||||
BasicPort benchmark_pin(constrained_net_name, 1);
|
||||
/* If io naming is applicable, just consider the renaming port */
|
||||
BasicPort actual_module_global_pin =
|
||||
io_name_map.fpga_top_port(module_global_pin);
|
||||
if (!actual_module_global_pin.is_valid()) {
|
||||
print_verilog_wire_connection(fp, benchmark_pin, module_global_pin,
|
||||
false);
|
||||
} else {
|
||||
print_verilog_wire_connection(fp, benchmark_pin,
|
||||
actual_module_global_pin, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -407,7 +445,7 @@ int print_verilog_mock_fpga_wrapper(
|
|||
const ModuleManager& module_manager, const FabricGlobalPortInfo& global_ports,
|
||||
const AtomContext& atom_ctx, const PlacementContext& place_ctx,
|
||||
const PinConstraints& pin_constraints, const BusGroup& bus_group,
|
||||
const IoLocationMap& io_location_map,
|
||||
const IoLocationMap& io_location_map, const IoNameMap& io_name_map,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const std::string& circuit_name, const std::string& verilog_fname,
|
||||
const VerilogTestbenchOption& options) {
|
||||
|
@ -434,9 +472,37 @@ int print_verilog_mock_fpga_wrapper(
|
|||
print_verilog_file_header(fp, title, options.time_stamp());
|
||||
|
||||
/* Find the top_module */
|
||||
ModuleId top_module =
|
||||
module_manager.find_module(generate_fpga_top_module_name());
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
|
||||
ModuleId top_module = module_manager.find_module(options.dut_module());
|
||||
if (!module_manager.valid_module_id(top_module)) {
|
||||
VTR_LOG_ERROR(
|
||||
"Unable to find the DUT module '%s'. Please check if you create "
|
||||
"dedicated module when building the fabric!\n",
|
||||
options.dut_module().c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
/* Note that we always need the core module as it contains the original port
|
||||
* names before possible renaming at top-level module. If there is no core
|
||||
* module, it means that the current top module is the core module */
|
||||
ModuleId core_module =
|
||||
module_manager.find_module(generate_fpga_core_module_name());
|
||||
if (!module_manager.valid_module_id(core_module)) {
|
||||
core_module = top_module;
|
||||
}
|
||||
|
||||
/* Precheck on the top module and decide if we need to consider I/O naming
|
||||
* - If we do have a fpga_core module added, and dut is fpga_top, we need a
|
||||
* I/O naming
|
||||
* - If we do NOT have a fpga_core module added, and dut is fpga_top, we do
|
||||
* NOT need a I/O naming
|
||||
* - If we do have a fpga_core module added, and dut is fpga_core, we do NOT
|
||||
* need a I/O naming
|
||||
* - If we do NOT have a fpga_core module added, and dut is fpga_core, it
|
||||
* should error out earlier.
|
||||
*/
|
||||
bool require_io_naming = false;
|
||||
if (top_module != core_module) {
|
||||
require_io_naming = true;
|
||||
}
|
||||
|
||||
/* Print module declaration */
|
||||
print_verilog_module_declaration(fp, module_manager, top_module,
|
||||
|
@ -466,16 +532,17 @@ int print_verilog_mock_fpga_wrapper(
|
|||
/* Connect FPGA top module global ports to constant or benchmark global
|
||||
* signals! */
|
||||
status = print_verilog_mock_fpga_wrapper_connect_global_ports(
|
||||
fp, module_manager, top_module, pin_constraints, global_ports,
|
||||
benchmark_clock_port_names);
|
||||
fp, module_manager, core_module, pin_constraints, global_ports,
|
||||
require_io_naming ? io_name_map : IoNameMap(), benchmark_clock_port_names);
|
||||
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Connect I/Os to benchmark I/Os or constant driver */
|
||||
print_verilog_mock_fpga_wrapper_connect_ios(
|
||||
fp, module_manager, top_module, atom_ctx, place_ctx, io_location_map,
|
||||
pin_constraints, global_ports, netlist_annotation, std::string(),
|
||||
fp, module_manager, core_module, atom_ctx, place_ctx, io_location_map,
|
||||
require_io_naming ? io_name_map : IoNameMap(), pin_constraints,
|
||||
global_ports, netlist_annotation, std::string(),
|
||||
std::string(APPINST_PORT_POSTFIX), std::string(APPINST_PORT_POSTFIX),
|
||||
benchmark_clock_port_names, (size_t)VERILOG_DEFAULT_SIGNAL_INIT_VALUE);
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "config_protocol.h"
|
||||
#include "fabric_global_port_info.h"
|
||||
#include "io_location_map.h"
|
||||
#include "io_name_map.h"
|
||||
#include "module_manager.h"
|
||||
#include "pin_constraints.h"
|
||||
#include "verilog_testbench_options.h"
|
||||
|
@ -30,7 +31,7 @@ int print_verilog_mock_fpga_wrapper(
|
|||
const ModuleManager& module_manager, const FabricGlobalPortInfo& global_ports,
|
||||
const AtomContext& atom_ctx, const PlacementContext& place_ctx,
|
||||
const PinConstraints& pin_constraints, const BusGroup& bus_group,
|
||||
const IoLocationMap& io_location_map,
|
||||
const IoLocationMap& io_location_map, const IoNameMap& io_name_map,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const std::string& circuit_name, const std::string& verilog_fname,
|
||||
const VerilogTestbenchOption& options);
|
||||
|
|
|
@ -306,9 +306,8 @@ static int print_verilog_preconfig_top_module_connect_global_ports(
|
|||
* while uses 'force' syntax to impost the bitstream at mem_inv port
|
||||
*******************************************************************/
|
||||
static void print_verilog_preconfig_top_module_force_bitstream(
|
||||
std::fstream &fp, const ModuleManager &module_manager,
|
||||
const ModuleId &top_module, const BitstreamManager &bitstream_manager,
|
||||
const bool &output_datab_bits) {
|
||||
std::fstream &fp, const std::string &top_block_name,
|
||||
const BitstreamManager &bitstream_manager, const bool &output_datab_bits) {
|
||||
/* Validate the file stream */
|
||||
valid_file_stream(fp);
|
||||
|
||||
|
@ -325,14 +324,11 @@ static void print_verilog_preconfig_top_module_force_bitstream(
|
|||
}
|
||||
/* Build the hierarchical path of the configuration bit in modules */
|
||||
std::vector<ConfigBlockId> block_hierarchy =
|
||||
find_bitstream_manager_block_hierarchy(bitstream_manager,
|
||||
config_block_id);
|
||||
/* Drop the first block, which is the top module, it should be replaced by
|
||||
* the instance name here */
|
||||
find_bitstream_manager_block_hierarchy(bitstream_manager, config_block_id,
|
||||
top_block_name);
|
||||
/* Ensure that this is the module we want to drop! */
|
||||
VTR_ASSERT(0 ==
|
||||
module_manager.module_name(top_module)
|
||||
.compare(bitstream_manager.block_name(block_hierarchy[0])));
|
||||
VTR_ASSERT(top_block_name ==
|
||||
bitstream_manager.block_name(block_hierarchy[0]));
|
||||
block_hierarchy.erase(block_hierarchy.begin());
|
||||
/* Build the full hierarchy path */
|
||||
std::string bit_hierarchy_path(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME);
|
||||
|
@ -386,9 +382,8 @@ static void print_verilog_preconfig_top_module_force_bitstream(
|
|||
* This function uses '$deposit' syntax to do so
|
||||
*******************************************************************/
|
||||
static void print_verilog_preconfig_top_module_deposit_bitstream(
|
||||
std::fstream &fp, const ModuleManager &module_manager,
|
||||
const ModuleId &top_module, const BitstreamManager &bitstream_manager,
|
||||
const bool &output_datab_bits) {
|
||||
std::fstream &fp, const std::string &top_block_name,
|
||||
const BitstreamManager &bitstream_manager, const bool &output_datab_bits) {
|
||||
/* Validate the file stream */
|
||||
valid_file_stream(fp);
|
||||
|
||||
|
@ -405,15 +400,15 @@ static void print_verilog_preconfig_top_module_deposit_bitstream(
|
|||
}
|
||||
/* Build the hierarchical path of the configuration bit in modules */
|
||||
std::vector<ConfigBlockId> block_hierarchy =
|
||||
find_bitstream_manager_block_hierarchy(bitstream_manager,
|
||||
config_block_id);
|
||||
find_bitstream_manager_block_hierarchy(bitstream_manager, config_block_id,
|
||||
top_block_name);
|
||||
/* Drop the first block, which is the top module, it should be replaced by
|
||||
* the instance name here */
|
||||
/* Ensure that this is the module we want to drop! */
|
||||
VTR_ASSERT(0 ==
|
||||
module_manager.module_name(top_module)
|
||||
.compare(bitstream_manager.block_name(block_hierarchy[0])));
|
||||
VTR_ASSERT(top_block_name ==
|
||||
bitstream_manager.block_name(block_hierarchy[0]));
|
||||
block_hierarchy.erase(block_hierarchy.begin());
|
||||
|
||||
/* Build the full hierarchy path */
|
||||
std::string bit_hierarchy_path(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME);
|
||||
for (const ConfigBlockId &temp_block : block_hierarchy) {
|
||||
|
@ -470,9 +465,9 @@ static void print_verilog_preconfig_top_module_deposit_bitstream(
|
|||
* 2. Mentor Modelsim prefers using '$deposit' syntax to do so
|
||||
*******************************************************************/
|
||||
static void print_verilog_preconfig_top_module_load_bitstream(
|
||||
std::fstream &fp, const ModuleManager &module_manager,
|
||||
const ModuleId &top_module, const CircuitLibrary &circuit_lib,
|
||||
const CircuitModelId &mem_model, const BitstreamManager &bitstream_manager,
|
||||
std::fstream &fp, const std::string &top_block_name,
|
||||
const CircuitLibrary &circuit_lib, const CircuitModelId &mem_model,
|
||||
const BitstreamManager &bitstream_manager,
|
||||
const e_embedded_bitstream_hdl_type &embedded_bitstream_hdl_type) {
|
||||
/* Skip the datab port if there is only 1 output port in memory model
|
||||
* Currently, it assumes that the data output port is always defined while
|
||||
|
@ -494,11 +489,11 @@ static void print_verilog_preconfig_top_module_load_bitstream(
|
|||
/* Use assign syntax for Icarus simulator */
|
||||
if (EMBEDDED_BITSTREAM_HDL_IVERILOG == embedded_bitstream_hdl_type) {
|
||||
print_verilog_preconfig_top_module_force_bitstream(
|
||||
fp, module_manager, top_module, bitstream_manager, output_datab_bits);
|
||||
fp, top_block_name, bitstream_manager, output_datab_bits);
|
||||
/* Use deposit syntax for other simulators */
|
||||
} else if (EMBEDDED_BITSTREAM_HDL_MODELSIM == embedded_bitstream_hdl_type) {
|
||||
print_verilog_preconfig_top_module_deposit_bitstream(
|
||||
fp, module_manager, top_module, bitstream_manager, output_datab_bits);
|
||||
fp, top_block_name, bitstream_manager, output_datab_bits);
|
||||
}
|
||||
|
||||
print_verilog_comment(
|
||||
|
@ -545,7 +540,7 @@ int print_verilog_preconfig_top_module(
|
|||
const FabricGlobalPortInfo &global_ports, const AtomContext &atom_ctx,
|
||||
const PlacementContext &place_ctx, const PinConstraints &pin_constraints,
|
||||
const BusGroup &bus_group, const IoLocationMap &io_location_map,
|
||||
const VprNetlistAnnotation &netlist_annotation,
|
||||
const IoNameMap &io_name_map, const VprNetlistAnnotation &netlist_annotation,
|
||||
const std::string &circuit_name, const std::string &verilog_fname,
|
||||
const VerilogTestbenchOption &options) {
|
||||
std::string timer_message =
|
||||
|
@ -577,20 +572,33 @@ int print_verilog_preconfig_top_module(
|
|||
print_verilog_preconfig_top_module_ports(fp, circuit_name, atom_ctx,
|
||||
netlist_annotation, bus_group);
|
||||
|
||||
/* Find the top_module */
|
||||
ModuleId top_module =
|
||||
module_manager.find_module(generate_fpga_top_module_name());
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
|
||||
/* Spot the dut module */
|
||||
ModuleId top_module = module_manager.find_module(options.dut_module());
|
||||
if (!module_manager.valid_module_id(top_module)) {
|
||||
VTR_LOG_ERROR(
|
||||
"Unable to find the DUT module '%s'. Please check if you create "
|
||||
"dedicated module when building the fabric!\n",
|
||||
options.dut_module().c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
/* Note that we always need the core module as it contains the original port
|
||||
* names before possible renaming at top-level module. If there is no core
|
||||
* module, it means that the current top module is the core module */
|
||||
ModuleId core_module =
|
||||
module_manager.find_module(generate_fpga_core_module_name());
|
||||
if (!module_manager.valid_module_id(core_module)) {
|
||||
core_module = top_module;
|
||||
}
|
||||
|
||||
/* Print internal wires */
|
||||
print_verilog_preconfig_top_module_internal_wires(fp, module_manager,
|
||||
top_module);
|
||||
core_module);
|
||||
|
||||
/* Instanciate FPGA top-level module */
|
||||
print_verilog_testbench_fpga_instance(
|
||||
fp, module_manager, top_module,
|
||||
fp, module_manager, top_module, core_module,
|
||||
std::string(FORMAL_VERIFICATION_TOP_MODULE_UUT_NAME),
|
||||
std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX),
|
||||
std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX), io_name_map,
|
||||
options.explicit_port_mapping());
|
||||
|
||||
/* Find clock ports in benchmark */
|
||||
|
@ -600,7 +608,7 @@ int print_verilog_preconfig_top_module(
|
|||
/* Connect FPGA top module global ports to constant or benchmark global
|
||||
* signals! */
|
||||
status = print_verilog_preconfig_top_module_connect_global_ports(
|
||||
fp, module_manager, top_module, pin_constraints, global_ports,
|
||||
fp, module_manager, core_module, pin_constraints, global_ports,
|
||||
benchmark_clock_port_names);
|
||||
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||
return status;
|
||||
|
@ -608,7 +616,7 @@ int print_verilog_preconfig_top_module(
|
|||
|
||||
/* Connect I/Os to benchmark I/Os or constant driver */
|
||||
print_verilog_testbench_connect_fpga_ios(
|
||||
fp, module_manager, top_module, atom_ctx, place_ctx, io_location_map,
|
||||
fp, module_manager, core_module, atom_ctx, place_ctx, io_location_map,
|
||||
netlist_annotation, bus_group,
|
||||
std::string(FORMAL_VERIFICATION_TOP_MODULE_PORT_POSTFIX), std::string(),
|
||||
std::string(), std::vector<std::string>(),
|
||||
|
@ -618,10 +626,20 @@ int print_verilog_preconfig_top_module(
|
|||
CircuitModelId sram_model = config_protocol.memory_model();
|
||||
VTR_ASSERT(true == circuit_lib.valid_model_id(sram_model));
|
||||
|
||||
/* If we do have the core module, and the dut is specified as core module, the
|
||||
* hierarchy path when adding should be the instance name of the core module
|
||||
*/
|
||||
std::string inst_name = generate_fpga_top_module_name();
|
||||
if (options.dut_module() == generate_fpga_core_module_name()) {
|
||||
ModuleId parent_module =
|
||||
module_manager.find_module(generate_fpga_top_module_name());
|
||||
inst_name = module_manager.instance_name(parent_module, core_module, 0);
|
||||
}
|
||||
|
||||
/* Assign FPGA internal SRAM/Memory ports to bitstream values, only output
|
||||
* when needed */
|
||||
print_verilog_preconfig_top_module_load_bitstream(
|
||||
fp, module_manager, top_module, circuit_lib, sram_model, bitstream_manager,
|
||||
fp, inst_name, circuit_lib, sram_model, bitstream_manager,
|
||||
options.embedded_bitstream_hdl_type());
|
||||
|
||||
/* Add signal initialization:
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "config_protocol.h"
|
||||
#include "fabric_global_port_info.h"
|
||||
#include "io_location_map.h"
|
||||
#include "io_name_map.h"
|
||||
#include "module_manager.h"
|
||||
#include "pin_constraints.h"
|
||||
#include "verilog_testbench_options.h"
|
||||
|
@ -33,7 +34,7 @@ int print_verilog_preconfig_top_module(
|
|||
const FabricGlobalPortInfo& global_ports, const AtomContext& atom_ctx,
|
||||
const PlacementContext& place_ctx, const PinConstraints& pin_constraints,
|
||||
const BusGroup& bus_group, const IoLocationMap& io_location_map,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const IoNameMap& io_name_map, const VprNetlistAnnotation& netlist_annotation,
|
||||
const std::string& circuit_name, const std::string& verilog_fname,
|
||||
const VerilogTestbenchOption& options);
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
******************************************************************************/
|
||||
#include "verilog_testbench_options.h"
|
||||
|
||||
#include "openfpga_naming.h"
|
||||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
|
||||
|
@ -14,6 +15,7 @@ namespace openfpga {
|
|||
*************************************************/
|
||||
VerilogTestbenchOption::VerilogTestbenchOption() {
|
||||
output_directory_.clear();
|
||||
dut_module_ = "fpga_top";
|
||||
fabric_netlist_file_path_.clear();
|
||||
reference_benchmark_file_path_.clear();
|
||||
print_preconfig_top_testbench_ = false;
|
||||
|
@ -37,6 +39,8 @@ std::string VerilogTestbenchOption::output_directory() const {
|
|||
return output_directory_;
|
||||
}
|
||||
|
||||
std::string VerilogTestbenchOption::dut_module() const { return dut_module_; }
|
||||
|
||||
std::string VerilogTestbenchOption::fabric_netlist_file_path() const {
|
||||
return fabric_netlist_file_path_;
|
||||
}
|
||||
|
@ -108,6 +112,19 @@ void VerilogTestbenchOption::set_output_directory(
|
|||
output_directory_ = output_dir;
|
||||
}
|
||||
|
||||
void VerilogTestbenchOption::set_dut_module(const std::string& dut_module) {
|
||||
/* Precheck: only accept two legal names */
|
||||
if (dut_module != generate_fpga_top_module_name() &&
|
||||
dut_module != generate_fpga_core_module_name()) {
|
||||
VTR_LOG_ERROR(
|
||||
"Invalid module name '%s' for Design Under Test (DUT)! Expect [%s|%s]\n",
|
||||
dut_module.c_str(), generate_fpga_top_module_name().c_str(),
|
||||
generate_fpga_core_module_name().c_str());
|
||||
exit(1);
|
||||
}
|
||||
dut_module_ = dut_module;
|
||||
}
|
||||
|
||||
void VerilogTestbenchOption::set_fabric_netlist_file_path(
|
||||
const std::string& fabric_netlist_file_path) {
|
||||
fabric_netlist_file_path_ = fabric_netlist_file_path;
|
||||
|
|
|
@ -37,6 +37,7 @@ class VerilogTestbenchOption {
|
|||
|
||||
public: /* Public accessors */
|
||||
std::string output_directory() const;
|
||||
std::string dut_module() const;
|
||||
std::string fabric_netlist_file_path() const;
|
||||
std::string reference_benchmark_file_path() const;
|
||||
bool fast_configuration() const;
|
||||
|
@ -60,6 +61,7 @@ class VerilogTestbenchOption {
|
|||
|
||||
public: /* Public mutators */
|
||||
void set_output_directory(const std::string& output_dir);
|
||||
void set_dut_module(const std::string& dut_module);
|
||||
/* The reference verilog file path is the key parameters that will have an
|
||||
* impact on other options:
|
||||
* - print_preconfig_top_testbench
|
||||
|
@ -93,6 +95,7 @@ class VerilogTestbenchOption {
|
|||
|
||||
private: /* Internal Data */
|
||||
std::string output_directory_;
|
||||
std::string dut_module_;
|
||||
std::string fabric_netlist_file_path_;
|
||||
std::string reference_benchmark_file_path_;
|
||||
bool fast_configuration_;
|
||||
|
|
|
@ -34,12 +34,11 @@ namespace openfpga {
|
|||
.out(out_postfix>)
|
||||
);
|
||||
*******************************************************************/
|
||||
void print_verilog_testbench_fpga_instance(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const std::string& top_instance_name,
|
||||
const std::string& net_postfix,
|
||||
const bool& explicit_port_mapping) {
|
||||
void print_verilog_testbench_fpga_instance(
|
||||
std::fstream& fp, const ModuleManager& module_manager,
|
||||
const ModuleId& top_module, const ModuleId& core_module,
|
||||
const std::string& top_instance_name, const std::string& net_postfix,
|
||||
const IoNameMap& io_name_map, const bool& explicit_port_mapping) {
|
||||
/* Validate the file stream */
|
||||
valid_file_stream(fp);
|
||||
|
||||
|
@ -47,8 +46,24 @@ void print_verilog_testbench_fpga_instance(std::fstream& fp,
|
|||
print_verilog_comment(
|
||||
fp, std::string("----- FPGA top-level module to be capsulated -----"));
|
||||
|
||||
/* Precheck on the top module and decide if we need to consider I/O naming
|
||||
* - If we do have a fpga_core module added, and dut is fpga_top, we need a
|
||||
* I/O naming
|
||||
* - If we do NOT have a fpga_core module added, and dut is fpga_top, we do
|
||||
* NOT need a I/O naming
|
||||
* - If we do have a fpga_core module added, and dut is fpga_core, we do NOT
|
||||
* need a I/O naming
|
||||
* - If we do NOT have a fpga_core module added, and dut is fpga_core, it
|
||||
* should error out earlier.
|
||||
*/
|
||||
bool require_io_naming = false;
|
||||
if (top_module != core_module) {
|
||||
require_io_naming = true;
|
||||
}
|
||||
|
||||
/* Create an empty port-to-port name mapping, because we use default names */
|
||||
std::map<std::string, BasicPort> port2port_name_map;
|
||||
if (!require_io_naming) {
|
||||
if (!net_postfix.empty()) {
|
||||
for (const ModulePortId& module_port_id :
|
||||
module_manager.module_ports(top_module)) {
|
||||
|
@ -59,6 +74,38 @@ void print_verilog_testbench_fpga_instance(std::fstream& fp,
|
|||
port2port_name_map[module_port.get_name()] = net_port;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
VTR_ASSERT_SAFE(require_io_naming);
|
||||
/* We walk through the ports under top module. Find renamed ports at
|
||||
* core-level and use them as net names */
|
||||
for (const ModulePortId& module_port_id :
|
||||
module_manager.module_ports(top_module)) {
|
||||
BasicPort module_port =
|
||||
module_manager.module_port(top_module, module_port_id);
|
||||
/* Bypass dummy port: the port does not exist at core module */
|
||||
if (io_name_map.fpga_top_port_is_dummy(module_port)) {
|
||||
ModulePortId core_module_port =
|
||||
module_manager.find_module_port(core_module, module_port.get_name());
|
||||
if (!module_manager.valid_module_port_id(core_module,
|
||||
core_module_port)) {
|
||||
/* Print the wire for the dummy port */
|
||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, module_port) << ";"
|
||||
<< std::endl;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/* Not a dummy port, if it is renamed, use the new name. Otherwise, keep
|
||||
* the old name */
|
||||
BasicPort net_port = io_name_map.fpga_core_port(module_port);
|
||||
if (net_port.is_valid()) {
|
||||
net_port.set_name(net_port.get_name() + net_postfix);
|
||||
} else {
|
||||
net_port = module_port;
|
||||
net_port.set_name(module_port.get_name() + net_postfix);
|
||||
}
|
||||
port2port_name_map[module_port.get_name()] = net_port;
|
||||
}
|
||||
}
|
||||
|
||||
/* Use explicit port mapping for a clean instanciation */
|
||||
print_verilog_module_instance(fp, module_manager, top_module,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "circuit_library.h"
|
||||
#include "fabric_global_port_info.h"
|
||||
#include "io_location_map.h"
|
||||
#include "io_name_map.h"
|
||||
#include "module_manager.h"
|
||||
#include "pin_constraints.h"
|
||||
#include "simulation_setting.h"
|
||||
|
@ -25,12 +26,11 @@
|
|||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
void print_verilog_testbench_fpga_instance(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const std::string& top_instance_name,
|
||||
const std::string& net_postfix,
|
||||
const bool& explicit_port_mapping);
|
||||
void print_verilog_testbench_fpga_instance(
|
||||
std::fstream& fp, const ModuleManager& module_manager,
|
||||
const ModuleId& top_module, const ModuleId& core_module,
|
||||
const std::string& top_instance_name, const std::string& net_postfix,
|
||||
const IoNameMap& io_name_map, const bool& explicit_port_mapping);
|
||||
|
||||
void print_verilog_testbench_benchmark_instance(
|
||||
std::fstream& fp, const std::string& module_name,
|
||||
|
|
|
@ -2435,7 +2435,7 @@ int print_verilog_full_testbench(
|
|||
const FabricGlobalPortInfo& global_ports, const AtomContext& atom_ctx,
|
||||
const PlacementContext& place_ctx, const PinConstraints& pin_constraints,
|
||||
const BusGroup& bus_group, const std::string& bitstream_file,
|
||||
const IoLocationMap& io_location_map,
|
||||
const IoLocationMap& io_location_map, const IoNameMap& io_name_map,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const std::string& circuit_name, const std::string& verilog_fname,
|
||||
const SimulationSetting& simulation_parameters,
|
||||
|
@ -2465,10 +2465,23 @@ int print_verilog_full_testbench(
|
|||
circuit_name;
|
||||
print_verilog_file_header(fp, title, options.time_stamp());
|
||||
|
||||
/* Find the top_module */
|
||||
ModuleId top_module =
|
||||
module_manager.find_module(generate_fpga_top_module_name());
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
|
||||
/* Spot the dut module */
|
||||
ModuleId top_module = module_manager.find_module(options.dut_module());
|
||||
if (!module_manager.valid_module_id(top_module)) {
|
||||
VTR_LOG_ERROR(
|
||||
"Unable to find the DUT module '%s'. Please check if you create "
|
||||
"dedicated module when building the fabric!\n",
|
||||
options.dut_module().c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
/* Note that we always need the core module as it contains the original port
|
||||
* names before possible renaming at top-level module. If there is no core
|
||||
* module, it means that the current top module is the core module */
|
||||
ModuleId core_module =
|
||||
module_manager.find_module(generate_fpga_core_module_name());
|
||||
if (!module_manager.valid_module_id(core_module)) {
|
||||
core_module = top_module;
|
||||
}
|
||||
|
||||
/* Preparation: find all the clock ports */
|
||||
std::vector<std::string> clock_port_names =
|
||||
|
@ -2492,7 +2505,7 @@ int print_verilog_full_testbench(
|
|||
|
||||
/* Start of testbench */
|
||||
print_verilog_top_testbench_ports(
|
||||
fp, module_manager, top_module, atom_ctx, netlist_annotation,
|
||||
fp, module_manager, core_module, atom_ctx, netlist_annotation,
|
||||
clock_port_names, global_ports, pin_constraints, simulation_parameters,
|
||||
config_protocol, circuit_name, options);
|
||||
|
||||
|
@ -2522,7 +2535,7 @@ int print_verilog_full_testbench(
|
|||
/* Generate stimuli for programming interface */
|
||||
int status = CMD_EXEC_SUCCESS;
|
||||
status = print_verilog_top_testbench_configuration_protocol_stimulus(
|
||||
fp, config_protocol, simulation_parameters, module_manager, top_module,
|
||||
fp, config_protocol, simulation_parameters, module_manager, core_module,
|
||||
fast_configuration, bit_value_to_skip, fabric_bitstream, blwl_sr_banks,
|
||||
prog_clock_period, VERILOG_SIM_TIMESCALE);
|
||||
|
||||
|
@ -2557,19 +2570,19 @@ int print_verilog_full_testbench(
|
|||
|
||||
/* Generate stimuli for global ports or connect them to existed signals */
|
||||
print_verilog_top_testbench_global_ports_stimuli(
|
||||
fp, module_manager, top_module, pin_constraints, config_protocol,
|
||||
fp, module_manager, core_module, pin_constraints, config_protocol,
|
||||
global_ports, simulation_parameters, active_global_prog_reset,
|
||||
active_global_prog_set);
|
||||
|
||||
/* Instanciate FPGA top-level module */
|
||||
print_verilog_testbench_fpga_instance(
|
||||
fp, module_manager, top_module,
|
||||
std::string(TOP_TESTBENCH_FPGA_INSTANCE_NAME), std::string(),
|
||||
fp, module_manager, top_module, core_module,
|
||||
std::string(TOP_TESTBENCH_FPGA_INSTANCE_NAME), std::string(), io_name_map,
|
||||
explicit_port_mapping);
|
||||
|
||||
/* Connect I/Os to benchmark I/Os or constant driver */
|
||||
print_verilog_testbench_connect_fpga_ios(
|
||||
fp, module_manager, top_module, atom_ctx, place_ctx, io_location_map,
|
||||
fp, module_manager, core_module, atom_ctx, place_ctx, io_location_map,
|
||||
netlist_annotation, BusGroup(), std::string(),
|
||||
std::string(TOP_TESTBENCH_SHARED_INPUT_POSTFIX),
|
||||
std::string(TOP_TESTBENCH_FPGA_OUTPUT_POSTFIX), clock_port_names,
|
||||
|
@ -2585,7 +2598,7 @@ int print_verilog_full_testbench(
|
|||
/* load bitstream to FPGA fabric in a configuration phase */
|
||||
print_verilog_full_testbench_bitstream(
|
||||
fp, bitstream_file, config_protocol, apply_fast_configuration,
|
||||
bit_value_to_skip, module_manager, top_module, bitstream_manager,
|
||||
bit_value_to_skip, module_manager, core_module, bitstream_manager,
|
||||
fabric_bitstream, blwl_sr_banks);
|
||||
|
||||
/* Add signal initialization:
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "fabric_bitstream.h"
|
||||
#include "fabric_global_port_info.h"
|
||||
#include "io_location_map.h"
|
||||
#include "io_name_map.h"
|
||||
#include "memory_bank_shift_register_banks.h"
|
||||
#include "module_manager.h"
|
||||
#include "pin_constraints.h"
|
||||
|
@ -38,7 +39,7 @@ int print_verilog_full_testbench(
|
|||
const FabricGlobalPortInfo& global_ports, const AtomContext& atom_ctx,
|
||||
const PlacementContext& place_ctx, const PinConstraints& pin_constraints,
|
||||
const BusGroup& bus_group, const std::string& bitstream_file,
|
||||
const IoLocationMap& io_location_map,
|
||||
const IoLocationMap& io_location_map, const IoNameMap& io_name_map,
|
||||
const VprNetlistAnnotation& netlist_annotation,
|
||||
const std::string& circuit_name, const std::string& verilog_fname,
|
||||
const SimulationSetting& simulation_parameters,
|
||||
|
|
|
@ -74,10 +74,16 @@ bool port_is_fabric_global_reset_port(
|
|||
const FabricGlobalPortInfo& fabric_global_port_info,
|
||||
const ModuleManager& module_manager, const BasicPort& port) {
|
||||
/* Find the top_module: the fabric global ports are always part of the ports
|
||||
* of the top module */
|
||||
* of the top/core module. If there is a core module, we should consider core
|
||||
* only */
|
||||
ModuleId top_module =
|
||||
module_manager.find_module(generate_fpga_top_module_name());
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
|
||||
ModuleId core_module =
|
||||
module_manager.find_module(generate_fpga_core_module_name());
|
||||
if (module_manager.valid_module_id(core_module)) {
|
||||
top_module = core_module;
|
||||
}
|
||||
|
||||
for (const FabricGlobalPortId& fabric_global_port_id :
|
||||
fabric_global_port_info.global_ports()) {
|
||||
|
@ -107,10 +113,16 @@ FabricGlobalPortId find_fabric_global_port(
|
|||
const FabricGlobalPortInfo& fabric_global_port_info,
|
||||
const ModuleManager& module_manager, const BasicPort& port) {
|
||||
/* Find the top_module: the fabric global ports are always part of the ports
|
||||
* of the top module */
|
||||
* of the top/core module. If there is a core module, we should consider core
|
||||
* only */
|
||||
ModuleId top_module =
|
||||
module_manager.find_module(generate_fpga_top_module_name());
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(top_module));
|
||||
ModuleId core_module =
|
||||
module_manager.find_module(generate_fpga_core_module_name());
|
||||
if (module_manager.valid_module_id(core_module)) {
|
||||
top_module = core_module;
|
||||
}
|
||||
|
||||
for (const FabricGlobalPortId& fabric_global_port_id :
|
||||
fabric_global_port_info.global_ports()) {
|
||||
|
|
|
@ -23,7 +23,7 @@ lut_truth_table_fixup
|
|||
# - Enable pin duplication on grid modules
|
||||
build_fabric --compress_routing #--verbose
|
||||
# Add a fpga core between fpga top and the underlying modules
|
||||
add_fpga_core_to_fabric --instance_name fpga_core_inst --verbose
|
||||
add_fpga_core_to_fabric ${OPENFPGA_WRAPPER_IO_NAMING_RULES} --instance_name fpga_core_inst --verbose
|
||||
|
||||
# Write the fabric hierarchy of module graph to a file
|
||||
# This is used by hierarchical PnR flows
|
||||
|
@ -54,8 +54,8 @@ write_fabric_verilog --file ./SRC --explicit_port_mapping --include_timing --pri
|
|||
# - 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_preconfigured_fabric_wrapper --embed_bitstream iverilog --file ./SRC --explicit_port_mapping
|
||||
write_full_testbench ${OPENFPGA_TESTBENCH_DUT_MODULE} --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} --explicit_port_mapping --include_signal_init --bitstream fabric_bitstream.bit
|
||||
write_preconfigured_fabric_wrapper ${OPENFPGA_TESTBENCH_DUT_MODULE} --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
|
||||
|
|
|
@ -22,6 +22,7 @@ lut_truth_table_fixup
|
|||
# - Enabled compression on routing architecture modules
|
||||
# - Enable pin duplication on grid modules
|
||||
build_fabric --compress_routing #--verbose
|
||||
${OPENFPGA_MOCK_WRAPPER_ADD_FPGA_CORE}
|
||||
|
||||
# Write the fabric hierarchy of module graph to a file
|
||||
# This is used by hierarchical PnR flows
|
||||
|
|
|
@ -23,7 +23,7 @@ lut_truth_table_fixup
|
|||
# - Enable pin duplication on grid modules
|
||||
build_fabric --compress_routing #--verbose
|
||||
# Add a fpga core between fpga top and the underlying modules
|
||||
add_fpga_core_to_fabric --instance_name fpga_core_inst --verbose
|
||||
add_fpga_core_to_fabric ${OPENFPGA_WRAPPER_IO_NAMING_RULES} --instance_name fpga_core_inst --verbose
|
||||
|
||||
# Write the fabric hierarchy of module graph to a file
|
||||
# This is used by hierarchical PnR flows
|
||||
|
@ -54,7 +54,7 @@ write_fabric_verilog --file ./SRC --explicit_port_mapping --include_timing --pri
|
|||
# - 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} --include_signal_init --explicit_port_mapping --bitstream fabric_bitstream.bit ${OPENFPGA_FAST_CONFIGURATION}
|
||||
write_full_testbench ${OPENFPGA_TESTBENCH_DUT_MODULE} --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} --include_signal_init --explicit_port_mapping --bitstream fabric_bitstream.bit ${OPENFPGA_FAST_CONFIGURATION}
|
||||
|
||||
# Write the SDC files for PnR backend
|
||||
# - Turn on every options here
|
||||
|
|
|
@ -17,7 +17,11 @@ run-task basic_tests/source_command/source_file $@
|
|||
|
||||
echo -e "Testing testbenches using fpga core wrapper"
|
||||
run-task basic_tests/full_testbench/fpga_core_wrapper $@
|
||||
run-task basic_tests/full_testbench/fpga_core_wrapper_naming_rules $@
|
||||
run-task basic_tests/full_testbench/fpga_core_wrapper_naming_rules_use_core_tb $@
|
||||
run-task basic_tests/preconfig_testbench/fpga_core_wrapper $@
|
||||
run-task basic_tests/preconfig_testbench/fpga_core_wrapper_naming_rules $@
|
||||
run-task basic_tests/preconfig_testbench/fpga_core_wrapper_naming_rules_use_core_tb $@
|
||||
|
||||
echo -e "Testing configuration chain of a K4N4 FPGA";
|
||||
run-task basic_tests/full_testbench/configuration_chain $@
|
||||
|
|
|
@ -21,6 +21,8 @@ openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_
|
|||
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
|
||||
openfpga_vpr_device_layout=
|
||||
openfpga_fast_configuration=
|
||||
openfpga_wrapper_io_naming_rules=
|
||||
openfpga_testbench_dut_module=
|
||||
|
||||
[ARCHITECTURES]
|
||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml
|
||||
|
@ -33,13 +35,10 @@ bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch
|
|||
[SYNTHESIS_PARAM]
|
||||
bench_read_verilog_options_common = -nolatches
|
||||
bench0_top = and2
|
||||
bench0_chan_width = 300
|
||||
|
||||
bench1_top = or2
|
||||
bench1_chan_width = 300
|
||||
|
||||
bench2_top = and2_latch
|
||||
bench2_chan_width = 300
|
||||
|
||||
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||
end_flow_with_test=
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
# 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/write_full_testbench_fpga_core_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_vpr_device_layout=
|
||||
openfpga_fast_configuration=
|
||||
openfpga_wrapper_io_naming_rules=--io_naming ${PATH:TASK_DIR}/config/wrapper_io_naming.xml
|
||||
openfpga_testbench_dut_module=
|
||||
|
||||
[ARCHITECTURES]
|
||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml
|
||||
|
||||
[BENCHMARKS]
|
||||
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
|
||||
bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/or2/or2.v
|
||||
bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch/and2_latch.v
|
||||
|
||||
[SYNTHESIS_PARAM]
|
||||
bench_read_verilog_options_common = -nolatches
|
||||
bench0_top = and2
|
||||
|
||||
bench1_top = or2
|
||||
|
||||
bench2_top = and2_latch
|
||||
|
||||
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||
end_flow_with_test=
|
|
@ -0,0 +1,11 @@
|
|||
<ports>
|
||||
<port top_name="pclk" core_name="prog_clk"/>
|
||||
<port top_name="top_io[0:7]" core_name="gfpga_pad_GPIO_PAD[0:7]"/>
|
||||
<port top_name="right_ioA[0:3]" core_name="gfpga_pad_GPIO_PAD[8:11]"/>
|
||||
<port top_name="right_ioB[0:3]" core_name="gfpga_pad_GPIO_PAD[12:15]"/>
|
||||
<port top_name="bottom_io[0:7]" core_name="gfpga_pad_GPIO_PAD[16:23]"/>
|
||||
<port top_name="left_io[0:7]" core_name="gfpga_pad_GPIO_PAD[24:31]"/>
|
||||
<port top_name="config_head" core_name="ccff_head"/>
|
||||
<port top_name="config_tail" core_name="ccff_tail"/>
|
||||
<port top_name="pvt_sensor" is_dummy="true" direction="input"/>
|
||||
</ports>
|
|
@ -0,0 +1,44 @@
|
|||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
# 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/write_full_testbench_fpga_core_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_vpr_device_layout=
|
||||
openfpga_fast_configuration=
|
||||
openfpga_wrapper_io_naming_rules=--io_naming ${PATH:TASK_DIR}/config/wrapper_io_naming.xml
|
||||
openfpga_testbench_dut_module=--dut_module fpga_core
|
||||
|
||||
[ARCHITECTURES]
|
||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml
|
||||
|
||||
[BENCHMARKS]
|
||||
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
|
||||
bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/or2/or2.v
|
||||
bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch/and2_latch.v
|
||||
|
||||
[SYNTHESIS_PARAM]
|
||||
bench_read_verilog_options_common = -nolatches
|
||||
bench0_top = and2
|
||||
|
||||
bench1_top = or2
|
||||
|
||||
bench2_top = and2_latch
|
||||
|
||||
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||
end_flow_with_test=
|
|
@ -0,0 +1,11 @@
|
|||
<ports>
|
||||
<port top_name="pclk" core_name="prog_clk"/>
|
||||
<port top_name="top_io[0:7]" core_name="gfpga_pad_GPIO_PAD[0:7]"/>
|
||||
<port top_name="right_ioA[0:3]" core_name="gfpga_pad_GPIO_PAD[8:11]"/>
|
||||
<port top_name="right_ioB[0:3]" core_name="gfpga_pad_GPIO_PAD[12:15]"/>
|
||||
<port top_name="bottom_io[0:7]" core_name="gfpga_pad_GPIO_PAD[16:23]"/>
|
||||
<port top_name="left_io[0:7]" core_name="gfpga_pad_GPIO_PAD[24:31]"/>
|
||||
<port top_name="config_head" core_name="ccff_head"/>
|
||||
<port top_name="config_tail" core_name="ccff_tail"/>
|
||||
<port top_name="pvt_sensor" is_dummy="true" direction="input"/>
|
||||
</ports>
|
|
@ -23,6 +23,7 @@ openfpga_repack_design_constraints=
|
|||
openfpga_mock_wrapper_options=--explicit_port_mapping
|
||||
openfpga_mock_wrapper_bgf=
|
||||
openfpga_mock_wrapper_pcf=
|
||||
openfpga_mock_wrapper_add_fpga_core=
|
||||
|
||||
[ARCHITECTURES]
|
||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm.xml
|
||||
|
|
|
@ -23,6 +23,7 @@ openfpga_repack_design_constraints=
|
|||
openfpga_mock_wrapper_options=--explicit_port_mapping
|
||||
openfpga_mock_wrapper_bgf=
|
||||
openfpga_mock_wrapper_pcf=
|
||||
openfpga_mock_wrapper_add_fpga_core=
|
||||
|
||||
[ARCHITECTURES]
|
||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
<bus_group>
|
||||
<bus name="result[7:0]" big_endian="false">
|
||||
<pin id="0" name="result_0_"/>
|
||||
<pin id="1" name="result_1_"/>
|
||||
<pin id="2" name="result_2_"/>
|
||||
<pin id="3" name="result_3_"/>
|
||||
<pin id="4" name="result_4_"/>
|
||||
<pin id="5" name="result_5_"/>
|
||||
<pin id="6" name="result_6_"/>
|
||||
<pin id="7" name="result_7_"/>
|
||||
</bus>
|
||||
</bus_group>
|
|
@ -0,0 +1,7 @@
|
|||
<pin_constraints>
|
||||
<!-- For a given .blif file, we want to assign
|
||||
- the reset signal to the op_reset[0] port of the FPGA fabric
|
||||
-->
|
||||
<set_io pin="op_reset[0]" net="reset"/>
|
||||
</pin_constraints>
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
# 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 = false
|
||||
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/mock_wrapper_example_script.openfpga
|
||||
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_dpram8K_dsp36_fracff_40nm_openfpga.xml
|
||||
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml
|
||||
openfpga_repack_design_constraints=
|
||||
openfpga_mock_wrapper_options=--explicit_port_mapping
|
||||
openfpga_mock_wrapper_bgf=
|
||||
openfpga_mock_wrapper_pcf=
|
||||
openfpga_mock_wrapper_add_fpga_core=add_fpga_core_to_fabric --io_naming ${PATH:TASK_DIR}/config/wrapper_io_naming.xml
|
||||
|
||||
[ARCHITECTURES]
|
||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm.xml
|
||||
|
||||
[BENCHMARKS]
|
||||
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/counters/counter_8bit_async_reset/counter.v
|
||||
|
||||
[SYNTHESIS_PARAM]
|
||||
# Yosys script parameters
|
||||
bench_yosys_cell_sim_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm_cell_sim.v
|
||||
bench_yosys_dff_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_fracff_40nm_dff_map.v
|
||||
bench_yosys_bram_map_rules_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_bram.txt
|
||||
bench_yosys_bram_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_bram_map.v
|
||||
bench_yosys_dsp_map_verilog_common=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_yosys_techlib/k6_frac_N10_tileable_adder_chain_dpram8K_dsp36_40nm_dsp_map.v
|
||||
bench_yosys_dsp_map_parameters_common=-D DSP_A_MAXWIDTH=36 -D DSP_B_MAXWIDTH=36 -D DSP_A_MINWIDTH=2 -D DSP_B_MINWIDTH=2 -D DSP_NAME=mult_36x36
|
||||
bench_read_verilog_options_common = -nolatches
|
||||
bench_yosys_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_dff_flow.ys
|
||||
bench_yosys_rewrite_common=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/ys_tmpl_yosys_vpr_flow_with_rewrite.ys
|
||||
|
||||
bench0_top = counter
|
||||
bench0_openfpga_mock_wrapper_pcf=-pcf ${PATH:TASK_DIR}/config/pin_constraints_reset.xml
|
||||
bench0_openfpga_mock_wrapper_bgf=-bgf ${PATH:TASK_DIR}/config/counter8_bus_group.xml
|
||||
|
||||
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||
end_flow_with_test=
|
||||
vpr_fpga_verilog_formal_verification_top_netlist=
|
|
@ -0,0 +1,11 @@
|
|||
<ports>
|
||||
<port top_name="pclk" core_name="prog_clk"/>
|
||||
<port top_name="top_io[0:7]" core_name="gfpga_pad_GPIO_PAD[0:7]"/>
|
||||
<port top_name="right_ioA[0:3]" core_name="gfpga_pad_GPIO_PAD[8:11]"/>
|
||||
<port top_name="right_ioB[0:3]" core_name="gfpga_pad_GPIO_PAD[12:15]"/>
|
||||
<port top_name="bottom_io[0:7]" core_name="gfpga_pad_GPIO_PAD[16:23]"/>
|
||||
<port top_name="left_io[0:7]" core_name="gfpga_pad_GPIO_PAD[24:31]"/>
|
||||
<port top_name="config_head" core_name="ccff_head"/>
|
||||
<port top_name="config_tail" core_name="ccff_tail"/>
|
||||
<port top_name="pvt_sensor" is_dummy="true" direction="input"/>
|
||||
</ports>
|
|
@ -23,6 +23,7 @@ openfpga_repack_design_constraints=
|
|||
openfpga_mock_wrapper_options=
|
||||
openfpga_mock_wrapper_bgf=
|
||||
openfpga_mock_wrapper_pcf=
|
||||
openfpga_mock_wrapper_add_fpga_core=
|
||||
|
||||
[ARCHITECTURES]
|
||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml
|
||||
|
|
|
@ -23,6 +23,7 @@ openfpga_repack_design_constraints=--design_constraints ${PATH:TASK_DIR}/config/
|
|||
openfpga_mock_wrapper_options=
|
||||
openfpga_mock_wrapper_bgf=
|
||||
openfpga_mock_wrapper_pcf=
|
||||
openfpga_mock_wrapper_add_fpga_core=
|
||||
|
||||
[ARCHITECTURES]
|
||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_GlobalTile4Clk_40nm.xml
|
||||
|
|
|
@ -19,6 +19,8 @@ fpga_flow=yosys_vpr
|
|||
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/fpga_core_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_wrapper_io_naming_rules=
|
||||
openfpga_testbench_dut_module=
|
||||
|
||||
[ARCHITECTURES]
|
||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml
|
||||
|
@ -31,13 +33,10 @@ bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch
|
|||
[SYNTHESIS_PARAM]
|
||||
bench_read_verilog_options_common = -nolatches
|
||||
bench0_top = and2
|
||||
bench0_chan_width = 300
|
||||
|
||||
bench1_top = or2
|
||||
bench1_chan_width = 300
|
||||
|
||||
bench2_top = and2_latch
|
||||
bench2_chan_width = 300
|
||||
|
||||
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||
end_flow_with_test=
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
# 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/fpga_core_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_wrapper_io_naming_rules=--io_naming ${PATH:TASK_DIR}/config/wrapper_io_naming.xml
|
||||
openfpga_testbench_dut_module=
|
||||
|
||||
[ARCHITECTURES]
|
||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml
|
||||
|
||||
[BENCHMARKS]
|
||||
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
|
||||
bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/or2/or2.v
|
||||
bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch/and2_latch.v
|
||||
|
||||
[SYNTHESIS_PARAM]
|
||||
bench_read_verilog_options_common = -nolatches
|
||||
bench0_top = and2
|
||||
|
||||
bench1_top = or2
|
||||
|
||||
bench2_top = and2_latch
|
||||
|
||||
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||
end_flow_with_test=
|
||||
vpr_fpga_verilog_formal_verification_top_netlist=
|
|
@ -0,0 +1,11 @@
|
|||
<ports>
|
||||
<port top_name="pclk" core_name="prog_clk"/>
|
||||
<port top_name="top_io[0:7]" core_name="gfpga_pad_GPIO_PAD[0:7]"/>
|
||||
<port top_name="right_ioA[0:3]" core_name="gfpga_pad_GPIO_PAD[8:11]"/>
|
||||
<port top_name="right_ioB[0:3]" core_name="gfpga_pad_GPIO_PAD[12:15]"/>
|
||||
<port top_name="bottom_io[0:7]" core_name="gfpga_pad_GPIO_PAD[16:23]"/>
|
||||
<port top_name="left_io[0:7]" core_name="gfpga_pad_GPIO_PAD[24:31]"/>
|
||||
<port top_name="config_head" core_name="ccff_head"/>
|
||||
<port top_name="config_tail" core_name="ccff_tail"/>
|
||||
<port top_name="pvt_sensor" is_dummy="true" direction="input"/>
|
||||
</ports>
|
|
@ -0,0 +1,43 @@
|
|||
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||
# 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/fpga_core_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_wrapper_io_naming_rules=--io_naming ${PATH:TASK_DIR}/config/wrapper_io_naming.xml
|
||||
openfpga_testbench_dut_module= --dut_module fpga_core
|
||||
|
||||
[ARCHITECTURES]
|
||||
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml
|
||||
|
||||
[BENCHMARKS]
|
||||
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
|
||||
bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/or2/or2.v
|
||||
bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch/and2_latch.v
|
||||
|
||||
[SYNTHESIS_PARAM]
|
||||
bench_read_verilog_options_common = -nolatches
|
||||
bench0_top = and2
|
||||
|
||||
bench1_top = or2
|
||||
|
||||
bench2_top = and2_latch
|
||||
|
||||
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||
end_flow_with_test=
|
||||
vpr_fpga_verilog_formal_verification_top_netlist=
|
|
@ -0,0 +1,11 @@
|
|||
<ports>
|
||||
<port top_name="pclk" core_name="prog_clk"/>
|
||||
<port top_name="top_io[0:7]" core_name="gfpga_pad_GPIO_PAD[0:7]"/>
|
||||
<port top_name="right_ioA[0:3]" core_name="gfpga_pad_GPIO_PAD[8:11]"/>
|
||||
<port top_name="right_ioB[0:3]" core_name="gfpga_pad_GPIO_PAD[12:15]"/>
|
||||
<port top_name="bottom_io[0:7]" core_name="gfpga_pad_GPIO_PAD[16:23]"/>
|
||||
<port top_name="left_io[0:7]" core_name="gfpga_pad_GPIO_PAD[24:31]"/>
|
||||
<port top_name="config_head" core_name="ccff_head"/>
|
||||
<port top_name="config_tail" core_name="ccff_tail"/>
|
||||
<port top_name="pvt_sensor" is_dummy="true" direction="input"/>
|
||||
</ports>
|
Loading…
Reference in New Issue