Merge pull request #1247 from lnis-uofu/xt_fabric_subkey

Now Fabric Key Supports Sub-modules
This commit is contained in:
tangxifan 2023-07-13 19:27:26 -07:00 committed by GitHub
commit 8cac776b28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 2335 additions and 923 deletions

View File

@ -5,6 +5,19 @@ Fabric Key (.xml)
A fabric key follows an XML format. As shown in the following XML code, the key file includes the organization of configurable blocks in the top-level FPGA fabric.
Configurable Module
^^^^^^^^^^^^^^^^^^^
Fabric key can be applied to various modules. Each module can be a top-level FPGA fabric, or a submodule of the FPGA fabric.
.. option:: <module name="<string>"/>
Under each module, a set of keys can be defined. Note that for the top-level FPGA fabric, not only keys but also regions and shift-register banks can be defined. For non-top-level module, only keys are allowed.
- ``name`` indicates the unique name of a valid module in FPGA fabric. Note that ``fpga_top`` is the considered as the module name of the top-level FPGA fabric.
.. note:: ``fpga_core`` is not applicable to fabric key.
Configurable Region
^^^^^^^^^^^^^^^^^^^
@ -23,6 +36,7 @@ The following example shows how to define multiple configuration regions in the
.. code-block:: xml
<fabric_key>
<module name="fpga_top">
<region id="0">
<bl_shift_register_banks>
<bank id="0" range="bl[0:24]"/>
@ -77,6 +91,7 @@ The following example shows how to define multiple configuration regions in the
<key id="11" name="cby_1__1_" value="0" alias="cby_1__1_"/>
<key id="12" name="grid_clb" value="0" alias="grid_clb_1__1_"/>
</region>
</module>
</fabric_key>
@ -111,6 +126,7 @@ This key contains only ``alias`` which is easy to craft.
.. code-block:: xml
<fabric_key>
<module name="fpga_top">
<region id="0">
<key id="0" alias="sb_2__2_"/>
<key id="1" alias="grid_clb_2_2"/>
@ -146,6 +162,7 @@ This key contains only ``alias`` which is easy to craft.
<key id="31" alias="grid_io_top_1_3"/>
<key id="32" alias="grid_io_left_0_2"/>
</region>
</module>
</fabric_key>
The following shows another example of a fabric key generate by OpenFPGA for a 2 :math:`\times` 2 FPGA.
@ -154,6 +171,7 @@ This key contains only ``name`` and ``value`` which is fast to parse.
.. code-block:: xml
<fabric_key>
<module name="fpga_top">
<region id="0">
<key id="0" name="sb_2__2_" value="0"/>
<key id="1" name="grid_clb" value="3"/>
@ -189,6 +207,7 @@ This key contains only ``name`` and ``value`` which is fast to parse.
<key id="31" name="grid_io_top" value="0"/>
<key id="32" name="grid_io_left" value="1"/>
</region>
</module>
</fabric_key>
The following shows another example of a fabric key generate by OpenFPGA for a 2 :math:`\times` 2 FPGA using memory bank.
@ -197,6 +216,7 @@ This key contains only ``name``, ``value``, ``row`` and ``column``.
.. code-block:: xml
<fabric_key>
<module name="fpga_top">
<region id="0">
<key id="0" name="sb_2__2_" value="0" alias="sb_2__2_" column="5" row="5"/>
<key id="1" name="grid_clb" value="3" alias="grid_clb_2__2_" column="4" row="4"/>
@ -232,6 +252,7 @@ This key contains only ``name``, ``value``, ``row`` and ``column``.
<key id="31" name="grid_io_top" value="0" alias="grid_io_top_1__3_" column="2" row="6"/>
<key id="32" name="grid_io_left" value="1" alias="grid_io_left_0__2_" column="0" row="4"/>
</region>
</module>
</fabric_key>
BL Shift Register Banks

View File

@ -269,6 +269,8 @@ build_fabric
Output current fabric key to an XML file. For example, ``--write_fabric_key fpga_2x2.xml`` See details in :ref:`file_formats_fabric_key`.
.. warning:: This option will be deprecated. Use :ref:`cmd_write_fabric_key` as a replacement.
.. 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.
@ -281,6 +283,27 @@ build_fabric
.. note:: This is a must-run command before launching FPGA-Verilog, FPGA-Bitstream, FPGA-SDC and FPGA-SPICE
.. _cmd_write_fabric_key:
write_fabric_key
~~~~~~~~~~~~~~~~
Output current fabric key to an XML file. For example, ``write_fabric_key --file fpga_2x2.xml`` See details in :ref:`file_formats_fabric_key`.
.. note:: This command can output module-level keys while the ``--write_fabric_key`` option in command ``build_fabric`` does NOT support! Strongly recommend to use this command to obtain fabric key.
.. option:: --file <string> or -f <string>
Specify the file name. For example, ``--file fabric_key_echo.xml``.
.. option:: --include_module_keys
Output module-level keys to the file.
.. option:: --verbose
Show verbose log
.. _cmd_add_fpga_core_to_fabric:
add_fpga_core_to_fabric

View File

@ -3,8 +3,8 @@ cmake_minimum_required(VERSION 3.9)
project("libfabrickey")
file(GLOB_RECURSE EXEC_SOURCES test/*.cpp)
file(GLOB_RECURSE LIB_SOURCES src/*.cpp)
file(GLOB_RECURSE LIB_HEADERS src/*.h)
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

View File

@ -1,4 +1,5 @@
<fabric_key>
<module name="fpga_top">
<region id="0">
<key id="0" name="sb" value="0"/>
<key id="2" name="cb" value="10"/>
@ -6,4 +7,5 @@
<key id="3" name="clb" value="53"/>
<key id="4" name="bram" value="32"/>
</region>
</module>
</fabric_key>

View File

@ -5,6 +5,8 @@
#include "vtr_assert.h"
#include "vtr_log.h"
namespace openfpga { // Begin namespace openfpga
/************************************************************************
* Member functions for class FabricKey
***********************************************************************/
@ -39,6 +41,17 @@ FabricKey::fabric_word_line_bank_range FabricKey::wl_banks(
wl_bank_ids_[region_id].end());
}
FabricKey::fabric_key_module_range FabricKey::modules() const {
return vtr::make_range(sub_key_module_ids_.begin(),
sub_key_module_ids_.end());
}
std::vector<FabricSubKeyId> FabricKey::sub_keys(
const FabricKeyModuleId& module_id) const {
VTR_ASSERT(valid_module_id(module_id));
return module_sub_keys_[module_id];
}
/************************************************************************
* Public Accessors : Basic data query
***********************************************************************/
@ -87,6 +100,29 @@ std::vector<openfpga::BasicPort> FabricKey::wl_bank_data_ports(
return wl_bank_data_ports_[region_id][bank_id];
}
std::string FabricKey::module_name(const FabricKeyModuleId& module_id) const {
VTR_ASSERT(valid_module_id(module_id));
return sub_key_module_names_[module_id];
}
std::string FabricKey::sub_key_name(const FabricSubKeyId& key_id) const {
/* validate the key_id */
VTR_ASSERT(valid_sub_key_id(key_id));
return sub_key_names_[key_id];
}
size_t FabricKey::sub_key_value(const FabricSubKeyId& key_id) const {
/* validate the key_id */
VTR_ASSERT(valid_sub_key_id(key_id));
return sub_key_values_[key_id];
}
std::string FabricKey::sub_key_alias(const FabricSubKeyId& key_id) const {
/* validate the key_id */
VTR_ASSERT(valid_sub_key_id(key_id));
return sub_key_alias_[key_id];
}
/************************************************************************
* Public Mutators
***********************************************************************/
@ -263,6 +299,70 @@ void FabricKey::add_data_port_to_wl_shift_register_bank(
wl_bank_data_ports_[region_id][bank_id].push_back(data_port);
}
void FabricKey::reserve_modules(const size_t& num_modules) {
sub_key_module_ids_.reserve(num_modules);
sub_key_module_names_.reserve(num_modules);
module_sub_keys_.reserve(num_modules);
}
void FabricKey::reserve_module_keys(const FabricKeyModuleId& module_id,
const size_t& num_keys) {
VTR_ASSERT(valid_module_id(module_id));
module_sub_keys_[module_id].reserve(num_keys);
sub_key_ids_.reserve(sub_key_ids_.size() + num_keys);
sub_key_names_.reserve(sub_key_names_.size() + num_keys);
sub_key_values_.reserve(sub_key_values_.size() + num_keys);
sub_key_alias_.reserve(sub_key_alias_.size() + num_keys);
}
FabricKeyModuleId FabricKey::create_module(const std::string& name) {
/* Ensure name is not duplicated */
auto result = module2subkey_lookup_.find(name);
if (result != module2subkey_lookup_.end()) {
return FabricKeyModuleId::INVALID(); /* Return an invalid id */
}
/* Create a new id */
FabricKeyModuleId module_id = FabricKeyModuleId(sub_key_module_ids_.size());
sub_key_module_ids_.push_back(module_id);
sub_key_module_names_.push_back(name);
module_sub_keys_.emplace_back();
/* Register in lookup */
module2subkey_lookup_[name] = module_id;
return module_id;
}
FabricSubKeyId FabricKey::create_module_key(
const FabricKeyModuleId& module_id) {
VTR_ASSERT(valid_module_id(module_id));
/* Create a new id */
FabricSubKeyId key_id = FabricSubKeyId(sub_key_ids_.size());
sub_key_ids_.push_back(key_id);
sub_key_names_.emplace_back();
sub_key_values_.emplace_back();
sub_key_alias_.emplace_back();
/* Add the new id to module */
module_sub_keys_[module_id].emplace_back(key_id);
return key_id;
}
void FabricKey::set_sub_key_name(const FabricSubKeyId& key_id,
const std::string& name) {
VTR_ASSERT(valid_sub_key_id(key_id));
sub_key_names_[key_id] = name;
}
void FabricKey::set_sub_key_value(const FabricSubKeyId& key_id,
const size_t& value) {
VTR_ASSERT(valid_sub_key_id(key_id));
sub_key_values_[key_id] = value;
}
void FabricKey::set_sub_key_alias(const FabricSubKeyId& key_id,
const std::string& alias) {
VTR_ASSERT(valid_sub_key_id(key_id));
sub_key_alias_[key_id] = alias;
}
/************************************************************************
* Internal invalidators/validators
***********************************************************************/
@ -297,3 +397,15 @@ bool FabricKey::valid_wl_bank_id(const FabricRegionId& region_id,
return (size_t(bank_id) < wl_bank_ids_[region_id].size()) &&
(bank_id == wl_bank_ids_[region_id][bank_id]);
}
bool FabricKey::valid_module_id(const FabricKeyModuleId& module_id) const {
return (size_t(module_id) < sub_key_module_ids_.size()) &&
(module_id == sub_key_module_ids_[module_id]);
}
bool FabricKey::valid_sub_key_id(const FabricSubKeyId& sub_key_id) const {
return (size_t(sub_key_id) < sub_key_ids_.size()) &&
(sub_key_id == sub_key_ids_[sub_key_id]);
}
} // End of namespace openfpga

View File

@ -16,6 +16,8 @@
#include "fabric_key_fwd.h"
#include "openfpga_port.h"
namespace openfpga { // Begin namespace openfpga
/********************************************************************
* A data structure to describe a secure key for fabric organization
* A fabric may consist of multiple regions
@ -47,12 +49,18 @@ class FabricKey {
typedef vtr::vector<FabricWordLineBankId,
FabricWordLineBankId>::const_iterator
fabric_word_line_bank_iterator;
typedef vtr::vector<FabricSubKeyId, FabricSubKeyId>::const_iterator
fabric_sub_key_iterator;
typedef vtr::vector<FabricKeyModuleId, FabricKeyModuleId>::const_iterator
fabric_key_module_iterator;
/* Create range */
typedef vtr::Range<fabric_region_iterator> fabric_region_range;
typedef vtr::Range<fabric_key_iterator> fabric_key_range;
typedef vtr::Range<fabric_bit_line_bank_iterator> fabric_bit_line_bank_range;
typedef vtr::Range<fabric_word_line_bank_iterator>
fabric_word_line_bank_range;
typedef vtr::Range<fabric_sub_key_iterator> fabric_sub_key_range;
typedef vtr::Range<fabric_key_module_iterator> fabric_key_module_range;
public: /* Constructors */
FabricKey();
@ -62,20 +70,19 @@ class FabricKey {
fabric_region_range regions() const;
fabric_bit_line_bank_range bl_banks(const FabricRegionId& region_id) const;
fabric_word_line_bank_range wl_banks(const FabricRegionId& region_id) const;
fabric_key_module_range modules() const;
std::vector<FabricSubKeyId> sub_keys(
const FabricKeyModuleId& module_id) const;
public: /* Public Accessors: Basic data query */
/* Access all the keys of a region */
std::vector<FabricKeyId> region_keys(const FabricRegionId& region_id) const;
/* Access the name of a key */
std::string key_name(const FabricKeyId& key_id) const;
/* Access the value of a key */
size_t key_value(const FabricKeyId& key_id) const;
/* Access the alias of a key */
std::string key_alias(const FabricKeyId& key_id) const;
/* Access the coordinate of a key */
vtr::Point<int> key_coordinate(const FabricKeyId& key_id) const;
@ -84,14 +91,19 @@ class FabricKey {
/* Return a list of data ports which will be driven by a BL shift register
* bank */
std::vector<openfpga::BasicPort> bl_bank_data_ports(
std::vector<BasicPort> bl_bank_data_ports(
const FabricRegionId& region_id, const FabricBitLineBankId& bank_id) const;
/* Return a list of data ports which will be driven by a WL shift register
* bank */
std::vector<openfpga::BasicPort> wl_bank_data_ports(
std::vector<BasicPort> wl_bank_data_ports(
const FabricRegionId& region_id, const FabricWordLineBankId& bank_id) const;
std::string module_name(const FabricKeyModuleId& module_id) const;
std::string sub_key_name(const FabricSubKeyId& key_id) const;
size_t sub_key_value(const FabricSubKeyId& key_id) const;
std::string sub_key_alias(const FabricSubKeyId& key_id) const;
public: /* Public Mutators: model-related */
/* Reserve a number of regions to be memory efficent */
void reserve_regions(const size_t& num_regions);
@ -115,11 +127,8 @@ class FabricKey {
/* Configure attributes of a key */
void set_key_name(const FabricKeyId& key_id, const std::string& name);
void set_key_value(const FabricKeyId& key_id, const size_t& value);
void set_key_alias(const FabricKeyId& key_id, const std::string& alias);
void set_key_coordinate(const FabricKeyId& key_id,
const vtr::Point<int>& coord);
@ -136,7 +145,7 @@ class FabricKey {
/* Add a data port to a given BL shift register bank */
void add_data_port_to_bl_shift_register_bank(
const FabricRegionId& region_id, const FabricBitLineBankId& bank_id,
const openfpga::BasicPort& data_port);
const BasicPort& data_port);
/* Create a new shift register bank for WLs and return an id */
FabricWordLineBankId create_wl_shift_register_bank(
@ -145,7 +154,20 @@ class FabricKey {
/* Add a data port to a given WL shift register bank */
void add_data_port_to_wl_shift_register_bank(
const FabricRegionId& region_id, const FabricWordLineBankId& bank_id,
const openfpga::BasicPort& data_port);
const BasicPort& data_port);
/* Reserve a number of keys to be memory efficent */
void reserve_modules(const size_t& num_modules);
void reserve_module_keys(const FabricKeyModuleId& module_id,
const size_t& num_keys);
/* Create a new key and add it to the library, return an id */
FabricKeyModuleId create_module(const std::string& name);
FabricSubKeyId create_module_key(const FabricKeyModuleId& module_id);
/* Configure attributes of a sub key */
void set_sub_key_name(const FabricSubKeyId& key_id, const std::string& name);
void set_sub_key_value(const FabricSubKeyId& key_id, const size_t& value);
void set_sub_key_alias(const FabricSubKeyId& key_id,
const std::string& alias);
public: /* Public invalidators/validators */
bool valid_region_id(const FabricRegionId& region_id) const;
@ -156,29 +178,26 @@ class FabricKey {
const FabricBitLineBankId& bank_id) const;
bool valid_wl_bank_id(const FabricRegionId& region_id,
const FabricWordLineBankId& bank_id) const;
bool valid_module_id(const FabricKeyModuleId& module_id) const;
bool valid_sub_key_id(const FabricSubKeyId& sub_key_id) const;
private: /* Internal data */
/* ---- Top-level keys and regions ---- */
/* Unique ids for each region */
vtr::vector<FabricRegionId, FabricRegionId> region_ids_;
/* Key ids for each region */
vtr::vector<FabricRegionId, std::vector<FabricKeyId>> region_key_ids_;
/* Unique ids for each key */
vtr::vector<FabricKeyId, FabricKeyId> key_ids_;
/* Names for each key */
vtr::vector<FabricKeyId, std::string> key_names_;
/* Values for each key */
vtr::vector<FabricKeyId, size_t> key_values_;
/* Values for each key */
vtr::vector<FabricKeyId, vtr::Point<int>> key_coordinates_;
/* Region for each key */
vtr::vector<FabricKeyId, FabricRegionId> key_regions_;
/* Optional alias for each key, with which a key can also be represented */
vtr::vector<FabricKeyId, std::string> key_alias_;
@ -187,8 +206,8 @@ class FabricKey {
vtr::vector<FabricBitLineBankId, FabricBitLineBankId>>
bl_bank_ids_;
/* Data ports to be connected to each BL shift register bank */
vtr::vector<FabricRegionId, vtr::vector<FabricBitLineBankId,
std::vector<openfpga::BasicPort>>>
vtr::vector<FabricRegionId,
vtr::vector<FabricBitLineBankId, std::vector<BasicPort>>>
bl_bank_data_ports_;
/* Unique ids for each WL shift register bank */
@ -196,9 +215,23 @@ class FabricKey {
vtr::vector<FabricWordLineBankId, FabricWordLineBankId>>
wl_bank_ids_;
/* Data ports to be connected to each WL shift register bank */
vtr::vector<FabricRegionId, vtr::vector<FabricWordLineBankId,
std::vector<openfpga::BasicPort>>>
vtr::vector<FabricRegionId,
vtr::vector<FabricWordLineBankId, std::vector<BasicPort>>>
wl_bank_data_ports_;
/* ---- List of sub modules ---- */
vtr::vector<FabricKeyModuleId, FabricKeyModuleId> sub_key_module_ids_;
vtr::vector<FabricKeyModuleId, std::string> sub_key_module_names_;
vtr::vector<FabricKeyModuleId, std::vector<FabricSubKeyId>> module_sub_keys_;
std::map<std::string, FabricKeyModuleId> module2subkey_lookup_;
/* ---- Sub keys ---- */
vtr::vector<FabricSubKeyId, FabricSubKeyId> sub_key_ids_;
vtr::vector<FabricSubKeyId, std::string> sub_key_names_;
vtr::vector<FabricSubKeyId, size_t> sub_key_values_;
vtr::vector<FabricSubKeyId, std::string> sub_key_alias_;
};
} // End of namespace openfpga
#endif

View File

@ -12,17 +12,25 @@
#include "vtr_strong_id.h"
namespace openfpga { // Begin namespace openfpga
struct fabric_region_id_tag;
struct fabric_key_id_tag;
struct fabric_bit_line_bank_id_tag;
struct fabric_word_line_bank_id_tag;
struct fabric_sub_key_id_tag;
struct fabric_key_module_id_tag;
typedef vtr::StrongId<fabric_region_id_tag> FabricRegionId;
typedef vtr::StrongId<fabric_key_id_tag> FabricKeyId;
typedef vtr::StrongId<fabric_bit_line_bank_id_tag> FabricBitLineBankId;
typedef vtr::StrongId<fabric_word_line_bank_id_tag> FabricWordLineBankId;
typedef vtr::StrongId<fabric_sub_key_id_tag> FabricSubKeyId;
typedef vtr::StrongId<fabric_key_module_id_tag> FabricKeyModuleId;
/* Short declaration of class */
class FabricKey;
} // End of namespace openfpga
#endif

View File

@ -0,0 +1,32 @@
#ifndef FABRIC_KEY_XML_CONSTANTS_H
#define FABRIC_KEY_XML_CONSTANTS_H
namespace openfpga { // Begin namespace openfpga
/* Constants required by XML parser */
constexpr const char* XML_FABRIC_KEY_ROOT_NAME = "fabric_key";
constexpr const char* XML_FABRIC_KEY_MODULE_NODE_NAME = "module";
constexpr const char* XML_FABRIC_KEY_MODULE_ATTRIBUTE_NAME_NAME = "name";
constexpr const char* XML_FABRIC_KEY_REGION_NODE_NAME = "region";
constexpr const char* XML_FABRIC_KEY_REGION_ATTRIBUTE_ID_NAME = "id";
constexpr const char* XML_FABRIC_KEY_KEY_NODE_NAME = "key";
constexpr const char* XML_FABRIC_KEY_KEY_ATTRIBUTE_ID_NAME = "id";
constexpr const char* XML_FABRIC_KEY_KEY_ATTRIBUTE_ALIAS_NAME = "alias";
constexpr const char* XML_FABRIC_KEY_KEY_ATTRIBUTE_NAME_NAME = "name";
constexpr const char* XML_FABRIC_KEY_KEY_ATTRIBUTE_VALUE_NAME = "value";
constexpr const char* XML_FABRIC_KEY_KEY_ATTRIBUTE_COLUMN_NAME = "column";
constexpr const char* XML_FABRIC_KEY_KEY_ATTRIBUTE_ROW_NAME = "row";
constexpr const char* XML_FABRIC_KEY_BL_SHIFT_REGISTER_BANKS_NODE_NAME =
"bl_shift_register_banks";
constexpr const char* XML_FABRIC_KEY_WL_SHIFT_REGISTER_BANKS_NODE_NAME =
"wl_shift_register_banks";
constexpr const char* XML_FABRIC_KEY_BLWL_SHIFT_REGISTER_BANK_NODE_NAME =
"bank";
constexpr const char*
XML_FABRIC_KEY_BLWL_SHIFT_REGISTER_BANK_ATTRIBUTE_ID_NAME = "id";
constexpr const char*
XML_FABRIC_KEY_BLWL_SHIFT_REGISTER_BANK_ATTRIBUTE_RANGE_NAME = "range";
} // End of namespace openfpga
#endif

View File

@ -0,0 +1,461 @@
/********************************************************************
* This file includes the top-level function of this library
* which reads an XML of a fabric key 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_time.h"
/* Headers from openfpga util library */
#include "openfpga_port_parser.h"
#include "openfpga_reserved_words.h"
#include "openfpga_tokenizer.h"
/* Headers from libarchfpga */
#include "arch_error.h"
#include "fabric_key_xml_constants.h"
#include "read_xml_fabric_key.h"
#include "read_xml_util.h"
namespace openfpga { // Begin namespace openfpga
/********************************************************************
* Parse XML codes of a <key> to an object of FabricKey
*******************************************************************/
static void read_xml_module_key(pugi::xml_node& xml_component_key,
const pugiutil::loc_data& loc_data,
FabricKey& fabric_key,
const FabricKeyModuleId& module_id) {
/* Find the id of component key */
size_t id = get_attribute(xml_component_key,
XML_FABRIC_KEY_KEY_ATTRIBUTE_ID_NAME, loc_data)
.as_int();
FabricSubKeyId sub_key_id = fabric_key.sub_keys(module_id)[id];
if (false == fabric_key.valid_sub_key_id(sub_key_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_component_key),
"Invalid 'id' attribute '%d' (in total %lu keys)!\n", id,
fabric_key.sub_keys(module_id).size());
}
VTR_ASSERT_SAFE(true == fabric_key.valid_sub_key_id(sub_key_id));
/* If we have an alias, set the value as well */
const std::string& alias =
get_attribute(xml_component_key, XML_FABRIC_KEY_KEY_ATTRIBUTE_ALIAS_NAME,
loc_data, pugiutil::ReqOpt::OPTIONAL)
.as_string();
if (!alias.empty()) {
fabric_key.set_sub_key_alias(sub_key_id, alias);
}
/* If we have the alias set, name and valus are optional then
* Otherwise, they are mandatory attributes
*/
pugiutil::ReqOpt required_name_value = pugiutil::ReqOpt::OPTIONAL;
if (true == alias.empty()) {
required_name_value = pugiutil::ReqOpt::REQUIRED;
}
const std::string& name =
get_attribute(xml_component_key, XML_FABRIC_KEY_KEY_ATTRIBUTE_NAME_NAME,
loc_data, required_name_value)
.as_string();
const size_t& value =
get_attribute(xml_component_key, XML_FABRIC_KEY_KEY_ATTRIBUTE_VALUE_NAME,
loc_data, required_name_value)
.as_int();
fabric_key.set_sub_key_name(sub_key_id, name);
fabric_key.set_sub_key_value(sub_key_id, value);
}
/********************************************************************
* Parse XML codes of a <key> to an object of FabricKey
*******************************************************************/
static void read_xml_region_key(pugi::xml_node& xml_component_key,
const pugiutil::loc_data& loc_data,
FabricKey& fabric_key,
const FabricRegionId& fabric_region) {
/* Find the id of component key */
const size_t& id =
get_attribute(xml_component_key, XML_FABRIC_KEY_KEY_ATTRIBUTE_ID_NAME,
loc_data)
.as_int();
if (false == fabric_key.valid_key_id(FabricKeyId(id))) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_component_key),
"Invalid 'id' attribute '%d' (in total %lu keys)!\n", id,
fabric_key.keys().size());
}
VTR_ASSERT_SAFE(true == fabric_key.valid_key_id(FabricKeyId(id)));
/* If we have an alias, set the value as well */
const std::string& alias =
get_attribute(xml_component_key, XML_FABRIC_KEY_KEY_ATTRIBUTE_ALIAS_NAME,
loc_data, pugiutil::ReqOpt::OPTIONAL)
.as_string();
if (!alias.empty()) {
fabric_key.set_key_alias(FabricKeyId(id), alias);
}
/* If we have the alias set, name and valus are optional then
* Otherwise, they are mandatory attributes
*/
pugiutil::ReqOpt required_name_value = pugiutil::ReqOpt::OPTIONAL;
if (true == alias.empty()) {
required_name_value = pugiutil::ReqOpt::REQUIRED;
}
const std::string& name =
get_attribute(xml_component_key, XML_FABRIC_KEY_KEY_ATTRIBUTE_NAME_NAME,
loc_data, required_name_value)
.as_string();
const size_t& value =
get_attribute(xml_component_key, XML_FABRIC_KEY_KEY_ATTRIBUTE_VALUE_NAME,
loc_data, required_name_value)
.as_int();
fabric_key.set_key_name(FabricKeyId(id), name);
fabric_key.set_key_value(FabricKeyId(id), value);
fabric_key.add_key_to_region(fabric_region, FabricKeyId(id));
/* Parse coordinates */
vtr::Point<int> coord;
coord.set_x(get_attribute(xml_component_key,
XML_FABRIC_KEY_KEY_ATTRIBUTE_COLUMN_NAME, loc_data,
pugiutil::ReqOpt::OPTIONAL)
.as_int(-1));
coord.set_y(get_attribute(xml_component_key,
XML_FABRIC_KEY_KEY_ATTRIBUTE_ROW_NAME, loc_data,
pugiutil::ReqOpt::OPTIONAL)
.as_int(-1));
if (fabric_key.valid_key_coordinate(coord)) {
fabric_key.set_key_coordinate(FabricKeyId(id), coord);
}
}
/********************************************************************
* Parse XML codes of a <bank> under <bl_shift_register_banks> to an object of
*FabricKey
*******************************************************************/
static void read_xml_region_bl_shift_register_bank(
pugi::xml_node& xml_bank, const pugiutil::loc_data& loc_data,
FabricKey& fabric_key, const FabricRegionId& fabric_region) {
/* Find the id of the bank */
FabricBitLineBankId bank_id = FabricBitLineBankId(
get_attribute(xml_bank,
XML_FABRIC_KEY_BLWL_SHIFT_REGISTER_BANK_ATTRIBUTE_ID_NAME,
loc_data)
.as_int());
if (!fabric_key.valid_bl_bank_id(fabric_region, bank_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_bank),
"Invalid 'id' attribute '%lu' (in total %lu BL banks)!\n",
size_t(bank_id), fabric_key.bl_banks(fabric_region).size());
}
VTR_ASSERT_SAFE(true == fabric_key.valid_bl_bank_id(fabric_region, bank_id));
/* Parse the ports */
std::string data_ports =
get_attribute(xml_bank,
XML_FABRIC_KEY_BLWL_SHIFT_REGISTER_BANK_ATTRIBUTE_RANGE_NAME,
loc_data)
.as_string();
/* Split with ',' if we have multiple ports */
openfpga::StringToken tokenizer(data_ports);
for (const std::string& data_port : tokenizer.split(',')) {
openfpga::PortParser data_port_parser(data_port);
fabric_key.add_data_port_to_bl_shift_register_bank(fabric_region, bank_id,
data_port_parser.port());
}
}
/********************************************************************
* Parse XML codes of a <bl_shift_register_banks> to an object of FabricKey
*******************************************************************/
static void read_xml_region_bl_shift_register_banks(
pugi::xml_node& xml_bl_bank, const pugiutil::loc_data& loc_data,
FabricKey& fabric_key, const FabricRegionId& fabric_region) {
size_t num_banks = count_children(
xml_bl_bank, XML_FABRIC_KEY_BLWL_SHIFT_REGISTER_BANK_NODE_NAME, loc_data,
pugiutil::ReqOpt::OPTIONAL);
fabric_key.reserve_bl_shift_register_banks(fabric_region, num_banks);
for (size_t ibank = 0; ibank < num_banks; ++ibank) {
fabric_key.create_bl_shift_register_bank(fabric_region);
}
for (pugi::xml_node xml_bank : xml_bl_bank.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_bank.name() !=
std::string(XML_FABRIC_KEY_BLWL_SHIFT_REGISTER_BANK_NODE_NAME)) {
bad_tag(xml_bank, loc_data, xml_bl_bank,
{XML_FABRIC_KEY_BLWL_SHIFT_REGISTER_BANK_NODE_NAME});
}
read_xml_region_bl_shift_register_bank(xml_bank, loc_data, fabric_key,
fabric_region);
}
}
/********************************************************************
* Parse XML codes of a <bank> under <wl_shift_register_banks> to an object of
*FabricKey
*******************************************************************/
static void read_xml_region_wl_shift_register_bank(
pugi::xml_node& xml_bank, const pugiutil::loc_data& loc_data,
FabricKey& fabric_key, const FabricRegionId& fabric_region) {
/* Find the id of the bank */
FabricWordLineBankId bank_id = FabricWordLineBankId(
get_attribute(xml_bank,
XML_FABRIC_KEY_BLWL_SHIFT_REGISTER_BANK_ATTRIBUTE_ID_NAME,
loc_data)
.as_int());
if (!fabric_key.valid_wl_bank_id(fabric_region, bank_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_bank),
"Invalid 'id' attribute '%lu' (in total %lu WL banks)!\n",
size_t(bank_id), fabric_key.wl_banks(fabric_region).size());
}
VTR_ASSERT_SAFE(true == fabric_key.valid_wl_bank_id(fabric_region, bank_id));
/* Parse the ports */
std::string data_ports =
get_attribute(xml_bank,
XML_FABRIC_KEY_BLWL_SHIFT_REGISTER_BANK_ATTRIBUTE_RANGE_NAME,
loc_data)
.as_string();
/* Split with ',' if we have multiple ports */
openfpga::StringToken tokenizer(data_ports);
for (const std::string& data_port : tokenizer.split(',')) {
openfpga::PortParser data_port_parser(data_port);
fabric_key.add_data_port_to_wl_shift_register_bank(fabric_region, bank_id,
data_port_parser.port());
}
}
/********************************************************************
* Parse XML codes of a <bl_shift_register_banks> to an object of FabricKey
*******************************************************************/
static void read_xml_region_wl_shift_register_banks(
pugi::xml_node& xml_wl_bank, const pugiutil::loc_data& loc_data,
FabricKey& fabric_key, const FabricRegionId& fabric_region) {
size_t num_banks = count_children(
xml_wl_bank, XML_FABRIC_KEY_BLWL_SHIFT_REGISTER_BANK_NODE_NAME, loc_data,
pugiutil::ReqOpt::OPTIONAL);
fabric_key.reserve_wl_shift_register_banks(fabric_region, num_banks);
for (size_t ibank = 0; ibank < num_banks; ++ibank) {
fabric_key.create_wl_shift_register_bank(fabric_region);
}
for (pugi::xml_node xml_bank : xml_wl_bank.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_bank.name() !=
std::string(XML_FABRIC_KEY_BLWL_SHIFT_REGISTER_BANK_NODE_NAME)) {
bad_tag(xml_bank, loc_data, xml_wl_bank,
{XML_FABRIC_KEY_BLWL_SHIFT_REGISTER_BANK_NODE_NAME});
}
read_xml_region_wl_shift_register_bank(xml_bank, loc_data, fabric_key,
fabric_region);
}
}
/********************************************************************
* Parse XML codes of a <key> to an object of FabricKey
*******************************************************************/
static void read_xml_fabric_region(pugi::xml_node& xml_region,
const pugiutil::loc_data& loc_data,
FabricKey& fabric_key) {
/* Find the unique id for the region */
const FabricRegionId& region_id = FabricRegionId(
get_attribute(xml_region, XML_FABRIC_KEY_REGION_ATTRIBUTE_ID_NAME, loc_data)
.as_int());
if (false == fabric_key.valid_region_id(region_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_region),
"Invalid region id '%lu' (in total %lu regions)!\n",
size_t(region_id), fabric_key.regions().size());
}
VTR_ASSERT_SAFE(true == fabric_key.valid_region_id(region_id));
/* Reserve memory space for the keys in the region */
size_t num_keys = count_children(xml_region, XML_FABRIC_KEY_KEY_NODE_NAME,
loc_data, pugiutil::ReqOpt::OPTIONAL);
fabric_key.reserve_region_keys(region_id, num_keys);
/* Parse the key for this region */
if (0 < num_keys) {
pugi::xml_node xml_key =
get_first_child(xml_region, XML_FABRIC_KEY_KEY_NODE_NAME, loc_data);
while (xml_key) {
read_xml_region_key(xml_key, loc_data, fabric_key, region_id);
xml_key = xml_key.next_sibling(xml_key.name());
}
}
/* Parse the BL shift register bank for this region */
pugi::xml_node xml_bl_bank = get_single_child(
xml_region, XML_FABRIC_KEY_BL_SHIFT_REGISTER_BANKS_NODE_NAME, loc_data,
pugiutil::ReqOpt::OPTIONAL);
read_xml_region_bl_shift_register_banks(xml_bl_bank, loc_data, fabric_key,
region_id);
/* Parse the WL shift register bank for this region */
pugi::xml_node xml_wl_bank = get_single_child(
xml_region, XML_FABRIC_KEY_WL_SHIFT_REGISTER_BANKS_NODE_NAME, loc_data,
pugiutil::ReqOpt::OPTIONAL);
read_xml_region_wl_shift_register_banks(xml_wl_bank, loc_data, fabric_key,
region_id);
}
/********************************************************************
* Parse XML codes of a <module> which is a top-level module
*******************************************************************/
static void read_xml_fabric_key_top_module(pugi::xml_node& xml_module,
const pugiutil::loc_data& loc_data,
FabricKey& fabric_key) {
size_t num_regions =
std::distance(xml_module.children().begin(), xml_module.children().end());
/* Reserve memory space for the region */
fabric_key.reserve_regions(num_regions);
for (size_t iregion = 0; iregion < num_regions; ++iregion) {
fabric_key.create_region();
}
/* Reserve memory space for the keys */
size_t num_keys = 0;
for (pugi::xml_node xml_region : xml_module.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_region.name() != std::string(XML_FABRIC_KEY_REGION_NODE_NAME)) {
bad_tag(xml_region, loc_data, xml_module,
{XML_FABRIC_KEY_REGION_NODE_NAME});
}
num_keys +=
std::distance(xml_region.children().begin(), xml_region.children().end());
}
fabric_key.reserve_keys(num_keys);
for (size_t ikey = 0; ikey < num_keys; ++ikey) {
fabric_key.create_key();
}
/* Iterate over the children under this node,
* each child should be named after circuit_model
*/
for (pugi::xml_node xml_region : xml_module.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_region.name() != std::string(XML_FABRIC_KEY_REGION_NODE_NAME)) {
bad_tag(xml_region, loc_data, xml_module,
{XML_FABRIC_KEY_REGION_NODE_NAME});
}
read_xml_fabric_region(xml_region, loc_data, fabric_key);
}
}
/********************************************************************
* Parse XML codes of a <module> which is a regular module
*******************************************************************/
static void read_xml_fabric_key_module(pugi::xml_node& xml_module,
const pugiutil::loc_data& loc_data,
FabricKey& fabric_key) {
std::string name =
get_attribute(xml_module, XML_FABRIC_KEY_MODULE_ATTRIBUTE_NAME_NAME,
loc_data)
.as_string();
FabricKeyModuleId module_id = fabric_key.create_module(name);
/* Parse all the sub keys */
size_t num_keys =
std::distance(xml_module.children().begin(), xml_module.children().end());
/* Reserve for better memory efficiency */
fabric_key.reserve_module_keys(module_id, num_keys);
for (size_t ikey = 0; ikey < num_keys; ++ikey) {
fabric_key.create_module_key(module_id);
}
for (pugi::xml_node xml_key : xml_module.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_key.name() != std::string(XML_FABRIC_KEY_KEY_NODE_NAME)) {
bad_tag(xml_key, loc_data, xml_module, {XML_FABRIC_KEY_KEY_NODE_NAME});
}
read_xml_module_key(xml_key, loc_data, fabric_key, module_id);
}
}
/********************************************************************
* Parse XML codes of a <module> to an object of FabricKey
* - For top-level module, we expect a fixed name. If so, we use a special
*parser
* - For regular module, we follow regular parser
*******************************************************************/
static void read_xml_fabric_keys_by_modules(pugi::xml_node& xml_module,
const pugiutil::loc_data& loc_data,
FabricKey& fabric_key) {
std::string name =
get_attribute(xml_module, XML_FABRIC_KEY_MODULE_ATTRIBUTE_NAME_NAME,
loc_data)
.as_string();
if (name == std::string(openfpga::FPGA_TOP_MODULE_NAME)) {
read_xml_fabric_key_top_module(xml_module, loc_data, fabric_key);
} else {
read_xml_fabric_key_module(xml_module, loc_data, fabric_key);
}
}
/********************************************************************
* Parse XML codes about <fabric> to an object of FabricKey
*******************************************************************/
FabricKey read_xml_fabric_key(const char* key_fname) {
vtr::ScopedStartFinishTimer timer("Read Fabric Key");
FabricKey fabric_key;
/* Parse the file */
pugi::xml_document doc;
pugiutil::loc_data loc_data;
try {
loc_data = pugiutil::load_xml(doc, key_fname);
pugi::xml_node xml_root =
get_single_child(doc, XML_FABRIC_KEY_ROOT_NAME, loc_data);
/* Under the root node, we expect only modules */
size_t num_modules =
std::distance(xml_root.children().begin(), xml_root.children().end());
/* Reserve for memory efficiency */
fabric_key.reserve_modules(num_modules);
/* Walk through the modules, fill keys one by one */
for (pugi::xml_node xml_module : xml_root.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_module.name() != std::string(XML_FABRIC_KEY_MODULE_NODE_NAME)) {
bad_tag(xml_module, loc_data, xml_root,
{XML_FABRIC_KEY_MODULE_NODE_NAME});
}
/* Parse fabric keys by module */
read_xml_fabric_keys_by_modules(xml_module, loc_data, fabric_key);
}
} catch (pugiutil::XmlError& e) {
archfpga_throw(key_fname, e.line(), "%s", e.what());
}
return fabric_key;
}
} // End of namespace openfpga

View File

@ -9,6 +9,11 @@
/********************************************************************
* Function declaration
*******************************************************************/
namespace openfpga { // Begin namespace openfpga
FabricKey read_xml_fabric_key(const char* key_fname);
} // End of namespace openfpga
#endif

View File

@ -0,0 +1,351 @@
/********************************************************************
* This file includes functions that outputs a configuration protocol 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"
#include "openfpga_reserved_words.h"
/* Headers from arch openfpga library */
#include "write_xml_utils.h"
/* Headers from fabrickey library */
#include "fabric_key_xml_constants.h"
#include "write_xml_fabric_key.h"
namespace openfpga { // Begin namespace openfpga
/********************************************************************
* A writer to output a component sub key 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_fabric_component_sub_key(
std::fstream& fp, const FabricKey& fabric_key,
const FabricSubKeyId& component_key, const size_t& key_idx,
const size_t& level) {
/* Validate the file stream */
if (false == openfpga::valid_file_stream(fp)) {
return 2;
}
openfpga::write_tab_to_file(fp, level);
fp << "<" << XML_FABRIC_KEY_KEY_NODE_NAME;
if (false == fabric_key.valid_sub_key_id(component_key)) {
return 1;
}
write_xml_attribute(fp, XML_FABRIC_KEY_KEY_ATTRIBUTE_ID_NAME, key_idx);
if (!fabric_key.sub_key_name(component_key).empty()) {
write_xml_attribute(fp, XML_FABRIC_KEY_KEY_ATTRIBUTE_NAME_NAME,
fabric_key.sub_key_name(component_key).c_str());
}
write_xml_attribute(fp, XML_FABRIC_KEY_KEY_ATTRIBUTE_VALUE_NAME,
fabric_key.sub_key_value(component_key));
if (!fabric_key.sub_key_alias(component_key).empty()) {
write_xml_attribute(fp, XML_FABRIC_KEY_KEY_ATTRIBUTE_ALIAS_NAME,
fabric_key.sub_key_alias(component_key).c_str());
}
fp << "/>"
<< "\n";
return 0;
}
/********************************************************************
* A writer to output a component key 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_fabric_component_key(std::fstream& fp,
const FabricKey& fabric_key,
const FabricKeyId& component_key,
const size_t& level) {
/* Validate the file stream */
if (false == openfpga::valid_file_stream(fp)) {
return 2;
}
openfpga::write_tab_to_file(fp, level);
fp << "<" << XML_FABRIC_KEY_KEY_NODE_NAME;
if (false == fabric_key.valid_key_id(component_key)) {
return 1;
}
write_xml_attribute(fp, XML_FABRIC_KEY_KEY_ATTRIBUTE_ID_NAME,
size_t(component_key));
if (!fabric_key.key_name(component_key).empty()) {
write_xml_attribute(fp, XML_FABRIC_KEY_KEY_ATTRIBUTE_NAME_NAME,
fabric_key.key_name(component_key).c_str());
}
write_xml_attribute(fp, XML_FABRIC_KEY_KEY_ATTRIBUTE_VALUE_NAME,
fabric_key.key_value(component_key));
if (!fabric_key.key_alias(component_key).empty()) {
write_xml_attribute(fp, XML_FABRIC_KEY_KEY_ATTRIBUTE_ALIAS_NAME,
fabric_key.key_alias(component_key).c_str());
}
vtr::Point<int> coord = fabric_key.key_coordinate(component_key);
if (fabric_key.valid_key_coordinate(coord)) {
write_xml_attribute(fp, XML_FABRIC_KEY_KEY_ATTRIBUTE_COLUMN_NAME,
coord.x());
write_xml_attribute(fp, XML_FABRIC_KEY_KEY_ATTRIBUTE_ROW_NAME, coord.y());
}
fp << "/>"
<< "\n";
return 0;
}
/********************************************************************
* A writer to output a BL shift register bank description 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_fabric_bl_shift_register_banks(
std::fstream& fp, const FabricKey& fabric_key, const FabricRegionId& region,
const size_t& level) {
/* Validate the file stream */
if (false == openfpga::valid_file_stream(fp)) {
return 2;
}
/* If we have an empty bank, we just skip it */
if (0 == fabric_key.bl_banks(region).size()) {
return 0;
}
/* Write the root node */
openfpga::write_tab_to_file(fp, level);
fp << "<" << XML_FABRIC_KEY_BL_SHIFT_REGISTER_BANKS_NODE_NAME << ">"
<< "\n";
for (const auto& bank : fabric_key.bl_banks(region)) {
openfpga::write_tab_to_file(fp, level + 1);
fp << "<" << XML_FABRIC_KEY_BLWL_SHIFT_REGISTER_BANK_NODE_NAME;
write_xml_attribute(
fp, XML_FABRIC_KEY_BLWL_SHIFT_REGISTER_BANK_ATTRIBUTE_ID_NAME,
size_t(bank));
std::string port_str;
for (const auto& port : fabric_key.bl_bank_data_ports(region, bank)) {
port_str += generate_xml_port_name(port) + ",";
}
/* Chop the last comma */
if (!port_str.empty()) {
port_str.pop_back();
}
write_xml_attribute(
fp, XML_FABRIC_KEY_BLWL_SHIFT_REGISTER_BANK_ATTRIBUTE_RANGE_NAME,
port_str.c_str());
fp << "/>"
<< "\n";
}
openfpga::write_tab_to_file(fp, level);
fp << "</" << XML_FABRIC_KEY_BL_SHIFT_REGISTER_BANKS_NODE_NAME << ">"
<< "\n";
return 0;
}
/********************************************************************
* A writer to output a WL shift register bank description 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_fabric_wl_shift_register_banks(
std::fstream& fp, const FabricKey& fabric_key, const FabricRegionId& region,
const size_t& level) {
/* Validate the file stream */
if (false == openfpga::valid_file_stream(fp)) {
return 2;
}
/* If we have an empty bank, we just skip it */
if (0 == fabric_key.wl_banks(region).size()) {
return 0;
}
/* Write the root node */
openfpga::write_tab_to_file(fp, level);
fp << "<" << XML_FABRIC_KEY_WL_SHIFT_REGISTER_BANKS_NODE_NAME << ">"
<< "\n";
for (const auto& bank : fabric_key.wl_banks(region)) {
openfpga::write_tab_to_file(fp, level + 1);
fp << "<" << XML_FABRIC_KEY_BLWL_SHIFT_REGISTER_BANK_NODE_NAME;
write_xml_attribute(
fp, XML_FABRIC_KEY_BLWL_SHIFT_REGISTER_BANK_ATTRIBUTE_ID_NAME,
size_t(bank));
std::string port_str;
for (const auto& port : fabric_key.wl_bank_data_ports(region, bank)) {
port_str += generate_xml_port_name(port) + ",";
}
/* Chop the last comma */
if (!port_str.empty()) {
port_str.pop_back();
}
write_xml_attribute(
fp, XML_FABRIC_KEY_BLWL_SHIFT_REGISTER_BANK_ATTRIBUTE_RANGE_NAME,
port_str.c_str());
fp << "/>"
<< "\n";
}
openfpga::write_tab_to_file(fp, level);
fp << "</" << XML_FABRIC_KEY_WL_SHIFT_REGISTER_BANKS_NODE_NAME << ">"
<< "\n";
return 0;
}
/* Write keys under the top-level module to a file */
static int write_xml_top_module_keys(std::fstream& fp,
const FabricKey& fabric_key,
const size_t& level) {
int err_code = 0;
/* Write the module declaration */
openfpga::write_tab_to_file(fp, level);
fp << "<" << XML_FABRIC_KEY_MODULE_NODE_NAME << " "
<< XML_FABRIC_KEY_MODULE_ATTRIBUTE_NAME_NAME << "=\""
<< FPGA_TOP_MODULE_NAME << "\""
<< ">\n";
/* Write region by region */
for (const FabricRegionId& region : fabric_key.regions()) {
openfpga::write_tab_to_file(fp, level + 1);
fp << "<" << XML_FABRIC_KEY_REGION_NODE_NAME << " "
<< XML_FABRIC_KEY_REGION_ATTRIBUTE_ID_NAME << "=\"" << size_t(region)
<< "\""
<< ">\n";
/* Write shift register banks */
write_xml_fabric_bl_shift_register_banks(fp, fabric_key, region, level + 2);
write_xml_fabric_wl_shift_register_banks(fp, fabric_key, region, level + 2);
/* Write component by component */
for (const FabricKeyId& key : fabric_key.region_keys(region)) {
err_code = write_xml_fabric_component_key(fp, fabric_key, key, level + 2);
if (0 != err_code) {
return err_code;
}
}
openfpga::write_tab_to_file(fp, level + 1);
fp << "</" << XML_FABRIC_KEY_REGION_NODE_NAME << ">"
<< "\n";
}
openfpga::write_tab_to_file(fp, level);
fp << "</" << XML_FABRIC_KEY_MODULE_NODE_NAME << ">\n";
return err_code;
}
/* Write keys under the a given module to a file */
static int write_xml_module_keys(std::fstream& fp, const FabricKey& fabric_key,
const FabricKeyModuleId& module_id,
const size_t& level) {
int err_code = 0;
/* Write the module declaration */
openfpga::write_tab_to_file(fp, level);
fp << "<" << XML_FABRIC_KEY_MODULE_NODE_NAME << " "
<< XML_FABRIC_KEY_MODULE_ATTRIBUTE_NAME_NAME << "=\""
<< fabric_key.module_name(module_id) << "\""
<< ">\n";
/* Write component by component */
size_t key_idx = 0;
for (const FabricSubKeyId& key : fabric_key.sub_keys(module_id)) {
err_code = write_xml_fabric_component_sub_key(fp, fabric_key, key, key_idx,
level + 1);
if (0 != err_code) {
return err_code;
}
key_idx++;
}
openfpga::write_tab_to_file(fp, level);
fp << "</" << XML_FABRIC_KEY_MODULE_NODE_NAME << ">\n";
return err_code;
}
/********************************************************************
* A writer to output a fabric key 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_fabric_key(const char* fname, const FabricKey& fabric_key) {
vtr::ScopedStartFinishTimer timer("Write Fabric Key");
/* 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_FABRIC_KEY_ROOT_NAME << ">"
<< "\n";
int err_code = 0;
/* Write the top-level module */
err_code = write_xml_top_module_keys(fp, fabric_key, 1);
if (0 != err_code) {
return err_code;
}
/* Write regular modules */
for (FabricKeyModuleId module_id : fabric_key.modules()) {
err_code = write_xml_module_keys(fp, fabric_key, module_id, 1);
if (0 != err_code) {
return err_code;
}
}
/* Finish writing the root node */
fp << "</" << XML_FABRIC_KEY_ROOT_NAME << ">"
<< "\n";
/* Close the file stream */
fp.close();
return err_code;
}
} // End of namespace openfpga

View File

@ -11,6 +11,11 @@
/********************************************************************
* Function declaration
*******************************************************************/
namespace openfpga { // Begin namespace openfpga
int write_xml_fabric_key(const char* fname, const FabricKey& fabric_key);
} // End of namespace openfpga
#endif

View File

@ -1,295 +0,0 @@
/********************************************************************
* This file includes the top-level function of this library
* which reads an XML of a fabric key 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_time.h"
/* Headers from openfpga util library */
#include "openfpga_port_parser.h"
#include "openfpga_tokenizer.h"
/* Headers from libarchfpga */
#include "arch_error.h"
#include "read_xml_fabric_key.h"
#include "read_xml_util.h"
/********************************************************************
* Parse XML codes of a <key> to an object of FabricKey
*******************************************************************/
static void read_xml_region_key(pugi::xml_node& xml_component_key,
const pugiutil::loc_data& loc_data,
FabricKey& fabric_key,
const FabricRegionId& fabric_region) {
/* Find the id of component key */
const size_t& id = get_attribute(xml_component_key, "id", loc_data).as_int();
if (false == fabric_key.valid_key_id(FabricKeyId(id))) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_component_key),
"Invalid 'id' attribute '%d' (in total %lu keys)!\n", id,
fabric_key.keys().size());
}
VTR_ASSERT_SAFE(true == fabric_key.valid_key_id(FabricKeyId(id)));
/* If we have an alias, set the value as well */
const std::string& alias = get_attribute(xml_component_key, "alias", loc_data,
pugiutil::ReqOpt::OPTIONAL)
.as_string();
if (!alias.empty()) {
fabric_key.set_key_alias(FabricKeyId(id), alias);
}
/* If we have the alias set, name and valus are optional then
* Otherwise, they are mandatory attributes
*/
pugiutil::ReqOpt required_name_value = pugiutil::ReqOpt::OPTIONAL;
if (true == alias.empty()) {
required_name_value = pugiutil::ReqOpt::REQUIRED;
}
const std::string& name =
get_attribute(xml_component_key, "name", loc_data, required_name_value)
.as_string();
const size_t& value =
get_attribute(xml_component_key, "value", loc_data, required_name_value)
.as_int();
fabric_key.set_key_name(FabricKeyId(id), name);
fabric_key.set_key_value(FabricKeyId(id), value);
fabric_key.add_key_to_region(fabric_region, FabricKeyId(id));
/* Parse coordinates */
vtr::Point<int> coord;
coord.set_x(get_attribute(xml_component_key, "column", loc_data,
pugiutil::ReqOpt::OPTIONAL)
.as_int(-1));
coord.set_y(get_attribute(xml_component_key, "row", loc_data,
pugiutil::ReqOpt::OPTIONAL)
.as_int(-1));
if (fabric_key.valid_key_coordinate(coord)) {
fabric_key.set_key_coordinate(FabricKeyId(id), coord);
}
}
/********************************************************************
* Parse XML codes of a <bank> under <bl_shift_register_banks> to an object of
*FabricKey
*******************************************************************/
static void read_xml_region_bl_shift_register_bank(
pugi::xml_node& xml_bank, const pugiutil::loc_data& loc_data,
FabricKey& fabric_key, const FabricRegionId& fabric_region) {
/* Find the id of the bank */
FabricBitLineBankId bank_id =
FabricBitLineBankId(get_attribute(xml_bank, "id", loc_data).as_int());
if (!fabric_key.valid_bl_bank_id(fabric_region, bank_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_bank),
"Invalid 'id' attribute '%lu' (in total %lu BL banks)!\n",
size_t(bank_id), fabric_key.bl_banks(fabric_region).size());
}
VTR_ASSERT_SAFE(true == fabric_key.valid_bl_bank_id(fabric_region, bank_id));
/* Parse the ports */
std::string data_ports =
get_attribute(xml_bank, "range", loc_data).as_string();
/* Split with ',' if we have multiple ports */
openfpga::StringToken tokenizer(data_ports);
for (const std::string& data_port : tokenizer.split(',')) {
openfpga::PortParser data_port_parser(data_port);
fabric_key.add_data_port_to_bl_shift_register_bank(fabric_region, bank_id,
data_port_parser.port());
}
}
/********************************************************************
* Parse XML codes of a <bl_shift_register_banks> to an object of FabricKey
*******************************************************************/
static void read_xml_region_bl_shift_register_banks(
pugi::xml_node& xml_bl_bank, const pugiutil::loc_data& loc_data,
FabricKey& fabric_key, const FabricRegionId& fabric_region) {
size_t num_banks =
count_children(xml_bl_bank, "bank", loc_data, pugiutil::ReqOpt::OPTIONAL);
fabric_key.reserve_bl_shift_register_banks(fabric_region, num_banks);
for (size_t ibank = 0; ibank < num_banks; ++ibank) {
fabric_key.create_bl_shift_register_bank(fabric_region);
}
for (pugi::xml_node xml_bank : xml_bl_bank.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_bank.name() != std::string("bank")) {
bad_tag(xml_bank, loc_data, xml_bl_bank, {"bank"});
}
read_xml_region_bl_shift_register_bank(xml_bank, loc_data, fabric_key,
fabric_region);
}
}
/********************************************************************
* Parse XML codes of a <bank> under <wl_shift_register_banks> to an object of
*FabricKey
*******************************************************************/
static void read_xml_region_wl_shift_register_bank(
pugi::xml_node& xml_bank, const pugiutil::loc_data& loc_data,
FabricKey& fabric_key, const FabricRegionId& fabric_region) {
/* Find the id of the bank */
FabricWordLineBankId bank_id =
FabricWordLineBankId(get_attribute(xml_bank, "id", loc_data).as_int());
if (!fabric_key.valid_wl_bank_id(fabric_region, bank_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_bank),
"Invalid 'id' attribute '%lu' (in total %lu WL banks)!\n",
size_t(bank_id), fabric_key.wl_banks(fabric_region).size());
}
VTR_ASSERT_SAFE(true == fabric_key.valid_wl_bank_id(fabric_region, bank_id));
/* Parse the ports */
std::string data_ports =
get_attribute(xml_bank, "range", loc_data).as_string();
/* Split with ',' if we have multiple ports */
openfpga::StringToken tokenizer(data_ports);
for (const std::string& data_port : tokenizer.split(',')) {
openfpga::PortParser data_port_parser(data_port);
fabric_key.add_data_port_to_wl_shift_register_bank(fabric_region, bank_id,
data_port_parser.port());
}
}
/********************************************************************
* Parse XML codes of a <bl_shift_register_banks> to an object of FabricKey
*******************************************************************/
static void read_xml_region_wl_shift_register_banks(
pugi::xml_node& xml_wl_bank, const pugiutil::loc_data& loc_data,
FabricKey& fabric_key, const FabricRegionId& fabric_region) {
size_t num_banks =
count_children(xml_wl_bank, "bank", loc_data, pugiutil::ReqOpt::OPTIONAL);
fabric_key.reserve_wl_shift_register_banks(fabric_region, num_banks);
for (size_t ibank = 0; ibank < num_banks; ++ibank) {
fabric_key.create_wl_shift_register_bank(fabric_region);
}
for (pugi::xml_node xml_bank : xml_wl_bank.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_bank.name() != std::string("bank")) {
bad_tag(xml_bank, loc_data, xml_wl_bank, {"bank"});
}
read_xml_region_wl_shift_register_bank(xml_bank, loc_data, fabric_key,
fabric_region);
}
}
/********************************************************************
* Parse XML codes of a <key> to an object of FabricKey
*******************************************************************/
static void read_xml_fabric_region(pugi::xml_node& xml_region,
const pugiutil::loc_data& loc_data,
FabricKey& fabric_key) {
/* Find the unique id for the region */
const FabricRegionId& region_id =
FabricRegionId(get_attribute(xml_region, "id", loc_data).as_int());
if (false == fabric_key.valid_region_id(region_id)) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_region),
"Invalid region id '%lu' (in total %lu regions)!\n",
size_t(region_id), fabric_key.regions().size());
}
VTR_ASSERT_SAFE(true == fabric_key.valid_region_id(region_id));
/* Reserve memory space for the keys in the region */
size_t num_keys =
count_children(xml_region, "key", loc_data, pugiutil::ReqOpt::OPTIONAL);
fabric_key.reserve_region_keys(region_id, num_keys);
/* Parse the key for this region */
if (0 < num_keys) {
pugi::xml_node xml_key = get_first_child(xml_region, "key", loc_data);
while (xml_key) {
read_xml_region_key(xml_key, loc_data, fabric_key, region_id);
xml_key = xml_key.next_sibling(xml_key.name());
}
}
/* Parse the BL shift register bank for this region */
pugi::xml_node xml_bl_bank =
get_single_child(xml_region, "bl_shift_register_banks", loc_data,
pugiutil::ReqOpt::OPTIONAL);
read_xml_region_bl_shift_register_banks(xml_bl_bank, loc_data, fabric_key,
region_id);
/* Parse the WL shift register bank for this region */
pugi::xml_node xml_wl_bank =
get_single_child(xml_region, "wl_shift_register_banks", loc_data,
pugiutil::ReqOpt::OPTIONAL);
read_xml_region_wl_shift_register_banks(xml_wl_bank, loc_data, fabric_key,
region_id);
}
/********************************************************************
* Parse XML codes about <fabric> to an object of FabricKey
*******************************************************************/
FabricKey read_xml_fabric_key(const char* key_fname) {
vtr::ScopedStartFinishTimer timer("Read Fabric Key");
FabricKey fabric_key;
/* Parse the file */
pugi::xml_document doc;
pugiutil::loc_data loc_data;
try {
loc_data = pugiutil::load_xml(doc, key_fname);
pugi::xml_node xml_root = get_single_child(doc, "fabric_key", loc_data);
size_t num_regions =
std::distance(xml_root.children().begin(), xml_root.children().end());
/* Reserve memory space for the region */
fabric_key.reserve_regions(num_regions);
for (size_t iregion = 0; iregion < num_regions; ++iregion) {
fabric_key.create_region();
}
/* Reserve memory space for the keys */
size_t num_keys = 0;
for (pugi::xml_node xml_region : xml_root.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_region.name() != std::string("region")) {
bad_tag(xml_region, loc_data, xml_root, {"region"});
}
num_keys += std::distance(xml_region.children().begin(),
xml_region.children().end());
}
fabric_key.reserve_keys(num_keys);
for (size_t ikey = 0; ikey < num_keys; ++ikey) {
fabric_key.create_key();
}
/* Iterate over the children under this node,
* each child should be named after circuit_model
*/
for (pugi::xml_node xml_region : xml_root.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_region.name() != std::string("region")) {
bad_tag(xml_region, loc_data, xml_root, {"region"});
}
read_xml_fabric_region(xml_region, loc_data, fabric_key);
}
} catch (pugiutil::XmlError& e) {
archfpga_throw(key_fname, e.line(), "%s", e.what());
}
return fabric_key;
}

View File

@ -1,225 +0,0 @@
/********************************************************************
* This file includes functions that outputs a configuration protocol 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 fabrickey library */
#include "write_xml_fabric_key.h"
/********************************************************************
* A writer to output a component key 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_fabric_component_key(std::fstream& fp,
const FabricKey& fabric_key,
const FabricKeyId& component_key) {
/* Validate the file stream */
if (false == openfpga::valid_file_stream(fp)) {
return 2;
}
openfpga::write_tab_to_file(fp, 2);
fp << "<key";
if (false == fabric_key.valid_key_id(component_key)) {
return 1;
}
write_xml_attribute(fp, "id", size_t(component_key));
if (!fabric_key.key_name(component_key).empty()) {
write_xml_attribute(fp, "name", fabric_key.key_name(component_key).c_str());
}
write_xml_attribute(fp, "value", fabric_key.key_value(component_key));
if (!fabric_key.key_alias(component_key).empty()) {
write_xml_attribute(fp, "alias",
fabric_key.key_alias(component_key).c_str());
}
vtr::Point<int> coord = fabric_key.key_coordinate(component_key);
if (fabric_key.valid_key_coordinate(coord)) {
write_xml_attribute(fp, "column", coord.x());
write_xml_attribute(fp, "row", coord.y());
}
fp << "/>"
<< "\n";
return 0;
}
/********************************************************************
* A writer to output a BL shift register bank description 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_fabric_bl_shift_register_banks(
std::fstream& fp, const FabricKey& fabric_key, const FabricRegionId& region) {
/* Validate the file stream */
if (false == openfpga::valid_file_stream(fp)) {
return 2;
}
/* If we have an empty bank, we just skip it */
if (0 == fabric_key.bl_banks(region).size()) {
return 0;
}
/* Write the root node */
openfpga::write_tab_to_file(fp, 2);
fp << "<bl_shift_register_banks>"
<< "\n";
for (const auto& bank : fabric_key.bl_banks(region)) {
openfpga::write_tab_to_file(fp, 3);
fp << "<bank";
write_xml_attribute(fp, "id", size_t(bank));
std::string port_str;
for (const auto& port : fabric_key.bl_bank_data_ports(region, bank)) {
port_str += generate_xml_port_name(port) + ",";
}
/* Chop the last comma */
if (!port_str.empty()) {
port_str.pop_back();
}
write_xml_attribute(fp, "range", port_str.c_str());
fp << "/>"
<< "\n";
}
openfpga::write_tab_to_file(fp, 2);
fp << "</bl_shift_register_banks>"
<< "\n";
return 0;
}
/********************************************************************
* A writer to output a WL shift register bank description 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_fabric_wl_shift_register_banks(
std::fstream& fp, const FabricKey& fabric_key, const FabricRegionId& region) {
/* Validate the file stream */
if (false == openfpga::valid_file_stream(fp)) {
return 2;
}
/* If we have an empty bank, we just skip it */
if (0 == fabric_key.wl_banks(region).size()) {
return 0;
}
/* Write the root node */
openfpga::write_tab_to_file(fp, 2);
fp << "<wl_shift_register_banks>"
<< "\n";
for (const auto& bank : fabric_key.wl_banks(region)) {
openfpga::write_tab_to_file(fp, 3);
fp << "<bank";
write_xml_attribute(fp, "id", size_t(bank));
std::string port_str;
for (const auto& port : fabric_key.wl_bank_data_ports(region, bank)) {
port_str += generate_xml_port_name(port) + ",";
}
/* Chop the last comma */
if (!port_str.empty()) {
port_str.pop_back();
}
write_xml_attribute(fp, "range", port_str.c_str());
fp << "/>"
<< "\n";
}
openfpga::write_tab_to_file(fp, 2);
fp << "</wl_shift_register_banks>"
<< "\n";
return 0;
}
/********************************************************************
* A writer to output a fabric key 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_fabric_key(const char* fname, const FabricKey& fabric_key) {
vtr::ScopedStartFinishTimer timer("Write Fabric Key");
/* 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 << "<fabric_key>"
<< "\n";
int err_code = 0;
/* Write region by region */
for (const FabricRegionId& region : fabric_key.regions()) {
openfpga::write_tab_to_file(fp, 1);
fp << "<region id=\"" << size_t(region) << "\""
<< ">\n";
/* Write shift register banks */
write_xml_fabric_bl_shift_register_banks(fp, fabric_key, region);
write_xml_fabric_wl_shift_register_banks(fp, fabric_key, region);
/* Write component by component */
for (const FabricKeyId& key : fabric_key.region_keys(region)) {
err_code = write_xml_fabric_component_key(fp, fabric_key, key);
if (0 != err_code) {
return err_code;
}
}
openfpga::write_tab_to_file(fp, 1);
fp << "</region>"
<< "\n";
}
/* Finish writing the root node */
fp << "</fabric_key>"
<< "\n";
/* Close the file stream */
fp.close();
return err_code;
}

View File

@ -16,14 +16,14 @@ int main(int argc, const char** argv) {
VTR_ASSERT((2 == argc) || (3 == argc));
/* Parse the fabric key from an XML file */
FabricKey test_key = read_xml_fabric_key(argv[1]);
openfpga::FabricKey test_key = openfpga::read_xml_fabric_key(argv[1]);
VTR_LOG("Read the fabric key from an XML file: %s.\n", argv[1]);
/* Output the circuit library to an XML file
* This is optional only used when there is a second argument
*/
if (3 <= argc) {
write_xml_fabric_key(argv[2], test_key);
openfpga::write_xml_fabric_key(argv[2], test_key);
VTR_LOG("Echo the fabric key to an XML file: %s.\n", argv[2]);
}
}

View File

@ -157,10 +157,10 @@ int build_fabric_template(T& openfpga_ctx, const Command& cmd,
std::string fkey_fname =
cmd_context.option_value(cmd, opt_write_fabric_key);
VTR_ASSERT(false == fkey_fname.empty());
curr_status =
write_fabric_key_to_xml_file(openfpga_ctx.module_graph(), fkey_fname,
curr_status = write_fabric_key_to_xml_file(
openfpga_ctx.module_graph(), fkey_fname,
openfpga_ctx.arch().config_protocol,
openfpga_ctx.blwl_shift_register_banks(),
openfpga_ctx.blwl_shift_register_banks(), false,
cmd_context.option_enable(cmd, opt_verbose));
/* If there is any error, final status cannot be overwritten by a success
* flag */
@ -172,6 +172,32 @@ int build_fabric_template(T& openfpga_ctx, const Command& cmd,
return final_status;
}
/********************************************************************
* Write fabric key of the module graph for FPGA device to a file
*******************************************************************/
template <class T>
int write_fabric_key_template(const T& openfpga_ctx, const Command& cmd,
const CommandContext& cmd_context) {
CommandOptionId opt_verbose = cmd.option("verbose");
CommandOptionId opt_include_module_keys = cmd.option("include_module_keys");
/* Check the option '--file' is enabled or not
* Actually, it must be enabled as the shell interface will check
* before reaching this fuction
*/
CommandOptionId opt_file = cmd.option("file");
VTR_ASSERT(true == cmd_context.option_enable(cmd, opt_file));
VTR_ASSERT(false == cmd_context.option_value(cmd, opt_file).empty());
/* Write fabric key to a file */
return write_fabric_key_to_xml_file(
openfpga_ctx.module_graph(), cmd_context.option_value(cmd, opt_file),
openfpga_ctx.arch().config_protocol,
openfpga_ctx.blwl_shift_register_banks(),
cmd_context.option_enable(cmd, opt_include_module_keys),
cmd_context.option_enable(cmd, opt_verbose));
}
/********************************************************************
* Write hierarchy of the module graph for FPGA device to a file
*******************************************************************/

View File

@ -738,6 +738,40 @@ ShellCommandId add_add_fpga_core_to_fabric_command_template(
return shell_cmd_id;
}
/********************************************************************
* - Add a command to Shell environment: write_fabric_key
* - Add associated options
* - Add command dependency
*******************************************************************/
template <class T>
ShellCommandId add_write_fabric_key_command_template(
openfpga::Shell<T>& shell, const ShellCommandClassId& cmd_class_id,
const std::vector<ShellCommandId>& dependent_cmds, const bool& hidden) {
Command shell_cmd("write_fabric_key");
/* Add an option '--file' in short '-f'*/
CommandOptionId opt_file =
shell_cmd.add_option("file", true, "file path to the fabric key XML");
shell_cmd.set_option_short_name(opt_file, "f");
shell_cmd.set_option_require_value(opt_file, openfpga::OPT_STRING);
/* Add an option '--include_module_keys'*/
shell_cmd.add_option("include_module_keys", false,
"Include module-level keys");
shell_cmd.add_option("verbose", false, "Show verbose outputs");
/* Add command to the Shell */
ShellCommandId shell_cmd_id = shell.add_command(
shell_cmd, "write fabric key of the FPGA fabric to file", hidden);
shell.set_command_class(shell_cmd_id, cmd_class_id);
shell.set_command_const_execute_function(shell_cmd_id,
write_fabric_key_template<T>);
/* Add command dependency to the Shell */
shell.set_command_dependency(shell_cmd_id, dependent_cmds);
return shell_cmd_id;
}
template <class T>
void add_setup_command_templates(openfpga::Shell<T>& shell,
const bool& hidden = false) {
@ -927,6 +961,16 @@ void add_setup_command_templates(openfpga::Shell<T>& shell,
shell, openfpga_setup_cmd_class, add_fpga_core_to_fabric_dependent_cmds,
hidden);
/********************************
* Command 'write_fabric_key'
*/
/* The 'write_fabric_key' command should NOT be executed before
* 'build_fabric' */
std::vector<ShellCommandId> write_fabric_key_dependent_cmds;
write_fabric_key_dependent_cmds.push_back(build_fabric_cmd_id);
add_write_fabric_key_command_template<T>(
shell, openfpga_setup_cmd_class, write_fabric_key_dependent_cmds, hidden);
/********************************
* Command 'write_fabric_hierarchy'
*/

View File

@ -22,6 +22,7 @@
#include "build_top_module_memory_bank.h"
#include "build_top_module_utils.h"
#include "command_exit_codes.h"
#include "module_manager_memory_utils.h"
#include "module_manager_utils.h"
#include "openfpga_device_grid_utils.h"
#include "openfpga_naming.h"
@ -542,6 +543,13 @@ int build_top_module(
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
/* Update the memory organization in sub module (non-top) */
status = load_submodules_memory_modules_from_fabric_key(
module_manager, circuit_lib, config_protocol, fabric_key);
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
}
/* Shuffle the configurable children in a random sequence */

View File

@ -7,6 +7,7 @@
#include "vtr_time.h"
/* Headers from openfpgautil library */
#include "command_exit_codes.h"
#include "openfpga_digest.h"
/* Headers from archopenfpga library */
@ -18,6 +19,51 @@
/* begin namespace openfpga */
namespace openfpga {
/***************************************************************************************
* Add module-level keys to fabric key
***************************************************************************************/
static int add_module_keys_to_fabric_key(const ModuleManager& module_manager,
const ModuleId& curr_module,
FabricKey& fabric_key) {
/* Bypass top-level module */
std::string module_name = module_manager.module_name(curr_module);
if (module_name == generate_fpga_top_module_name() ||
module_name == generate_fpga_core_module_name()) {
return CMD_EXEC_SUCCESS;
}
/* Bypass modules which does not have any configurable children */
if (module_manager.configurable_children(curr_module).empty()) {
return CMD_EXEC_SUCCESS;
}
/* Now create the module and add subkey one by one */
FabricKeyModuleId key_module_id = fabric_key.create_module(module_name);
if (!key_module_id) {
return CMD_EXEC_FATAL_ERROR;
}
size_t num_config_child =
module_manager.configurable_children(curr_module).size();
for (size_t ichild = 0; ichild < num_config_child; ++ichild) {
ModuleId child_module =
module_manager.configurable_children(curr_module)[ichild];
size_t child_instance =
module_manager.configurable_child_instances(curr_module)[ichild];
FabricSubKeyId sub_key = fabric_key.create_module_key(key_module_id);
fabric_key.set_sub_key_name(sub_key,
module_manager.module_name(child_module));
fabric_key.set_sub_key_value(sub_key, child_instance);
if (false ==
module_manager.instance_name(curr_module, child_module, child_instance)
.empty()) {
fabric_key.set_sub_key_alias(
sub_key, module_manager.instance_name(curr_module, child_module,
child_instance));
}
}
return CMD_EXEC_SUCCESS;
}
/***************************************************************************************
* Write the fabric key of top module to an XML file
* We will use the writer API in libfabrickey
@ -29,7 +75,9 @@ namespace openfpga {
int write_fabric_key_to_xml_file(
const ModuleManager& module_manager, const std::string& fname,
const ConfigProtocol& config_protocol,
const MemoryBankShiftRegisterBanks& blwl_sr_banks, const bool& verbose) {
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const bool& include_module_keys, const bool& verbose) {
int err_code = CMD_EXEC_SUCCESS;
std::string timer_message =
std::string("Write fabric key to XML file '") + fname + std::string("'");
@ -47,10 +95,18 @@ int write_fabric_key_to_xml_file(
/* Find top-level module */
std::string top_module_name = generate_fpga_top_module_name();
ModuleId top_module = module_manager.find_module(top_module_name);
if (true != module_manager.valid_module_id(top_module)) {
VTR_LOGV_ERROR(verbose, "Unable to find the top-level module '%s'!\n",
top_module_name.c_str());
return 1;
std::string core_module_name = generate_fpga_core_module_name();
ModuleId core_module = module_manager.find_module(core_module_name);
if (!module_manager.valid_module_id(top_module) &&
!module_manager.valid_module_id(core_module)) {
VTR_LOGV_ERROR(
verbose, "Unable to find the top-level/core-level module '%s' or '%s'!\n",
top_module_name.c_str(), core_module_name.c_str());
return CMD_EXEC_FATAL_ERROR;
}
if (module_manager.valid_module_id(top_module) &&
module_manager.valid_module_id(core_module)) {
top_module = core_module;
}
/* Build a fabric key database by visiting all the configurable children */
@ -165,8 +221,19 @@ int write_fabric_key_to_xml_file(
VTR_LOGV(verbose, "Created %lu regions and %lu keys for the top module %s.\n",
num_regions, num_keys, top_module_name.c_str());
/* Output module subkeys if specified */
if (include_module_keys) {
for (ModuleId submodule : module_manager.modules()) {
err_code =
add_module_keys_to_fabric_key(module_manager, submodule, fabric_key);
if (err_code != CMD_EXEC_SUCCESS) {
return CMD_EXEC_FATAL_ERROR;
}
}
}
/* Call the XML writer for fabric key */
int err_code = write_xml_fabric_key(fname.c_str(), fabric_key);
err_code = write_xml_fabric_key(fname.c_str(), fabric_key);
return err_code;
}

View File

@ -20,7 +20,8 @@ namespace openfpga {
int write_fabric_key_to_xml_file(
const ModuleManager& module_manager, const std::string& fname,
const ConfigProtocol& config_protocol,
const MemoryBankShiftRegisterBanks& blwl_sr_banks, const bool& verbose);
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const bool& include_module_keys, const bool& verbose);
} /* end namespace openfpga */

View File

@ -1320,6 +1320,15 @@ void ModuleManager::clear_io_children(const ModuleId& parent_module) {
io_child_coordinates_[parent_module].clear();
}
void ModuleManager::clear_module_net_sinks(const ModuleId& parent_module,
const ModuleNetId& net) {
VTR_ASSERT(valid_module_net_id(parent_module, net));
net_sink_ids_[parent_module][net].clear();
net_sink_terminal_ids_[parent_module][net].clear();
net_sink_instance_ids_[parent_module][net].clear();
net_sink_pin_ids_[parent_module][net].clear();
}
/******************************************************************************
* Private validators/invalidators
******************************************************************************/

View File

@ -469,6 +469,10 @@ class ModuleManager {
*/
void clear_io_children(const ModuleId& parent_module);
/* Remove all the sinks for a given net under a module */
void clear_module_net_sinks(const ModuleId& parent_module,
const ModuleNetId& net);
public: /* Public validators/invalidators */
bool valid_module_id(const ModuleId& module) const;
bool valid_module_port_id(const ModuleId& module,

View File

@ -0,0 +1,563 @@
/******************************************************************************
* This files includes most utilized functions
* for data structures for module management.
******************************************************************************/
#include <algorithm>
#include <cmath>
#include <map>
/* Headers from vtrutil library */
#include "command_exit_codes.h"
#include "vtr_assert.h"
#include "vtr_log.h"
/* Headers from openfpgautil library */
#include "build_decoder_modules.h"
#include "circuit_library_utils.h"
#include "decoder_library_utils.h"
#include "memory_utils.h"
#include "module_manager_memory_utils.h"
#include "module_manager_utils.h"
#include "openfpga_naming.h"
#include "openfpga_port.h"
#include "openfpga_reserved_words.h"
#include "pb_type_utils.h"
/* begin namespace openfpga */
namespace openfpga {
/********************************************************************
* Compare the configurable children list with a given list of fabric sub-keys
* Return true if exact naming-matches are found
* When searching for matching, we consider
* - alias is treated as No. 1 reference
* - the <name, value> pair as No. 2 reference
*******************************************************************/
static bool submodule_memory_modules_match_fabric_key(
ModuleManager& module_manager, const ModuleId& module_id,
const FabricKey& fabric_key, const FabricKeyModuleId& key_module_id) {
/* If the length does not match, conclusion is easy to be made */
size_t len_module_memory =
module_manager.configurable_children(module_id).size();
size_t len_fabric_sub_key = fabric_key.sub_keys(key_module_id).size();
if (len_module_memory != len_fabric_sub_key) {
return false;
}
/* Now walk through the child one by one */
for (size_t ikey = 0; ikey < len_module_memory; ++ikey) {
FabricSubKeyId key_id = fabric_key.sub_keys(key_module_id)[ikey];
std::pair<ModuleId, size_t> inst_info(ModuleId::INVALID(), 0);
/* Try to match the alias */
if (!fabric_key.sub_key_alias(key_id).empty()) {
if (!fabric_key.sub_key_name(key_id).empty()) {
inst_info.first =
module_manager.find_module(fabric_key.sub_key_name(key_id));
inst_info.second = module_manager.instance_id(
module_id, inst_info.first, fabric_key.sub_key_alias(key_id));
} else {
inst_info = find_module_manager_instance_module_info(
module_manager, module_id, fabric_key.sub_key_alias(key_id));
}
} else {
inst_info.first =
module_manager.find_module(fabric_key.sub_key_name(key_id));
inst_info.second = fabric_key.sub_key_value(key_id);
}
if (inst_info.first !=
module_manager.configurable_children(module_id)[ikey] ||
inst_info.second !=
module_manager.configurable_child_instances(module_id)[ikey]) {
return false;
}
}
return true;
}
/********************************************************************
* Update the configurable children list based on fabric key definitions
*******************************************************************/
static bool update_submodule_memory_modules_from_fabric_key(
ModuleManager& module_manager, const ModuleId& module_id,
const CircuitLibrary& circuit_lib, const ConfigProtocol& config_protocol,
const FabricKey& fabric_key, const FabricKeyModuleId& key_module_id) {
/* Reset the configurable children */
module_manager.clear_configurable_children(module_id);
for (FabricSubKeyId key_id : fabric_key.sub_keys(key_module_id)) {
std::pair<ModuleId, size_t> inst_info(ModuleId::INVALID(), 0);
/* Try to match the alias */
if (!fabric_key.sub_key_alias(key_id).empty()) {
if (!fabric_key.sub_key_name(key_id).empty()) {
inst_info.first =
module_manager.find_module(fabric_key.sub_key_name(key_id));
inst_info.second = module_manager.instance_id(
module_id, inst_info.first, fabric_key.sub_key_alias(key_id));
} else {
inst_info = find_module_manager_instance_module_info(
module_manager, module_id, fabric_key.sub_key_alias(key_id));
}
} else {
inst_info.first =
module_manager.find_module(fabric_key.sub_key_name(key_id));
inst_info.second = fabric_key.sub_key_value(key_id);
}
if (false == module_manager.valid_module_id(inst_info.first)) {
if (!fabric_key.sub_key_alias(key_id).empty()) {
VTR_LOG_ERROR("Invalid key alias '%s'!\n",
fabric_key.sub_key_alias(key_id).c_str());
} else {
VTR_LOG_ERROR("Invalid key name '%s'!\n",
fabric_key.sub_key_name(key_id).c_str());
}
return CMD_EXEC_FATAL_ERROR;
}
if (false == module_manager.valid_module_instance_id(
module_id, inst_info.first, inst_info.second)) {
if (!fabric_key.sub_key_alias(key_id).empty()) {
VTR_LOG_ERROR("Invalid key alias '%s'!\n",
fabric_key.sub_key_alias(key_id).c_str());
} else {
VTR_LOG_ERROR("Invalid key value '%ld'!\n", inst_info.second);
}
return CMD_EXEC_FATAL_ERROR;
}
/* If the the child has not configuration bits, error out */
if (0 == find_module_num_config_bits(
module_manager, inst_info.first, circuit_lib,
config_protocol.memory_model(), config_protocol.type())) {
if (!fabric_key.sub_key_alias(key_id).empty()) {
VTR_LOG_ERROR(
"Invalid key alias '%s' which has zero configuration bits!\n",
fabric_key.sub_key_alias(key_id).c_str());
} else {
VTR_LOG_ERROR(
"Invalid key name '%s' which has zero configuration bits!\n",
fabric_key.sub_key_name(key_id).c_str());
}
return CMD_EXEC_FATAL_ERROR;
}
/* Now we can add the child to configurable children of the top module */
module_manager.add_configurable_child(module_id, inst_info.first,
inst_info.second, vtr::Point<int>());
}
return CMD_EXEC_SUCCESS;
}
/********************************************************************
* Remove the nets around the configuration chain (ccff_head and ccff_tails)
*******************************************************************/
static int remove_submodule_nets_cmos_memory_chain_config_bus(
ModuleManager& module_manager, const ModuleId& parent_module,
const e_config_protocol_type& sram_orgz_type) {
for (size_t mem_index = 0;
mem_index < module_manager.configurable_children(parent_module).size();
++mem_index) {
ModuleId net_src_module_id;
size_t net_src_instance_id;
ModulePortId net_src_port_id;
if (0 == mem_index) {
/* Find the port name of configuration chain head */
std::string src_port_name =
generate_sram_port_name(sram_orgz_type, CIRCUIT_MODEL_PORT_INPUT);
net_src_module_id = parent_module;
net_src_instance_id = 0;
net_src_port_id =
module_manager.find_module_port(net_src_module_id, src_port_name);
} else {
/* Find the port name of previous memory module */
std::string src_port_name = generate_configuration_chain_tail_name();
net_src_module_id =
module_manager.configurable_children(parent_module)[mem_index - 1];
net_src_instance_id = module_manager.configurable_child_instances(
parent_module)[mem_index - 1];
net_src_port_id =
module_manager.find_module_port(net_src_module_id, src_port_name);
}
/* Get the pin id for source port */
BasicPort net_src_port =
module_manager.module_port(net_src_module_id, net_src_port_id);
/* Create a net for each pin */
for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) {
/* Find the net from which the source node is driving */
ModuleNetId net = module_manager.module_instance_port_net(
parent_module, net_src_module_id, net_src_instance_id, net_src_port_id,
net_src_port.pins()[pin_id]);
/* Remove the net including sources and sinks */
module_manager.clear_module_net_sinks(parent_module, net);
}
}
/* For the last memory module:
* net source is the configuration chain tail of the previous memory module
* net sink is the configuration chain tail of the primitive module
*/
/* Find the port name of previous memory module */
std::string src_port_name = generate_configuration_chain_tail_name();
ModuleId net_src_module_id =
module_manager.configurable_children(parent_module).back();
size_t net_src_instance_id =
module_manager.configurable_child_instances(parent_module).back();
ModulePortId net_src_port_id =
module_manager.find_module_port(net_src_module_id, src_port_name);
/* Get the pin id for source port */
BasicPort net_src_port =
module_manager.module_port(net_src_module_id, net_src_port_id);
/* Create a net for each pin */
for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) {
/* Find the net from which the source node is driving */
ModuleNetId net = module_manager.module_instance_port_net(
parent_module, net_src_module_id, net_src_instance_id, net_src_port_id,
net_src_port.pins()[pin_id]);
/* Remove the net including sources and sinks */
module_manager.clear_module_net_sinks(parent_module, net);
}
return CMD_EXEC_SUCCESS;
}
/********************************************************************
* Remove the nets around the configurable children for a given module which
*should be in CMOS type
*******************************************************************/
static int remove_submodule_nets_cmos_memory_config_bus(
ModuleManager& module_manager, const ModuleId& module_id,
const e_config_protocol_type& sram_orgz_type) {
switch (sram_orgz_type) {
case CONFIG_MEM_SCAN_CHAIN: {
return remove_submodule_nets_cmos_memory_chain_config_bus(
module_manager, module_id, sram_orgz_type);
break;
}
case CONFIG_MEM_STANDALONE:
case CONFIG_MEM_QL_MEMORY_BANK:
/* TODO:
add_module_nets_cmos_memory_bank_bl_config_bus(
module_manager, parent_module, sram_orgz_type, CIRCUIT_MODEL_PORT_BL);
add_module_nets_cmos_memory_bank_wl_config_bus(
module_manager, parent_module, sram_orgz_type, CIRCUIT_MODEL_PORT_WL);
add_module_nets_cmos_memory_bank_wl_config_bus(
module_manager, parent_module, sram_orgz_type, CIRCUIT_MODEL_PORT_WLR);
*/
break;
case CONFIG_MEM_MEMORY_BANK:
/* TODO:
add_module_nets_cmos_flatten_memory_config_bus(
module_manager, parent_module, sram_orgz_type, CIRCUIT_MODEL_PORT_BL);
add_module_nets_cmos_flatten_memory_config_bus(
module_manager, parent_module, sram_orgz_type, CIRCUIT_MODEL_PORT_WL);
*/
break;
case CONFIG_MEM_FRAME_BASED:
/* TODO:
add_module_nets_cmos_memory_frame_config_bus(module_manager, decoder_lib,
parent_module);
*/
break;
default:
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Invalid type of SRAM organization!\n");
return CMD_EXEC_FATAL_ERROR;
}
return CMD_EXEC_FATAL_ERROR;
}
/********************************************************************
* Remove the nets around the configurable children for a given module
*******************************************************************/
static int remove_submodule_configurable_children_nets(
ModuleManager& module_manager, const ModuleId& module_id,
const CircuitLibrary& circuit_lib, const ConfigProtocol& config_protocol) {
switch (circuit_lib.design_tech_type(config_protocol.memory_model())) {
case CIRCUIT_MODEL_DESIGN_CMOS:
return remove_submodule_nets_cmos_memory_config_bus(
module_manager, module_id, config_protocol.type());
break;
case CIRCUIT_MODEL_DESIGN_RRAM:
/* TODO: */
break;
default:
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Invalid type of memory design technology!\n");
return CMD_EXEC_FATAL_ERROR;
}
return CMD_EXEC_FATAL_ERROR;
}
/********************************************************************
* Rebuild the nets(only sinks) around the configuration chain (ccff_head and
*ccff_tails)
*******************************************************************/
static int rebuild_submodule_nets_cmos_memory_chain_config_bus(
ModuleManager& module_manager, const ModuleId& parent_module,
const e_config_protocol_type& sram_orgz_type) {
for (size_t mem_index = 0;
mem_index < module_manager.configurable_children(parent_module).size();
++mem_index) {
ModuleId net_src_module_id;
size_t net_src_instance_id;
ModulePortId net_src_port_id;
ModuleId net_sink_module_id;
size_t net_sink_instance_id;
ModulePortId net_sink_port_id;
if (0 == mem_index) {
/* Find the port name of configuration chain head */
std::string src_port_name =
generate_sram_port_name(sram_orgz_type, CIRCUIT_MODEL_PORT_INPUT);
net_src_module_id = parent_module;
net_src_instance_id = 0;
net_src_port_id =
module_manager.find_module_port(net_src_module_id, src_port_name);
/* Find the port name of next memory module */
std::string sink_port_name = generate_configuration_chain_head_name();
net_sink_module_id =
module_manager.configurable_children(parent_module)[mem_index];
net_sink_instance_id =
module_manager.configurable_child_instances(parent_module)[mem_index];
net_sink_port_id =
module_manager.find_module_port(net_sink_module_id, sink_port_name);
} else {
/* Find the port name of previous memory module */
std::string src_port_name = generate_configuration_chain_tail_name();
net_src_module_id =
module_manager.configurable_children(parent_module)[mem_index - 1];
net_src_instance_id = module_manager.configurable_child_instances(
parent_module)[mem_index - 1];
net_src_port_id =
module_manager.find_module_port(net_src_module_id, src_port_name);
/* Find the port name of next memory module */
std::string sink_port_name = generate_configuration_chain_head_name();
net_sink_module_id =
module_manager.configurable_children(parent_module)[mem_index];
net_sink_instance_id =
module_manager.configurable_child_instances(parent_module)[mem_index];
net_sink_port_id =
module_manager.find_module_port(net_sink_module_id, sink_port_name);
}
/* Get the pin id for source port */
BasicPort net_src_port =
module_manager.module_port(net_src_module_id, net_src_port_id);
/* Get the pin id for sink port */
BasicPort net_sink_port =
module_manager.module_port(net_sink_module_id, net_sink_port_id);
/* Port sizes of source and sink should match */
VTR_ASSERT(net_src_port.get_width() == net_sink_port.get_width());
/* Create a net for each pin */
for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) {
/* Create a net and add source and sink to it */
ModuleNetId net = create_module_source_pin_net(
module_manager, parent_module, net_src_module_id, net_src_instance_id,
net_src_port_id, net_src_port.pins()[pin_id]);
/* Add net sink */
module_manager.add_module_net_sink(parent_module, net, net_sink_module_id,
net_sink_instance_id, net_sink_port_id,
net_sink_port.pins()[pin_id]);
}
}
/* For the last memory module:
* net source is the configuration chain tail of the previous memory module
* net sink is the configuration chain tail of the primitive module
*/
/* Find the port name of previous memory module */
std::string src_port_name = generate_configuration_chain_tail_name();
ModuleId net_src_module_id =
module_manager.configurable_children(parent_module).back();
size_t net_src_instance_id =
module_manager.configurable_child_instances(parent_module).back();
ModulePortId net_src_port_id =
module_manager.find_module_port(net_src_module_id, src_port_name);
/* Find the port name of next memory module */
std::string sink_port_name =
generate_sram_port_name(sram_orgz_type, CIRCUIT_MODEL_PORT_OUTPUT);
ModuleId net_sink_module_id = parent_module;
size_t net_sink_instance_id = 0;
ModulePortId net_sink_port_id =
module_manager.find_module_port(net_sink_module_id, sink_port_name);
/* Get the pin id for source port */
BasicPort net_src_port =
module_manager.module_port(net_src_module_id, net_src_port_id);
/* Get the pin id for sink port */
BasicPort net_sink_port =
module_manager.module_port(net_sink_module_id, net_sink_port_id);
/* Port sizes of source and sink should match */
VTR_ASSERT(net_src_port.get_width() == net_sink_port.get_width());
/* Create a net for each pin */
for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) {
/* Create a net and add source and sink to it */
ModuleNetId net = create_module_source_pin_net(
module_manager, parent_module, net_src_module_id, net_src_instance_id,
net_src_port_id, net_src_port.pins()[pin_id]);
/* Add net sink */
module_manager.add_module_net_sink(parent_module, net, net_sink_module_id,
net_sink_instance_id, net_sink_port_id,
net_sink_port.pins()[pin_id]);
}
return CMD_EXEC_SUCCESS;
}
/********************************************************************
* Rebuild the nets around the configurable children for a given module which
*should be in CMOS type
*******************************************************************/
static int rebuild_submodule_nets_cmos_memory_config_bus(
ModuleManager& module_manager, const ModuleId& module_id,
const e_config_protocol_type& sram_orgz_type) {
switch (sram_orgz_type) {
case CONFIG_MEM_SCAN_CHAIN: {
return rebuild_submodule_nets_cmos_memory_chain_config_bus(
module_manager, module_id, sram_orgz_type);
break;
}
case CONFIG_MEM_STANDALONE:
case CONFIG_MEM_QL_MEMORY_BANK:
/* TODO:
add_module_nets_cmos_memory_bank_bl_config_bus(
module_manager, parent_module, sram_orgz_type, CIRCUIT_MODEL_PORT_BL);
add_module_nets_cmos_memory_bank_wl_config_bus(
module_manager, parent_module, sram_orgz_type, CIRCUIT_MODEL_PORT_WL);
add_module_nets_cmos_memory_bank_wl_config_bus(
module_manager, parent_module, sram_orgz_type, CIRCUIT_MODEL_PORT_WLR);
*/
break;
case CONFIG_MEM_MEMORY_BANK:
/* TODO:
add_module_nets_cmos_flatten_memory_config_bus(
module_manager, parent_module, sram_orgz_type, CIRCUIT_MODEL_PORT_BL);
add_module_nets_cmos_flatten_memory_config_bus(
module_manager, parent_module, sram_orgz_type, CIRCUIT_MODEL_PORT_WL);
*/
break;
case CONFIG_MEM_FRAME_BASED:
/* TODO:
add_module_nets_cmos_memory_frame_config_bus(module_manager, decoder_lib,
parent_module);
*/
break;
default:
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Invalid type of SRAM organization!\n");
return CMD_EXEC_FATAL_ERROR;
}
return CMD_EXEC_FATAL_ERROR;
}
/********************************************************************
* Rebuild the nets(only sinks) around the configurable children for a given
*module
*******************************************************************/
static int rebuild_submodule_configurable_children_nets(
ModuleManager& module_manager, const ModuleId& module_id,
const CircuitLibrary& circuit_lib, const ConfigProtocol& config_protocol) {
switch (circuit_lib.design_tech_type(config_protocol.memory_model())) {
case CIRCUIT_MODEL_DESIGN_CMOS:
return rebuild_submodule_nets_cmos_memory_config_bus(
module_manager, module_id, config_protocol.type());
break;
case CIRCUIT_MODEL_DESIGN_RRAM:
/* TODO: */
break;
default:
VTR_LOGF_ERROR(__FILE__, __LINE__,
"Invalid type of memory design technology!\n");
return CMD_EXEC_FATAL_ERROR;
}
return CMD_EXEC_FATAL_ERROR;
}
/********************************************************************
* Load and update the configurable children of a given module (not a top-level
*module) Compare the configurable children list with fabric sub-keys.
* - If match, nothing should be done
* - If not match,
* - remove the nets related to configurable children
* - rebuild the configurable children list
* - add the nets related to configurable children
*******************************************************************/
static int load_and_update_submodule_memory_modules_from_fabric_key(
ModuleManager& module_manager, const ModuleId& module_id,
const CircuitLibrary& circuit_lib, const ConfigProtocol& config_protocol,
const FabricKey& fabric_key, const FabricKeyModuleId& key_module_id) {
int status = CMD_EXEC_SUCCESS;
/* Compare the configurable children list */
if (submodule_memory_modules_match_fabric_key(module_manager, module_id,
fabric_key, key_module_id)) {
return CMD_EXEC_SUCCESS;
}
/* Do not match, now remove all the nets for the configurable children */
status = remove_submodule_configurable_children_nets(
module_manager, module_id, circuit_lib, config_protocol);
if (status == CMD_EXEC_FATAL_ERROR) {
return status;
}
/* Overwrite the configurable children list */
status = update_submodule_memory_modules_from_fabric_key(
module_manager, module_id, circuit_lib, config_protocol, fabric_key,
key_module_id);
if (status == CMD_EXEC_FATAL_ERROR) {
return status;
}
/* TODO: Create the nets for the new list of configurable children */
status = rebuild_submodule_configurable_children_nets(
module_manager, module_id, circuit_lib, config_protocol);
if (status == CMD_EXEC_FATAL_ERROR) {
return status;
}
return status;
}
/********************************************************************
* Load and update the configurable children of a given list of modules (not a
*top-level module)
*******************************************************************/
int load_submodules_memory_modules_from_fabric_key(
ModuleManager& module_manager, const CircuitLibrary& circuit_lib,
const ConfigProtocol& config_protocol, const FabricKey& fabric_key) {
int status = CMD_EXEC_SUCCESS;
for (FabricKeyModuleId key_module_id : fabric_key.modules()) {
std::string module_name = fabric_key.module_name(key_module_id);
/* Ensure this is not a top module! */
if (module_name == std::string(FPGA_TOP_MODULE_NAME)) {
VTR_LOG_ERROR(
"Expect a non-top-level name for the sub-module '%s' in fabric key!\n",
module_name.c_str());
return CMD_EXEC_FATAL_ERROR;
}
ModuleId module_id = module_manager.find_module(module_name);
if (module_id) {
/* This is a valid module, try to load and update */
status = load_and_update_submodule_memory_modules_from_fabric_key(
module_manager, module_id, circuit_lib, config_protocol, fabric_key,
key_module_id);
if (status == CMD_EXEC_FATAL_ERROR) {
return status;
}
} else {
/* Not a valid module, report error */
VTR_LOG_ERROR(
"The sub-module '%s' in fabric key is not a valid module in FPGA "
"fabric!\n",
module_name.c_str());
return CMD_EXEC_FATAL_ERROR;
}
}
return status;
}
} /* end namespace openfpga */

View File

@ -0,0 +1,41 @@
/******************************************************************************
* This files includes declarations for most utilized functions
* for data structures for module management.
******************************************************************************/
#ifndef MODULE_MANAGER_MEMORY_UTILS_H
#define MODULE_MANAGER_MEMORY_UTILS_H
/********************************************************************
* Include header files that are required by function declaration
*******************************************************************/
#include <tuple>
#include <vector>
/* Headers from readarch library */
#include "physical_types.h"
/* Headers from openfpgautil library */
#include "openfpga_port.h"
/* Headers from readarchopenfpga library */
#include "circuit_library.h"
#include "circuit_types.h"
#include "config_protocol.h"
#include "decoder_library.h"
#include "fabric_key.h"
#include "module_manager.h"
/********************************************************************
* Function declaration
*******************************************************************/
/* begin namespace openfpga */
namespace openfpga {
int load_submodules_memory_modules_from_fabric_key(
ModuleManager& module_manager, const CircuitLibrary& circuit_lib,
const ConfigProtocol& config_protocol, const FabricKey& fabric_key);
} /* end namespace openfpga */
#endif

View File

@ -8,6 +8,7 @@
#include <map>
/* Headers from vtrutil library */
#include "command_exit_codes.h"
#include "vtr_assert.h"
#include "vtr_log.h"

View File

@ -20,7 +20,9 @@
/* Headers from readarchopenfpga library */
#include "circuit_library.h"
#include "circuit_types.h"
#include "config_protocol.h"
#include "decoder_library.h"
#include "fabric_key.h"
#include "module_manager.h"
#include "vpr_device_annotation.h"

View File

@ -1,4 +1,5 @@
<fabric_key>
<module name="fpga_top">
<region id="0">
<bl_shift_register_banks>
<bank id="0" range="bl[0:16]"/>
@ -22,4 +23,5 @@
<key id="11" name="cby_1__1_" value="0" alias="cby_1__1_" column="3" row="2"/>
<key id="12" name="grid_clb" value="0" alias="grid_clb_1__1_" column="2" row="2"/>
</region>
</module>
</fabric_key>

View File

@ -1,4 +1,5 @@
<fabric_key>
<module name="fpga_top">
<region id="0">
<key id="0" name="grid_io_bottom" value="1" alias="grid_io_bottom_1__0_" column="2" row="0"/>
<key id="1" name="grid_io_bottom" value="0" alias="grid_io_bottom_2__0_" column="4" row="0"/>
@ -36,4 +37,5 @@
<key id="31" name="cby_1__1_" value="1" alias="cby_1__2_" column="3" row="4"/>
<key id="32" name="grid_clb" value="1" alias="grid_clb_1__2_" column="2" row="4"/>
</region>
</module>
</fabric_key>

View File

@ -1,4 +1,5 @@
<fabric_key>
<module name="fpga_top">
<region id="0">
<bl_shift_register_banks>
<bank id="0" range="bl[0:61]"/>
@ -48,4 +49,5 @@
<key id="31" name="cby_1__1_" value="1" alias="cby_1__2_" column="3" row="4"/>
<key id="32" name="grid_clb" value="1" alias="grid_clb_1__2_" column="2" row="4"/>
</region>
</module>
</fabric_key>

View File

@ -1,4 +1,5 @@
<fabric_key>
<module name="fpga_top">
<region id="0">
<key id="0" name="grid_io_bottom" value="0" alias="grid_io_bottom_1__0_"/>
<key id="1" name="grid_io_right" value="0" alias="grid_io_right_2__1_"/>
@ -20,4 +21,5 @@
<key id="11" name="cby_1__1_" value="0" alias="cby_1__1_"/>
<key id="12" name="grid_clb" value="0" alias="grid_clb_1__1_"/>
</region>
</module>
</fabric_key>

View File

@ -1,4 +1,5 @@
<fabric_key>
<module name="fpga_top">
<region id="0">
<key id="0" name="sb_2__2_" value="0" alias="sb_2__2_" column="5" row="5"/>
<key id="1" name="grid_clb" value="3" alias="grid_clb_2__2_" column="4" row="4"/>
@ -34,4 +35,5 @@
<key id="31" name="grid_io_top" value="0" alias="grid_io_top_1__3_" column="2" row="6"/>
<key id="32" name="grid_io_left" value="1" alias="grid_io_left_0__2_" column="0" row="4"/>
</region>
</module>
</fabric_key>

View File

@ -1,4 +1,5 @@
<fabric_key>
<module name="fpga_top">
<region id="0">
<key id="0" name="sb_2__2_" value="0" alias="sb_2__2_"/>
<key id="1" name="grid_clb" value="3" alias="grid_clb_2__2_"/>
@ -34,4 +35,5 @@
<key id="31" name="grid_io_top" value="0" alias="grid_io_top_1__3_"/>
<key id="32" name="grid_io_left" value="1" alias="grid_io_left_0__2_"/>
</region>
</module>
</fabric_key>

View File

@ -0,0 +1,61 @@
<fabric_key>
<module name="fpga_top">
<region id="0">
<key id="0" name="sb_2__2_" value="0" alias="sb_2__2_"/>
<key id="1" name="grid_clb" value="3" alias="grid_clb_2__2_"/>
<key id="2" name="sb_0__1_" value="0" alias="sb_0__1_"/>
<key id="3" name="cby_0__1_" value="0" alias="cby_0__1_"/>
<key id="4" name="grid_clb" value="2" alias="grid_clb_2__1_"/>
<key id="5" name="grid_io_left" value="0" alias="grid_io_left_0__1_"/>
<key id="6" name="sb_1__0_" value="0" alias="sb_1__0_"/>
<key id="7" name="sb_1__1_" value="0" alias="sb_1__1_"/>
<key id="8" name="cbx_1__1_" value="1" alias="cbx_2__1_"/>
<key id="9" name="cby_1__1_" value="1" alias="cby_1__2_"/>
<key id="10" name="grid_io_right" value="0" alias="grid_io_right_3__2_"/>
<key id="11" name="cbx_1__0_" value="1" alias="cbx_2__0_"/>
<key id="12" name="cby_1__1_" value="0" alias="cby_1__1_"/>
<key id="13" name="grid_io_right" value="1" alias="grid_io_right_3__1_"/>
<key id="14" name="grid_io_bottom" value="1" alias="grid_io_bottom_1__0_"/>
<key id="15" name="cby_2__1_" value="0" alias="cby_2__1_"/>
<key id="16" name="sb_2__1_" value="0" alias="sb_2__1_"/>
<key id="17" name="cbx_1__0_" value="0" alias="cbx_1__0_"/>
<key id="18" name="grid_clb" value="1" alias="grid_clb_1__2_"/>
<key id="19" name="cbx_1__2_" value="0" alias="cbx_1__2_"/>
<key id="20" name="cbx_1__2_" value="1" alias="cbx_2__2_"/>
<key id="21" name="sb_2__0_" value="0" alias="sb_2__0_"/>
<key id="22" name="sb_1__2_" value="0" alias="sb_1__2_"/>
<key id="23" name="cby_0__1_" value="1" alias="cby_0__2_"/>
<key id="24" name="sb_0__0_" value="0" alias="sb_0__0_"/>
<key id="25" name="grid_clb" value="0" alias="grid_clb_1__1_"/>
<key id="26" name="cby_2__1_" value="1" alias="cby_2__2_"/>
<key id="27" name="grid_io_top" value="1" alias="grid_io_top_2__3_"/>
<key id="28" name="sb_0__2_" value="0" alias="sb_0__2_"/>
<key id="29" name="grid_io_bottom" value="0" alias="grid_io_bottom_2__0_"/>
<key id="30" name="cbx_1__1_" value="0" alias="cbx_1__1_"/>
<key id="31" name="grid_io_top" value="0" alias="grid_io_top_1__3_"/>
<key id="32" name="grid_io_left" value="1" alias="grid_io_left_0__2_"/>
</region>
</module>
<module name="logical_tile_clb_mode_clb_">
<key id="0" name="logical_tile_clb_mode_default__fle" value="1" alias="logical_tile_clb_mode_default__fle_1"/>
<key id="1" name="logical_tile_clb_mode_default__fle" value="0" alias="logical_tile_clb_mode_default__fle_0"/>
<key id="2" name="logical_tile_clb_mode_default__fle" value="3" alias="logical_tile_clb_mode_default__fle_3"/>
<key id="3" name="mux_tree_size14_mem" value="0" alias="mem_fle_0_in_0"/>
<key id="4" name="logical_tile_clb_mode_default__fle" value="2" alias="logical_tile_clb_mode_default__fle_2"/>
<key id="5" name="mux_tree_size14_mem" value="1" alias="mem_fle_0_in_1"/>
<key id="6" name="mux_tree_size14_mem" value="2" alias="mem_fle_0_in_2"/>
<key id="7" name="mux_tree_size14_mem" value="3" alias="mem_fle_0_in_3"/>
<key id="8" name="mux_tree_size14_mem" value="4" alias="mem_fle_1_in_0"/>
<key id="9" name="mux_tree_size14_mem" value="5" alias="mem_fle_1_in_1"/>
<key id="10" name="mux_tree_size14_mem" value="6" alias="mem_fle_1_in_2"/>
<key id="11" name="mux_tree_size14_mem" value="7" alias="mem_fle_1_in_3"/>
<key id="12" name="mux_tree_size14_mem" value="8" alias="mem_fle_2_in_0"/>
<key id="13" name="mux_tree_size14_mem" value="9" alias="mem_fle_2_in_1"/>
<key id="14" name="mux_tree_size14_mem" value="10" alias="mem_fle_2_in_2"/>
<key id="15" name="mux_tree_size14_mem" value="11" alias="mem_fle_2_in_3"/>
<key id="16" name="mux_tree_size14_mem" value="12" alias="mem_fle_3_in_0"/>
<key id="17" name="mux_tree_size14_mem" value="13" alias="mem_fle_3_in_1"/>
<key id="18" name="mux_tree_size14_mem" value="14" alias="mem_fle_3_in_2"/>
<key id="19" name="mux_tree_size14_mem" value="15" alias="mem_fle_3_in_3"/>
</module>
</fabric_key>

View File

@ -116,6 +116,7 @@ run-task basic_tests/fabric_key/generate_random_key $@
run-task basic_tests/fabric_key/generate_random_key_ql_memory_bank $@
run-task basic_tests/fabric_key/load_external_key $@
run-task basic_tests/fabric_key/load_external_key_cc_fpga $@
run-task basic_tests/fabric_key/load_external_subkey_cc_fpga $@
run-task basic_tests/fabric_key/load_external_key_multi_region_cc_fpga $@
run-task basic_tests/fabric_key/load_external_key_qlbank_fpga $@
run-task basic_tests/fabric_key/load_external_key_multi_region_qlbank_fpga $@

View File

@ -0,0 +1,39 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# 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=vpr_blif
[OpenFPGA_SHELL]
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/generate_secure_fabric_from_key_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
external_fabric_key_file=${PATH:OPENFPGA_PATH}/openfpga_flow/fabric_keys/k4_N4_2x2_sample_subkey.xml
openfpga_vpr_device_layout=2x2
[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.blif
[SYNTHESIS_PARAM]
bench0_top = and2
bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.act
bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
bench0_chan_width = 300
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
end_flow_with_test=
#vpr_fpga_verilog_formal_verification_top_netlist=