Merge pull request #26 from RapidSilicon/qlbank_multibank_sr

Now QuickLogic Memory Bank Support Multiple Shift Register Chains in each Configuration Region
This commit is contained in:
tangxifan 2021-10-11 11:38:31 -07:00 committed by GitHub
commit c8ffc34125
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
43 changed files with 2248 additions and 313 deletions

View File

@ -167,8 +167,8 @@ The BL and WL protocols can be customized through the XML syntax ``bl`` and ``wl
<configuration_protocol>
<organization type="ql_memory_bank" circuit_model_name="sram_blwl">
<bl protocol="<string>"/>
<wl protocol="<string>"/>
<bl protocol="<string>" num_banks="<int>"/>
<wl protocol="<string>" num_banks="<int>"/>
</organization>
</configuration_protocol>
@ -203,6 +203,14 @@ The BL and WL protocols can be customized through the XML syntax ``bl`` and ``wl
Example of (a) a memory organization using shift register chains to control BL/WLs; (b) single memory bank across the fabric; and (c) multiple memory banks across the fabric.
.. option:: num_banks="<int>"
Specify the number of shift register banks (i.e., independent shift register chains) to be used in each configuration region. When enabled, the length of each shift register chain will be sized by OpenFPGA automatically based on the number of BL/WLs in each configuration region. OpenFPGA will try to create similar sizes for the shift register chains, in order to minimize the number of HDL modules. If not specified, the default number of banks will be ``1``.
.. note:: This is available applicable to shift-register-based BL/WL protocols
.. note:: More customization on the shift register chains can be enabled through :ref:`fabric_key`
.. note:: The flip-flop for WL shift register requires an enable signal to gate WL signals when loading WL shift registers

View File

@ -24,21 +24,54 @@ The following example shows how to define multiple configuration regions in the
<fabric_key>
<region id="0">
<bl_shift_register_banks>
<bank id="0" range="bl[0:24]"/>
<bank id="1" range="bl[25:40]"/>
</bl_shift_register_banks>
<wl_shift_register_banks>
<bank id="0" range="wl[0:19],wl[40:59]"/>
<bank id="1" range="wl[21:39],wl[60:69]"/>
</wl_shift_register_banks>
<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_"/>
<key id="2" name="sb_1__1_" value="0" alias="sb_1__1_"/>
</region>
<region id="1">
<bl_shift_register_banks>
<bank id="0" range="bl[0:24]"/>
<bank id="1" range="bl[25:40]"/>
</bl_shift_register_banks>
<wl_shift_register_banks>
<bank id="0" range="wl[0:19]"/>
</wl_shift_register_banks>
<key id="3" name="cbx_1__1_" value="0" alias="cbx_1__1_"/>
<key id="4" name="grid_io_top" value="0" alias="grid_io_top_1__2_"/>
<key id="5" name="sb_0__1_" value="0" alias="sb_0__1_"/>
</region>
<region id="2">
<bl_shift_register_banks>
<bank id="0" range="bl[0:24]"/>
<bank id="1" range="bl[25:40]"/>
<bank id="2" range="bl[41:59]"/>
</bl_shift_register_banks>
<wl_shift_register_banks>
<bank id="0" range="wl[0:19]"/>
<bank id="1" range="wl[21:39]"/>
</wl_shift_register_banks>
<key id="6" name="sb_0__0_" value="0" alias="sb_0__0_"/>
<key id="7" name="cby_0__1_" value="0" alias="cby_0__1_"/>
<key id="8" name="grid_io_left" value="0" alias="grid_io_left_0__1_"/>
</region>
<region id="3">
<bl_shift_register_banks>
<bank id="0" range="bl[0:24]"/>
<bank id="1" range="bl[25:40]"/>
</bl_shift_register_banks>
<wl_shift_register_banks>
<bank id="0" range="wl[0:19]"/>
<bank id="1" range="wl[21:39]"/>
<bank id="2" range="wl[40:49]"/>
</wl_shift_register_banks>
<key id="9" name="sb_1__0_" value="0" alias="sb_1__0_"/>
<key id="10" name="cbx_1__0_" value="0" alias="cbx_1__0_"/>
<key id="11" name="cby_1__1_" value="0" alias="cby_1__1_"/>
@ -200,3 +233,46 @@ This key contains only ``name``, ``value``, ``row`` and ``column``.
<key id="32" name="grid_io_left" value="1" alias="grid_io_left_0__2_" column="0" row="4"/>
</region>
</fabric_key>
BL Shift Register Banks
^^^^^^^^^^^^^^^^^^^^^^^
.. note:: The customizable is only available when the shift-register-based memory bank is selected in :ref:`config_protocol`
Each Bit-Line (BL) shift register bank is defined in the code block ``<bl_shift_register_banks>``.
A shift register bank may contain multiple shift register chains.
- each shift register chain can be defined using the ``bank`` syntax
- the BLs controlled by each chain can be customized through the ``range`` syntax.
.. option:: <bank id="<int>" range="<ports>"/>
- ``id`` indicates the sequence of the shift register chain in the bank. The id denotes the index in the head or tail bus. For example, ``id="0"`` means the head or tail of the shift register will be in the first bit of a head bus ``head[0:4]``
- ``range`` indicates ``BL`` port to be controlled by this shift register chain. Multiple BL ports can be defined but the sequence matters. For example, ``bl[0:3], bl[6:10]`` infers a 9-bit shift register chain whose output ports are connected from ``bl[0]`` to ``bl[10]``.
.. note:: When creating the range, you must know the number of BLs in the configuration region
.. note:: ports must use ``bl`` as the reserved port name
WL Shift Register Banks
^^^^^^^^^^^^^^^^^^^^^^^
.. note:: The customizable is only available when the shift-register-based memory bank is selected in :ref:`config_protocol`
Each Word-Line (WL) shift register bank is defined in the code block ``<wl_shift_register_banks>``.
A shift register bank may contain multiple shift register chains.
- each shift register chain can be defined using the ``bank`` syntax
- the BLs controlled by each chain can be customized through the ``range`` syntax.
.. option:: <bank id="<int>" range="<ports>"/>
- ``id`` indicates the sequence of the shift register chain in the bank. The id denotes the index in the head or tail bus. For example, ``id="0"`` means the head or tail of the shift register will be in the first bit of a head bus ``head[0:4]``
- ``range`` indicates ``WL`` port to be controlled by this shift register chain. Multiple WL ports can be defined but the sequence matters. For example, ``wl[0:3], wl[6:10]`` infers a 9-bit shift register chain whose output ports are connected from ``wl[0]`` to ``wl[10]``.
.. note:: When creating the range, you must know the number of BLs in the configuration region
.. note:: ports must use ``wl`` as the reserved port name

View File

@ -27,6 +27,16 @@ FabricKey::fabric_region_range FabricKey::regions() const {
return vtr::make_range(region_ids_.begin(), region_ids_.end());
}
FabricKey::fabric_bit_line_bank_range FabricKey::bl_banks(const FabricRegionId& region_id) const {
VTR_ASSERT(valid_region_id(region_id));
return vtr::make_range(bl_bank_ids_[region_id].begin(), bl_bank_ids_[region_id].end());
}
FabricKey::fabric_word_line_bank_range FabricKey::wl_banks(const FabricRegionId& region_id) const {
VTR_ASSERT(valid_region_id(region_id));
return vtr::make_range(wl_bank_ids_[region_id].begin(), wl_bank_ids_[region_id].end());
}
/************************************************************************
* Public Accessors : Basic data query
***********************************************************************/
@ -64,6 +74,16 @@ bool FabricKey::empty() const {
return 0 == key_ids_.size();
}
std::vector<openfpga::BasicPort> FabricKey::bl_bank_data_ports(const FabricRegionId& region_id, const FabricBitLineBankId& bank_id) const {
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
return bl_bank_data_ports_[region_id][bank_id];
}
std::vector<openfpga::BasicPort> FabricKey::wl_bank_data_ports(const FabricRegionId& region_id, const FabricWordLineBankId& bank_id) const {
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
return wl_bank_data_ports_[region_id][bank_id];
}
/************************************************************************
* Public Mutators
***********************************************************************/
@ -71,6 +91,10 @@ bool FabricKey::empty() const {
void FabricKey::reserve_regions(const size_t& num_regions) {
region_ids_.reserve(num_regions);
region_key_ids_.reserve(num_regions);
bl_bank_ids_.reserve(num_regions);
bl_bank_data_ports_.reserve(num_regions);
wl_bank_ids_.reserve(num_regions);
wl_bank_data_ports_.reserve(num_regions);
}
FabricRegionId FabricKey::create_region() {
@ -78,6 +102,10 @@ FabricRegionId FabricKey::create_region() {
FabricRegionId region = FabricRegionId(region_ids_.size());
region_ids_.push_back(region);
region_key_ids_.emplace_back();
bl_bank_ids_.emplace_back();
bl_bank_data_ports_.emplace_back();
wl_bank_ids_.emplace_back();
wl_bank_data_ports_.emplace_back();
return region;
}
@ -178,6 +206,54 @@ void FabricKey::set_key_coordinate(const FabricKeyId& key_id,
key_coordinates_[key_id] = coord;
}
void FabricKey::reserve_bl_shift_register_banks(const FabricRegionId& region_id, const size_t& num_banks) {
VTR_ASSERT(valid_region_id(region_id));
bl_bank_ids_[region_id].reserve(num_banks);
bl_bank_data_ports_[region_id].reserve(num_banks);
}
void FabricKey::reserve_wl_shift_register_banks(const FabricRegionId& region_id, const size_t& num_banks) {
VTR_ASSERT(valid_region_id(region_id));
wl_bank_ids_[region_id].reserve(num_banks);
wl_bank_data_ports_[region_id].reserve(num_banks);
}
FabricBitLineBankId FabricKey::create_bl_shift_register_bank(const FabricRegionId& region_id) {
VTR_ASSERT(valid_region_id(region_id));
/* Create a new id */
FabricBitLineBankId bank = FabricBitLineBankId(bl_bank_ids_[region_id].size());
bl_bank_ids_[region_id].push_back(bank);
bl_bank_data_ports_[region_id].emplace_back();
return bank;
}
void FabricKey::add_data_port_to_bl_shift_register_bank(const FabricRegionId& region_id,
const FabricBitLineBankId& bank_id,
const openfpga::BasicPort& data_port) {
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
bl_bank_data_ports_[region_id][bank_id].push_back(data_port);
}
FabricWordLineBankId FabricKey::create_wl_shift_register_bank(const FabricRegionId& region_id) {
VTR_ASSERT(valid_region_id(region_id));
/* Create a new id */
FabricWordLineBankId bank = FabricWordLineBankId(wl_bank_ids_[region_id].size());
wl_bank_ids_[region_id].push_back(bank);
wl_bank_data_ports_[region_id].emplace_back();
return bank;
}
void FabricKey::add_data_port_to_wl_shift_register_bank(const FabricRegionId& region_id,
const FabricWordLineBankId& bank_id,
const openfpga::BasicPort& data_port) {
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
wl_bank_data_ports_[region_id][bank_id].push_back(data_port);
}
/************************************************************************
* Internal invalidators/validators
***********************************************************************/
@ -193,3 +269,17 @@ bool FabricKey::valid_key_id(const FabricKeyId& key_id) const {
bool FabricKey::valid_key_coordinate(const vtr::Point<int>& coord) const {
return coord.x() > -1 && coord.y() > -1;
}
bool FabricKey::valid_bl_bank_id(const FabricRegionId& region_id, const FabricBitLineBankId& bank_id) const {
if (!valid_region_id(region_id)) {
return false;
}
return ( size_t(bank_id) < bl_bank_ids_[region_id].size() ) && ( bank_id == bl_bank_ids_[region_id][bank_id] );
}
bool FabricKey::valid_wl_bank_id(const FabricRegionId& region_id, const FabricWordLineBankId& bank_id) const {
if (!valid_region_id(region_id)) {
return false;
}
return ( size_t(bank_id) < wl_bank_ids_[region_id].size() ) && ( bank_id == wl_bank_ids_[region_id][bank_id] );
}

View File

@ -12,6 +12,9 @@
#include "vtr_vector.h"
#include "vtr_geometry.h"
/* Headers from openfpgautil library */
#include "openfpga_port.h"
#include "fabric_key_fwd.h"
/********************************************************************
@ -38,14 +41,20 @@ class FabricKey {
public: /* Types */
typedef vtr::vector<FabricKeyId, FabricKeyId>::const_iterator fabric_key_iterator;
typedef vtr::vector<FabricRegionId, FabricRegionId>::const_iterator fabric_region_iterator;
typedef vtr::vector<FabricBitLineBankId, FabricBitLineBankId>::const_iterator fabric_bit_line_bank_iterator;
typedef vtr::vector<FabricWordLineBankId, FabricWordLineBankId>::const_iterator fabric_word_line_bank_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;
public: /* Constructors */
FabricKey();
public: /* Accessors: aggregates */
fabric_key_range keys() const;
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;
public: /* Public Accessors: Basic data query */
/* Access all the keys of a region */
std::vector<FabricKeyId> region_keys(const FabricRegionId& region_id) const;
@ -65,6 +74,12 @@ class FabricKey {
/* Check if there are any keys */
bool empty() const;
/* Return a list of data ports which will be driven by a BL shift register bank */
std::vector<openfpga::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(const FabricRegionId& region_id, const FabricWordLineBankId& bank_id) const;
public: /* Public Mutators: model-related */
/* Reserve a number of regions to be memory efficent */
@ -100,11 +115,33 @@ class FabricKey {
void set_key_coordinate(const FabricKeyId& key_id,
const vtr::Point<int>& coord);
/* Reserve a number of banks to be memory efficent */
void reserve_bl_shift_register_banks(const FabricRegionId& region_id, const size_t& num_banks);
void reserve_wl_shift_register_banks(const FabricRegionId& region_id, const size_t& num_banks);
/* Create a new shift register bank for BLs and return an id */
FabricBitLineBankId create_bl_shift_register_bank(const FabricRegionId& region_id);
/* 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);
/* Create a new shift register bank for WLs and return an id */
FabricWordLineBankId create_wl_shift_register_bank(const FabricRegionId& region_id);
/* 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);
public: /* Public invalidators/validators */
bool valid_region_id(const FabricRegionId& region_id) const;
bool valid_key_id(const FabricKeyId& key_id) const;
/* Identify if key coordinate is acceptable to fabric key convention */
bool valid_key_coordinate(const vtr::Point<int>& coord) const;
bool valid_bl_bank_id(const FabricRegionId& region_id, const FabricBitLineBankId& bank_id) const;
bool valid_wl_bank_id(const FabricRegionId& region_id, const FabricWordLineBankId& bank_id) const;
private: /* Internal data */
/* Unique ids for each region */
vtr::vector<FabricRegionId, FabricRegionId> region_ids_;
@ -129,6 +166,16 @@ class FabricKey {
/* Optional alias for each key, with which a key can also be represented */
vtr::vector<FabricKeyId, std::string> key_alias_;
/* Unique ids for each BL shift register bank */
vtr::vector<FabricRegionId, 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>>> bl_bank_data_ports_;
/* Unique ids for each WL shift register bank */
vtr::vector<FabricRegionId, 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>>> wl_bank_data_ports_;
};
#endif

View File

@ -14,9 +14,13 @@
struct fabric_region_id_tag;
struct fabric_key_id_tag;
struct fabric_bit_line_bank_id_tag;
struct fabric_word_line_bank_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;
/* Short declaration of class */
class FabricKey;

View File

@ -13,6 +13,10 @@
#include "vtr_assert.h"
#include "vtr_time.h"
/* Headers from openfpga util library */
#include "openfpga_tokenizer.h"
#include "openfpga_port_parser.h"
/* Headers from libarchfpga */
#include "arch_error.h"
#include "read_xml_util.h"
@ -70,6 +74,114 @@ void read_xml_region_key(pugi::xml_node& xml_component_key,
}
}
/********************************************************************
* 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
*******************************************************************/
@ -88,20 +200,25 @@ void read_xml_fabric_region(pugi::xml_node& xml_region,
VTR_ASSERT_SAFE(true == fabric_key.valid_region_id(region_id));
/* Reserve memory space for the keys in the region */
size_t num_keys = std::distance(xml_region.children().begin(), xml_region.children().end());
size_t num_keys = count_children(xml_region, "key", loc_data, pugiutil::ReqOpt::OPTIONAL);
fabric_key.reserve_region_keys(region_id, num_keys);
for (pugi::xml_node xml_key : xml_region.children()) {
/* Error out if the XML child has an invalid name! */
if (xml_key.name() != std::string("key")) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_region),
"Unexpected child '%s' in region '%lu', Region XML node can only contain keys!\n",
xml_key.name(),
size_t(region_id));
}
/* Parse the key for this region */
read_xml_region_key(xml_key, loc_data, fabric_key, region_id);
/* 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);
}
/********************************************************************

View File

@ -63,6 +63,106 @@ int write_xml_fabric_component_key(std::fstream& fp,
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
*
@ -93,6 +193,10 @@ int write_xml_fabric_key(const char* fname,
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);

View File

@ -122,6 +122,7 @@ int write_fabric_bitstream(const OpenfpgaContext& openfpga_ctx,
/* By default, output in plain text format */
status = write_fabric_bitstream_to_text_file(openfpga_ctx.bitstream_manager(),
openfpga_ctx.fabric_bitstream(),
openfpga_ctx.blwl_shift_register_banks(),
openfpga_ctx.arch().config_protocol,
openfpga_ctx.fabric_global_port_info(),
cmd_context.option_value(cmd, opt_file),

View File

@ -135,6 +135,7 @@ int build_fabric(OpenfpgaContext& openfpga_ctx,
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(),
cmd_context.option_enable(cmd, opt_verbose));
/* If there is any error, final status cannot be overwritten by a success flag */
if (CMD_EXEC_SUCCESS != curr_status) {

View File

@ -66,7 +66,7 @@ class OpenfpgaContext : public Context {
const openfpga::DeviceRRGSB& device_rr_gsb() const { return device_rr_gsb_; }
const openfpga::MuxLibrary& mux_lib() const { return mux_lib_; }
const openfpga::DecoderLibrary& decoder_lib() const { return decoder_lib_; }
const std::array<openfpga::MemoryBankShiftRegisterBanks, 2>& blwl_shift_register_banks() { return blwl_sr_banks_; }
const openfpga::MemoryBankShiftRegisterBanks& blwl_shift_register_banks() const { return blwl_sr_banks_; }
const openfpga::TileDirect& tile_direct() const { return tile_direct_; }
const openfpga::ModuleManager& module_graph() const { return module_graph_; }
const openfpga::FlowManager& flow_manager() const { return flow_manager_; }
@ -89,7 +89,7 @@ class OpenfpgaContext : public Context {
openfpga::DeviceRRGSB& mutable_device_rr_gsb() { return device_rr_gsb_; }
openfpga::MuxLibrary& mutable_mux_lib() { return mux_lib_; }
openfpga::DecoderLibrary& mutable_decoder_lib() { return decoder_lib_; }
std::array<openfpga::MemoryBankShiftRegisterBanks, 2>& mutable_blwl_shift_register_banks() { return blwl_sr_banks_; }
openfpga::MemoryBankShiftRegisterBanks& mutable_blwl_shift_register_banks() { return blwl_sr_banks_; }
openfpga::TileDirect& mutable_tile_direct() { return tile_direct_; }
openfpga::ModuleManager& mutable_module_graph() { return module_graph_; }
openfpga::FlowManager& mutable_flow_manager() { return flow_manager_; }
@ -138,7 +138,7 @@ class OpenfpgaContext : public Context {
/* Library of shift register banks that control BLs and WLs
* @note Only used when memory bank is used as configuration protocol
*/
std::array<openfpga::MemoryBankShiftRegisterBanks, 2> blwl_sr_banks_;
openfpga::MemoryBankShiftRegisterBanks blwl_sr_banks_;
/* Fabric module graph */
openfpga::ModuleManager module_graph_;

View File

@ -107,6 +107,7 @@ int write_full_testbench(const OpenfpgaContext& openfpga_ctx,
return fpga_verilog_full_testbench(openfpga_ctx.module_graph(),
openfpga_ctx.bitstream_manager(),
openfpga_ctx.fabric_bitstream(),
openfpga_ctx.blwl_shift_register_banks(),
g_vpr_ctx.atom(),
g_vpr_ctx.placement(),
pin_constraints,

View File

@ -31,7 +31,7 @@ namespace openfpga {
*******************************************************************/
int build_device_module_graph(ModuleManager& module_manager,
DecoderLibrary& decoder_lib,
std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
MemoryBankShiftRegisterBanks& blwl_sr_banks,
const OpenfpgaContext& openfpga_ctx,
const DeviceContext& vpr_device_ctx,
const bool& frame_view,

View File

@ -17,7 +17,7 @@ namespace openfpga {
int build_device_module_graph(ModuleManager& module_manager,
DecoderLibrary& decoder_lib,
std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
MemoryBankShiftRegisterBanks& blwl_sr_banks,
const OpenfpgaContext& openfpga_ctx,
const DeviceContext& vpr_device_ctx,
const bool& frame_view,

View File

@ -23,6 +23,7 @@
#include "build_top_module_utils.h"
#include "build_top_module_connection.h"
#include "build_top_module_memory.h"
#include "build_top_module_memory_bank.h"
#include "build_top_module_directs.h"
#include "build_module_graph_utils.h"
@ -283,7 +284,7 @@ vtr::Matrix<size_t> add_top_module_connection_block_instances(ModuleManager& mod
*******************************************************************/
int build_top_module(ModuleManager& module_manager,
DecoderLibrary& decoder_lib,
std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
MemoryBankShiftRegisterBanks& blwl_sr_banks,
const CircuitLibrary& circuit_lib,
const VprDeviceAnnotation& vpr_device_annotation,
const DeviceGrid& grids,
@ -382,6 +383,11 @@ int build_top_module(ModuleManager& module_manager,
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
status = load_top_module_shift_register_banks_from_fabric_key(fabric_key, blwl_sr_banks);
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
}
/* Shuffle the configurable children in a random sequence */
@ -389,6 +395,13 @@ int build_top_module(ModuleManager& module_manager,
shuffle_top_module_configurable_children(module_manager, top_module, config_protocol);
}
/* Build shift register bank detailed connections */
sync_memory_bank_shift_register_banks_with_config_protocol_settings(module_manager,
blwl_sr_banks,
config_protocol,
top_module,
circuit_lib);
/* Add shared SRAM ports from the sub-modules under this Verilog module
* This is a much easier job after adding sub modules (instances),
* we just need to find all the I/O ports from the child modules and build a list of it
@ -408,6 +421,7 @@ int build_top_module(ModuleManager& module_manager,
add_top_module_sram_ports(module_manager, top_module,
circuit_lib, sram_model,
config_protocol,
const_cast<const MemoryBankShiftRegisterBanks&>(blwl_sr_banks),
top_module_num_config_bits);
}

View File

@ -30,7 +30,7 @@ namespace openfpga {
int build_top_module(ModuleManager& module_manager,
DecoderLibrary& decoder_lib,
std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
MemoryBankShiftRegisterBanks& blwl_sr_banks,
const CircuitLibrary& circuit_lib,
const VprDeviceAnnotation& vpr_device_annotation,
const DeviceGrid& grids,

View File

@ -807,6 +807,7 @@ void add_top_module_sram_ports(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const ConfigProtocol& config_protocol,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const TopModuleNumConfigBits& num_config_bits) {
std::vector<std::string> sram_port_names = generate_sram_port_names(circuit_lib, sram_model, config_protocol.type());
size_t total_num_config_bits = 0;
@ -852,7 +853,7 @@ void add_top_module_sram_ports(ModuleManager& module_manager,
break;
}
case CONFIG_MEM_QL_MEMORY_BANK: {
add_top_module_ql_memory_bank_sram_ports(module_manager, module_id, circuit_lib, config_protocol, num_config_bits);
add_top_module_ql_memory_bank_sram_ports(module_manager, module_id, circuit_lib, config_protocol, blwl_sr_banks, num_config_bits);
break;
}
case CONFIG_MEM_SCAN_CHAIN: {
@ -1735,7 +1736,7 @@ void add_top_module_nets_cmos_memory_frame_config_bus(ModuleManager& module_mana
static
void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
DecoderLibrary& decoder_lib,
std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
MemoryBankShiftRegisterBanks& blwl_sr_banks,
const ModuleId& parent_module,
const CircuitLibrary& circuit_lib,
const ConfigProtocol& config_protocol,
@ -1802,7 +1803,7 @@ void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
*******************************************************************/
void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
DecoderLibrary& decoder_lib,
std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
MemoryBankShiftRegisterBanks& blwl_sr_banks,
const ModuleId& parent_module,
const CircuitLibrary& circuit_lib,
const ConfigProtocol& config_protocol,

View File

@ -61,11 +61,12 @@ void add_top_module_sram_ports(ModuleManager& module_manager,
const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const ConfigProtocol& config_protocol,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const TopModuleNumConfigBits& num_config_bits);
void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
DecoderLibrary& decoder_lib,
std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
MemoryBankShiftRegisterBanks& blwl_sr_banks,
const ModuleId& parent_module,
const CircuitLibrary& circuit_lib,
const ConfigProtocol& config_protocol,

View File

@ -1073,33 +1073,36 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_flatten_config_bus(ModuleManager
/*********************************************************************
* This function to add nets for QuickLogic memory bank
* We build the net connects between the head ports of shift register banks
* We build the net connects between the head ports of BL shift register banks
* and the head ports of top-level module
* @note This function is applicable to both BL and WL shift registers
**********************************************************************/
static
void add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_heads(ModuleManager& module_manager,
const ModuleId& top_module,
const MemoryBankShiftRegisterBanks& sr_banks,
const std::string& head_port_name) {
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
ModulePortId blsr_head_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(head_port_name, config_region));
BasicPort blsr_head_port_info = module_manager.module_port(top_module, blsr_head_port);
void add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_bank_heads(ModuleManager& module_manager,
const ModuleId& top_module,
const MemoryBankShiftRegisterBanks& sr_banks) {
std::string head_port_name(BL_SHIFT_REGISTER_CHAIN_HEAD_NAME);
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
ModulePortId sr_head_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(head_port_name, config_region));
BasicPort sr_head_port_info = module_manager.module_port(top_module, sr_head_port);
/* Iterate over each shift register banks */
for (const auto& bank : sr_banks.bl_banks(config_region)) {
/* Get the module and instance ids */
ModuleId sr_bank_module = sr_banks.bl_shift_register_bank_module(config_region, bank);
size_t sr_bank_instance = sr_banks.bl_shift_register_bank_instance(config_region, bank);
for (size_t iinst = 0; iinst < sr_banks.shift_register_bank_modules(config_region).size(); ++iinst) {
ModuleId sr_bank_module = sr_banks.shift_register_bank_modules(config_region)[iinst];
size_t sr_bank_instance = sr_banks.shift_register_bank_instances(config_region)[iinst];
VTR_ASSERT(sr_bank_module);
ModulePortId sr_module_head_port = module_manager.find_module_port(sr_bank_module, head_port_name);
BasicPort sr_module_head_port_info = module_manager.module_port(sr_bank_module, sr_module_head_port);
VTR_ASSERT(sr_module_head_port_info.get_width() == blsr_head_port_info.get_width());
VTR_ASSERT(sr_module_head_port_info.get_width() == 1);
for (size_t ipin = 0; ipin < sr_module_head_port_info.pins().size(); ++ipin) {
/* Create net */
ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
top_module, 0,
blsr_head_port,
blsr_head_port_info.pins()[ipin]);
sr_head_port,
sr_head_port_info.pins()[size_t(bank)]);
VTR_ASSERT(ModuleNetId::INVALID() != net);
/* Add net sink */
@ -1112,27 +1115,70 @@ void add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_heads(ModuleMan
/*********************************************************************
* This function to add nets for QuickLogic memory bank
* We build the net connects between the head ports of shift register banks
* We build the net connects between the head ports of BL shift register banks
* and the head ports of top-level module
* @note This function is applicable to both BL and WL shift registers
**********************************************************************/
static
void add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_tails(ModuleManager& module_manager,
const ModuleId& top_module,
const MemoryBankShiftRegisterBanks& sr_banks,
const std::string& tail_port_name) {
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
ModulePortId blsr_tail_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(tail_port_name, config_region));
BasicPort blsr_tail_port_info = module_manager.module_port(top_module, blsr_tail_port);
void add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_bank_heads(ModuleManager& module_manager,
const ModuleId& top_module,
const MemoryBankShiftRegisterBanks& sr_banks) {
std::string head_port_name(WL_SHIFT_REGISTER_CHAIN_HEAD_NAME);
for (size_t iinst = 0; iinst < sr_banks.shift_register_bank_modules(config_region).size(); ++iinst) {
ModuleId sr_bank_module = sr_banks.shift_register_bank_modules(config_region)[iinst];
size_t sr_bank_instance = sr_banks.shift_register_bank_instances(config_region)[iinst];
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
ModulePortId sr_head_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(head_port_name, config_region));
BasicPort sr_head_port_info = module_manager.module_port(top_module, sr_head_port);
/* Iterate over each shift register banks */
for (const auto& bank : sr_banks.wl_banks(config_region)) {
/* Get the module and instance ids */
ModuleId sr_bank_module = sr_banks.wl_shift_register_bank_module(config_region, bank);
size_t sr_bank_instance = sr_banks.wl_shift_register_bank_instance(config_region, bank);
VTR_ASSERT(sr_bank_module);
ModulePortId sr_module_head_port = module_manager.find_module_port(sr_bank_module, head_port_name);
BasicPort sr_module_head_port_info = module_manager.module_port(sr_bank_module, sr_module_head_port);
VTR_ASSERT(sr_module_head_port_info.get_width() == 1);
for (size_t ipin = 0; ipin < sr_module_head_port_info.pins().size(); ++ipin) {
/* Create net */
ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
top_module, 0,
sr_head_port,
sr_head_port_info.pins()[size_t(bank)]);
VTR_ASSERT(ModuleNetId::INVALID() != net);
/* Add net sink */
module_manager.add_module_net_sink(top_module, net,
sr_bank_module, sr_bank_instance, sr_module_head_port, sr_module_head_port_info.pins()[ipin]);
}
}
}
}
/*********************************************************************
* This function to add nets for QuickLogic memory bank
* We build the net connects between the tail ports of BL shift register banks
* and the tail ports of top-level module
**********************************************************************/
static
void add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_bank_tails(ModuleManager& module_manager,
const ModuleId& top_module,
const MemoryBankShiftRegisterBanks& sr_banks) {
std::string tail_port_name(BL_SHIFT_REGISTER_CHAIN_TAIL_NAME);
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
ModulePortId sr_tail_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(tail_port_name, config_region));
BasicPort sr_tail_port_info = module_manager.module_port(top_module, sr_tail_port);
/* Iterate over each shift register banks */
for (const auto& bank : sr_banks.bl_banks(config_region)) {
/* Get the module and instance ids */
ModuleId sr_bank_module = sr_banks.bl_shift_register_bank_module(config_region, bank);
size_t sr_bank_instance = sr_banks.bl_shift_register_bank_instance(config_region, bank);
VTR_ASSERT(sr_bank_module);
ModulePortId sr_module_tail_port = module_manager.find_module_port(sr_bank_module, tail_port_name);
BasicPort sr_module_tail_port_info = module_manager.module_port(sr_bank_module, sr_module_tail_port);
VTR_ASSERT(sr_module_tail_port_info.get_width() == blsr_tail_port_info.get_width());
VTR_ASSERT(sr_module_tail_port_info.get_width() == 1);
for (size_t ipin = 0; ipin < sr_module_tail_port_info.pins().size(); ++ipin) {
/* Create net */
ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
@ -1143,7 +1189,47 @@ void add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_tails(ModuleMan
/* Add net sink */
module_manager.add_module_net_sink(top_module, net,
top_module, 0,
blsr_tail_port, blsr_tail_port_info.pins()[ipin]);
sr_tail_port, sr_tail_port_info.pins()[size_t(bank)]);
}
}
}
}
/*********************************************************************
* This function to add nets for QuickLogic memory bank
* We build the net connects between the tail ports of WL shift register banks
* and the tail ports of top-level module
**********************************************************************/
static
void add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_bank_tails(ModuleManager& module_manager,
const ModuleId& top_module,
const MemoryBankShiftRegisterBanks& sr_banks) {
std::string tail_port_name(WL_SHIFT_REGISTER_CHAIN_TAIL_NAME);
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
ModulePortId sr_tail_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(tail_port_name, config_region));
BasicPort sr_tail_port_info = module_manager.module_port(top_module, sr_tail_port);
/* Iterate over each shift register banks */
for (const auto& bank : sr_banks.wl_banks(config_region)) {
/* Get the module and instance ids */
ModuleId sr_bank_module = sr_banks.wl_shift_register_bank_module(config_region, bank);
size_t sr_bank_instance = sr_banks.wl_shift_register_bank_instance(config_region, bank);
VTR_ASSERT(sr_bank_module);
ModulePortId sr_module_tail_port = module_manager.find_module_port(sr_bank_module, tail_port_name);
BasicPort sr_module_tail_port_info = module_manager.module_port(sr_bank_module, sr_module_tail_port);
VTR_ASSERT(sr_module_tail_port_info.get_width() == 1);
for (size_t ipin = 0; ipin < sr_module_tail_port_info.pins().size(); ++ipin) {
/* Create net */
ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
sr_bank_module, sr_bank_instance,
sr_module_tail_port, sr_module_tail_port_info.pins()[ipin]);
VTR_ASSERT(ModuleNetId::INVALID() != net);
/* Add net sink */
module_manager.add_module_net_sink(top_module, net,
top_module, 0,
sr_tail_port, sr_tail_port_info.pins()[size_t(bank)]);
}
}
}
@ -1176,16 +1262,18 @@ void add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_tails(ModuleMan
* @note optional BL/WL is applicable to WLR, which may not always exist
*/
static
void add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_blwls(ModuleManager& module_manager,
const ModuleId& top_module,
const MemoryBankShiftRegisterBanks& sr_banks,
const std::string& sr_blwl_port_name,
const std::string& child_blwl_port_name,
const bool& optional_blwl = false) {
void add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_bank_bls(ModuleManager& module_manager,
const ModuleId& top_module,
const MemoryBankShiftRegisterBanks& sr_banks,
const std::string sr_blwl_port_name,
const std::string& child_blwl_port_name,
const bool& optional_blwl = false) {
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
for (size_t iinst = 0; iinst < sr_banks.shift_register_bank_modules(config_region).size(); ++iinst) {
ModuleId sr_bank_module = sr_banks.shift_register_bank_modules(config_region)[iinst];
size_t sr_bank_instance = sr_banks.shift_register_bank_instances(config_region)[iinst];
/* Iterate over each shift register banks */
for (const auto& bank : sr_banks.bl_banks(config_region)) {
/* Get the module and instance ids */
ModuleId sr_bank_module = sr_banks.bl_shift_register_bank_module(config_region, bank);
size_t sr_bank_instance = sr_banks.bl_shift_register_bank_instance(config_region, bank);
VTR_ASSERT(sr_bank_module);
ModulePortId sr_module_blwl_port = module_manager.find_module_port(sr_bank_module, sr_blwl_port_name);
@ -1195,29 +1283,106 @@ void add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_blwls(ModuleMan
VTR_ASSERT(sr_module_blwl_port);
BasicPort sr_module_blwl_port_info = module_manager.module_port(sr_bank_module, sr_module_blwl_port);
for (size_t sink_id = 0; sink_id < sr_banks.shift_register_bank_sink_child_ids(config_region, sr_bank_module, sr_bank_instance).size(); ++sink_id) {
size_t child_id = sr_banks.shift_register_bank_sink_child_ids(config_region, sr_bank_module, sr_bank_instance)[sink_id];
ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id];
size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[child_id];
/* Find the BL port */
ModulePortId child_blwl_port = module_manager.find_module_port(child_module, child_blwl_port_name);
BasicPort child_blwl_port_info = module_manager.module_port(child_module, child_blwl_port);
size_t cur_sr_module_blwl_pin_id = sr_banks.shift_register_bank_source_blwl_ids(config_region, sr_bank_module, sr_bank_instance)[sink_id];
for (const BasicPort& src_port : sr_banks.bl_shift_register_bank_source_ports(config_region, bank)) {
VTR_ASSERT(1 == src_port.get_width());
/* Create net */
ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
sr_bank_module, sr_bank_instance,
sr_module_blwl_port,
sr_module_blwl_port_info.pins()[cur_sr_module_blwl_pin_id]);
src_port.pins()[0]);
VTR_ASSERT(ModuleNetId::INVALID() != net);
/* Add net sink */
size_t sink_pin_id = sr_banks.shift_register_bank_sink_pin_ids(config_region, sr_bank_module, sr_bank_instance)[sink_id];
module_manager.add_module_net_sink(top_module, net,
child_module, child_instance, child_blwl_port, sink_pin_id);
for (size_t ichild = 0; ichild < sr_banks.bl_shift_register_bank_sink_child_ids(config_region, bank, src_port).size(); ++ichild) {
size_t child_id = sr_banks.bl_shift_register_bank_sink_child_ids(config_region, bank, src_port)[ichild];
ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id];
size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[child_id];
/* Find the BL port */
ModulePortId child_blwl_port = module_manager.find_module_port(child_module, child_blwl_port_name);
BasicPort child_blwl_port_info = module_manager.module_port(child_module, child_blwl_port);
/* Add net sink */
size_t sink_child_pin_id = sr_banks.bl_shift_register_bank_sink_child_pin_ids(config_region, bank, src_port)[ichild];
module_manager.add_module_net_sink(top_module, net,
child_module, child_instance, child_blwl_port, sink_child_pin_id);
}
}
}
}
}
/**************************************************************
* Add BL/WL nets from shift register module to each configurable child
* BL pins of shift register module are connected to the BL input pins of each PB/CB/SB
* For all the PB/CB/SB in the same column, they share the same set of BLs
* A quick example
*
* +-----------------------+
* | Shift register chain |
* +-----------------------+
* BL[i .. i + sqrt(N)]
* |
* | CLB[1][H]
* | +---------+
* | | SRAM |
* +-->| [0..N] |
* | +---------+
* |
* ...
* | CLB[1][1]
* | +---------+
* | | SRAM |
* +-->| [0..N] |
* | +---------+
* |
* @note optional BL/WL is applicable to WLR, which may not always exist
*/
static
void add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_bank_wls(ModuleManager& module_manager,
const ModuleId& top_module,
const MemoryBankShiftRegisterBanks& sr_banks,
const std::string sr_blwl_port_name,
const std::string& child_blwl_port_name,
const bool& optional_blwl = false) {
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
/* Iterate over each shift register banks */
for (const auto& bank : sr_banks.wl_banks(config_region)) {
/* Get the module and instance ids */
ModuleId sr_bank_module = sr_banks.wl_shift_register_bank_module(config_region, bank);
size_t sr_bank_instance = sr_banks.wl_shift_register_bank_instance(config_region, bank);
VTR_ASSERT(sr_bank_module);
ModulePortId sr_module_blwl_port = module_manager.find_module_port(sr_bank_module, sr_blwl_port_name);
if (!sr_module_blwl_port && optional_blwl) {
continue;
}
VTR_ASSERT(sr_module_blwl_port);
BasicPort sr_module_blwl_port_info = module_manager.module_port(sr_bank_module, sr_module_blwl_port);
for (const BasicPort& src_port : sr_banks.wl_shift_register_bank_source_ports(config_region, bank)) {
VTR_ASSERT(1 == src_port.get_width());
/* Create net */
ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
sr_bank_module, sr_bank_instance,
sr_module_blwl_port,
src_port.pins()[0]);
VTR_ASSERT(ModuleNetId::INVALID() != net);
for (size_t ichild = 0; ichild < sr_banks.wl_shift_register_bank_sink_child_ids(config_region, bank, src_port).size(); ++ichild) {
size_t child_id = sr_banks.wl_shift_register_bank_sink_child_ids(config_region, bank, src_port)[ichild];
ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id];
size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[child_id];
/* Find the BL port */
ModulePortId child_blwl_port = module_manager.find_module_port(child_module, child_blwl_port_name);
BasicPort child_blwl_port_info = module_manager.module_port(child_module, child_blwl_port);
/* Add net sink */
size_t sink_child_pin_id = sr_banks.wl_shift_register_bank_sink_child_pin_ids(config_region, bank, src_port)[ichild];
module_manager.add_module_net_sink(top_module, net,
child_module, child_instance, child_blwl_port, sink_child_pin_id);
}
}
}
}
@ -1285,15 +1450,7 @@ void add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(Module
CircuitModelId sram_model = config_protocol.memory_model();
CircuitModelId bl_memory_model = config_protocol.bl_memory_model();
/* Find out the unique shift register chain sizes */
vtr::vector<ConfigRegionId, size_t> unique_sr_sizes;
unique_sr_sizes.resize(module_manager.regions(top_module).size());
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
/* TODO: Need to find how to cut the BLs when there are multiple banks for shift registers in a region */
size_t num_bls = compute_memory_bank_regional_num_bls(module_manager, top_module,
config_region,
circuit_lib, sram_model);
unique_sr_sizes[config_region] = num_bls;
}
std::vector<size_t> unique_sr_sizes = sr_banks.bl_bank_unique_sizes();
/* Build submodules for shift register chains */
for (const size_t& sr_size : unique_sr_sizes) {
@ -1306,17 +1463,22 @@ void add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(Module
}
/* Instanciate the shift register chains in the top-level module */
sr_banks.resize_regions(module_manager.regions(top_module).size());
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
std::string sr_module_name = generate_bl_shift_register_module_name(circuit_lib.model_name(bl_memory_model), unique_sr_sizes[config_region]);
ModuleId sr_bank_module = module_manager.find_module(sr_module_name);
VTR_ASSERT(sr_bank_module);
for (const FabricBitLineBankId& sr_bank : sr_banks.bl_banks(config_region)) {
size_t bl_bank_size = sr_banks.bl_bank_size(config_region, sr_bank);
std::string sr_module_name = generate_bl_shift_register_module_name(circuit_lib.model_name(bl_memory_model), bl_bank_size);
ModuleId sr_bank_module = module_manager.find_module(sr_module_name);
VTR_ASSERT(sr_bank_module);
size_t cur_inst = module_manager.num_instance(top_module, sr_bank_module);
module_manager.add_child_module(top_module, sr_bank_module);
size_t cur_inst = module_manager.num_instance(top_module, sr_bank_module);
module_manager.add_child_module(top_module, sr_bank_module);
sr_banks.add_shift_register_instance(config_region, sr_bank_module, cur_inst);
sr_banks.link_bl_shift_register_bank_to_module(config_region, sr_bank, sr_bank_module);
sr_banks.link_bl_shift_register_bank_to_instance(config_region, sr_bank, cur_inst);
}
}
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
/**************************************************************
* Precompute the BLs and WLs distribution across the FPGA fabric
* The distribution is a matrix which contains the starting index of BL/WL for each column or row
@ -1338,10 +1500,14 @@ void add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(Module
size_t cur_bl_index = 0;
for (const size_t& sink_bl_pin : child_bl_port_info.pins()) {
/* Find the shift register bank id for the driving BL port */
size_t bl_pin_id = bl_start_index_per_tile[coord.x()] + cur_bl_index;
BasicPort src_bl_port(std::string(MEMORY_BL_PORT_NAME), bl_pin_id, bl_pin_id);
FabricBitLineBankId sr_bank = sr_banks.find_bl_shift_register_bank_id(config_region, src_bl_port);
BasicPort sr_bank_port = sr_banks.find_bl_shift_register_bank_data_port(config_region, src_bl_port);
VTR_ASSERT(sr_bank_port.is_valid());
sr_banks.add_shift_register_sink_nodes(config_region, sr_bank_module, cur_inst, child_id, sink_bl_pin);
sr_banks.add_shift_register_source_blwls(config_region, sr_bank_module, cur_inst, bl_pin_id);
sr_banks.add_bl_shift_register_bank_sink_node(config_region, sr_bank, sr_bank_port, child_id, sink_bl_pin);
cur_bl_index++;
}
@ -1352,16 +1518,14 @@ void add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(Module
* - Connect the head port from top-level module to each shift register bank
* - Connect the tail port from each shift register bank to top-level module
*/
add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_heads(module_manager, top_module, sr_banks,
std::string(BL_SHIFT_REGISTER_CHAIN_HEAD_NAME));
add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_bank_heads(module_manager, top_module, sr_banks);
add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_tails(module_manager, top_module, sr_banks,
std::string(BL_SHIFT_REGISTER_CHAIN_TAIL_NAME));
add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_bank_tails(module_manager, top_module, sr_banks);
/* Create connections between BLs of top-level module and BLs of child modules for each region */
add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_blwls(module_manager, top_module, sr_banks,
std::string(BL_SHIFT_REGISTER_CHAIN_BL_OUT_NAME),
std::string(MEMORY_BL_PORT_NAME));
add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_bank_bls(module_manager, top_module, sr_banks,
std::string(BL_SHIFT_REGISTER_CHAIN_BL_OUT_NAME),
std::string(MEMORY_BL_PORT_NAME));
}
/*********************************************************************
@ -1380,16 +1544,9 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(Module
CircuitModelId sram_model = config_protocol.memory_model();
CircuitModelId wl_memory_model = config_protocol.wl_memory_model();
/* Find out the unique shift register chain sizes */
vtr::vector<ConfigRegionId, size_t> unique_sr_sizes;
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
/* TODO: Need to find how to cut the BLs when there are multiple banks for shift registers in a region */
size_t num_wls = compute_memory_bank_regional_num_wls(module_manager, top_module,
config_region,
circuit_lib, sram_model);
unique_sr_sizes.push_back(num_wls);
}
std::vector<size_t> unique_sr_sizes = sr_banks.wl_bank_unique_sizes();
/* TODO: Build submodules for shift register chains */
/* Build submodules for shift register chains */
for (const size_t& sr_size : unique_sr_sizes) {
std::string sr_module_name = generate_wl_shift_register_module_name(circuit_lib.model_name(wl_memory_model), sr_size);
build_wl_shift_register_chain_module(module_manager,
@ -1400,17 +1557,22 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(Module
}
/* Instanciate the shift register chains in the top-level module */
sr_banks.resize_regions(module_manager.regions(top_module).size());
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
std::string sr_module_name = generate_wl_shift_register_module_name(circuit_lib.model_name(wl_memory_model), unique_sr_sizes[config_region]);
ModuleId sr_bank_module = module_manager.find_module(sr_module_name);
VTR_ASSERT(sr_bank_module);
for (const FabricWordLineBankId& sr_bank : sr_banks.wl_banks(config_region)) {
size_t wl_bank_size = sr_banks.wl_bank_size(config_region, sr_bank);
std::string sr_module_name = generate_wl_shift_register_module_name(circuit_lib.model_name(wl_memory_model), wl_bank_size);
ModuleId sr_bank_module = module_manager.find_module(sr_module_name);
VTR_ASSERT(sr_bank_module);
size_t cur_inst = module_manager.num_instance(top_module, sr_bank_module);
module_manager.add_child_module(top_module, sr_bank_module);
size_t cur_inst = module_manager.num_instance(top_module, sr_bank_module);
module_manager.add_child_module(top_module, sr_bank_module);
sr_banks.add_shift_register_instance(config_region, sr_bank_module, cur_inst);
sr_banks.link_wl_shift_register_bank_to_module(config_region, sr_bank, sr_bank_module);
sr_banks.link_wl_shift_register_bank_to_instance(config_region, sr_bank, cur_inst);
}
}
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
/**************************************************************
* Precompute the BLs and WLs distribution across the FPGA fabric
* The distribution is a matrix which contains the starting index of BL/WL for each column or row
@ -1433,8 +1595,13 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(Module
for (const size_t& sink_wl_pin : child_wl_port_info.pins()) {
size_t wl_pin_id = wl_start_index_per_tile[coord.y()] + cur_wl_index;
sr_banks.add_shift_register_sink_nodes(config_region, sr_bank_module, cur_inst, child_id, sink_wl_pin);
sr_banks.add_shift_register_source_blwls(config_region, sr_bank_module, cur_inst, wl_pin_id);
BasicPort src_wl_port(std::string(MEMORY_WL_PORT_NAME), wl_pin_id, wl_pin_id);
FabricWordLineBankId sr_bank = sr_banks.find_wl_shift_register_bank_id(config_region, src_wl_port);
BasicPort sr_bank_port = sr_banks.find_wl_shift_register_bank_data_port(config_region, src_wl_port);
VTR_ASSERT(sr_bank_port.is_valid());
sr_banks.add_wl_shift_register_bank_sink_node(config_region, sr_bank, sr_bank_port, child_id, sink_wl_pin);
cur_wl_index++;
}
@ -1445,20 +1612,18 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(Module
* - Connect the head port from top-level module to each shift register bank
* - Connect the tail port from each shift register bank to top-level module
*/
add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_heads(module_manager, top_module, sr_banks,
std::string(WL_SHIFT_REGISTER_CHAIN_HEAD_NAME));
add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_bank_heads(module_manager, top_module, sr_banks);
add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_tails(module_manager, top_module, sr_banks,
std::string(WL_SHIFT_REGISTER_CHAIN_TAIL_NAME));
add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_bank_tails(module_manager, top_module, sr_banks);
/* Create connections between BLs of top-level module and BLs of child modules for each region */
add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_blwls(module_manager, top_module, sr_banks,
std::string(WL_SHIFT_REGISTER_CHAIN_WL_OUT_NAME),
std::string(MEMORY_WL_PORT_NAME));
add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_blwls(module_manager, top_module, sr_banks,
std::string(WL_SHIFT_REGISTER_CHAIN_WLR_OUT_NAME),
std::string(MEMORY_WLR_PORT_NAME),
true);
add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_bank_wls(module_manager, top_module, sr_banks,
std::string(WL_SHIFT_REGISTER_CHAIN_WL_OUT_NAME),
std::string(MEMORY_WL_PORT_NAME));
add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_bank_wls(module_manager, top_module, sr_banks,
std::string(WL_SHIFT_REGISTER_CHAIN_WLR_OUT_NAME),
std::string(MEMORY_WLR_PORT_NAME),
true);
}
/*********************************************************************
@ -1477,7 +1642,7 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(Module
********************************************************************/
void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_manager,
DecoderLibrary& decoder_lib,
std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
MemoryBankShiftRegisterBanks& blwl_sr_banks,
const ModuleId& top_module,
const CircuitLibrary& circuit_lib,
const ConfigProtocol& config_protocol,
@ -1495,7 +1660,7 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma
break;
}
case BLWL_PROTOCOL_SHIFT_REGISTER: {
add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(module_manager, blwl_sr_banks[0], top_module, circuit_lib, config_protocol);
add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(module_manager, blwl_sr_banks, top_module, circuit_lib, config_protocol);
break;
}
default: {
@ -1514,7 +1679,7 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma
break;
}
case BLWL_PROTOCOL_SHIFT_REGISTER: {
add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(module_manager, blwl_sr_banks[1], top_module, circuit_lib, config_protocol);
add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(module_manager, blwl_sr_banks, top_module, circuit_lib, config_protocol);
break;
}
default: {
@ -1556,6 +1721,7 @@ void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager,
const ModuleId& module_id,
const CircuitLibrary& circuit_lib,
const ConfigProtocol& config_protocol,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const TopModuleNumConfigBits& num_config_bits) {
VTR_ASSERT_SAFE(CONFIG_MEM_QL_MEMORY_BANK == config_protocol.type());
CircuitModelId sram_model = config_protocol.memory_model();
@ -1591,7 +1757,7 @@ void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager,
case BLWL_PROTOCOL_SHIFT_REGISTER: {
/* Each region will have independent shift register banks */
for (const ConfigRegionId& config_region : module_manager.regions(module_id)) {
size_t num_heads = config_protocol.bl_num_banks();
size_t num_heads = blwl_sr_banks.bl_banks(config_region).size();
BasicPort blsr_head_port(generate_regional_blwl_port_name(std::string(BL_SHIFT_REGISTER_CHAIN_HEAD_NAME), config_region), num_heads);
module_manager.add_port(module_id, blsr_head_port, ModuleManager::MODULE_INPUT_PORT);
BasicPort blsr_tail_port(generate_regional_blwl_port_name(std::string(BL_SHIFT_REGISTER_CHAIN_TAIL_NAME), config_region), num_heads);
@ -1640,7 +1806,7 @@ void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager,
case BLWL_PROTOCOL_SHIFT_REGISTER: {
/* Each region will have independent shift register banks */
for (const ConfigRegionId& config_region : module_manager.regions(module_id)) {
size_t num_heads = config_protocol.wl_num_banks();
size_t num_heads = blwl_sr_banks.wl_banks(config_region).size();
BasicPort wlsr_head_port(generate_regional_blwl_port_name(std::string(WL_SHIFT_REGISTER_CHAIN_HEAD_NAME), config_region), num_heads);
module_manager.add_port(module_id, wlsr_head_port, ModuleManager::MODULE_INPUT_PORT);
BasicPort wlsr_tail_port(generate_regional_blwl_port_name(std::string(WL_SHIFT_REGISTER_CHAIN_TAIL_NAME), config_region), num_heads);
@ -1655,4 +1821,121 @@ void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager,
}
}
/********************************************************************
* Load the shift register bank -related data from fabric key to
* the dedicated and unified data structure
********************************************************************/
int load_top_module_shift_register_banks_from_fabric_key(const FabricKey& fabric_key,
MemoryBankShiftRegisterBanks& blwl_sr_banks) {
blwl_sr_banks.resize_regions(fabric_key.regions().size());
/* Load Bit-Line shift register banks */
for (const auto& region : fabric_key.regions()) {
blwl_sr_banks.reserve_bl_shift_register_banks(region, fabric_key.bl_banks(region).size());
for (const auto& bank : fabric_key.bl_banks(region)) {
FabricBitLineBankId sr_bank = blwl_sr_banks.create_bl_shift_register_bank(region);
for (const auto& data_port : fabric_key.bl_bank_data_ports(region, bank)) {
blwl_sr_banks.add_data_port_to_bl_shift_register_bank(region, sr_bank, data_port);
}
}
}
/* Load Bit-Line shift register banks */
for (const auto& region : fabric_key.regions()) {
blwl_sr_banks.reserve_wl_shift_register_banks(region, fabric_key.wl_banks(region).size());
for (const auto& bank : fabric_key.wl_banks(region)) {
FabricWordLineBankId sr_bank = blwl_sr_banks.create_wl_shift_register_bank(region);
for (const auto& data_port : fabric_key.wl_bank_data_ports(region, bank)) {
blwl_sr_banks.add_data_port_to_wl_shift_register_bank(region, sr_bank, data_port);
}
}
}
return 0;
}
/********************************************************************
* @brief This functions synchronize the settings in configuration protocol (from architecture description)
* and the existing information (loaded from fabric key files)
* @note This function should be called AFTER load_top_module_shift_register_banks_from_fabric_key()
********************************************************************/
void sync_memory_bank_shift_register_banks_with_config_protocol_settings(ModuleManager& module_manager,
MemoryBankShiftRegisterBanks& blwl_sr_banks,
const ConfigProtocol& config_protocol,
const ModuleId& top_module,
const CircuitLibrary& circuit_lib) {
/* ONLY synchronize when the configuration protocol is memory bank using shift registers */
if ( CONFIG_MEM_QL_MEMORY_BANK != config_protocol.type()
|| BLWL_PROTOCOL_SHIFT_REGISTER != config_protocol.bl_protocol_type()
|| BLWL_PROTOCOL_SHIFT_REGISTER != config_protocol.wl_protocol_type() ) {
return;
}
/* Fabric key has a higher priority in defining the shift register bank organization */
if (!blwl_sr_banks.empty()) {
return;
}
CircuitModelId sram_model = config_protocol.memory_model();
/* Reach here, if means we do not have any definition from fabric key files, use the settings from the configuration protocol */
blwl_sr_banks.resize_regions(module_manager.regions(top_module).size());
/* Based on the number of shift register banks, evenly distribute the BLs in each region for each shift register bank */
for (const auto& config_region : module_manager.regions(top_module)) {
size_t num_bls = compute_memory_bank_regional_num_bls(module_manager, top_module,
config_region,
circuit_lib, sram_model);
size_t num_bl_banks = config_protocol.bl_num_banks();
blwl_sr_banks.reserve_bl_shift_register_banks(config_region, num_bl_banks);
size_t regular_sr_bank_size = num_bls / num_bl_banks;
size_t cur_bl_index = 0;
for (size_t ibank = 0; ibank < num_bl_banks; ++ibank) {
/* For last bank, use all the residual sizes */
size_t cur_sr_bank_size = regular_sr_bank_size;
if (ibank == num_bl_banks - 1) {
cur_sr_bank_size = num_bls - ibank * regular_sr_bank_size;
}
/* Create a bank and assign data ports */
FabricBitLineBankId bank = blwl_sr_banks.create_bl_shift_register_bank(config_region);
BasicPort data_ports(std::string(MEMORY_BL_PORT_NAME), cur_bl_index, cur_bl_index + cur_sr_bank_size - 1);
blwl_sr_banks.add_data_port_to_bl_shift_register_bank(config_region, bank, data_ports);
/* Increment the bl index */
cur_bl_index += cur_sr_bank_size;
}
VTR_ASSERT(cur_bl_index == num_bls);
}
/* Based on the number of shift register banks, evenly distribute the WLs in each region for each shift register bank */
for (const auto& config_region : module_manager.regions(top_module)) {
size_t num_wls = compute_memory_bank_regional_num_wls(module_manager, top_module,
config_region,
circuit_lib, sram_model);
size_t num_wl_banks = config_protocol.wl_num_banks();
blwl_sr_banks.reserve_wl_shift_register_banks(config_region, num_wl_banks);
size_t regular_sr_bank_size = num_wls / num_wl_banks;
size_t cur_wl_index = 0;
for (size_t ibank = 0; ibank < num_wl_banks; ++ibank) {
/* For last bank, use all the residual sizes */
size_t cur_sr_bank_size = regular_sr_bank_size;
if (ibank == num_wl_banks - 1) {
cur_sr_bank_size = num_wls - ibank * regular_sr_bank_size;
}
/* Create a bank and assign data ports */
FabricWordLineBankId bank = blwl_sr_banks.create_wl_shift_register_bank(config_region);
BasicPort data_ports(std::string(MEMORY_WL_PORT_NAME), cur_wl_index, cur_wl_index + cur_sr_bank_size - 1);
blwl_sr_banks.add_data_port_to_wl_shift_register_bank(config_region, bank, data_ports);
/* Increment the bl index */
cur_wl_index += cur_sr_bank_size;
}
VTR_ASSERT(cur_wl_index == num_wls);
}
}
} /* end namespace openfpga */

View File

@ -26,7 +26,7 @@ namespace openfpga {
void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_manager,
DecoderLibrary& decoder_lib,
std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
MemoryBankShiftRegisterBanks& blwl_sr_banks,
const ModuleId& top_module,
const CircuitLibrary& circuit_lib,
const ConfigProtocol& config_protocol,
@ -36,8 +36,17 @@ void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager,
const ModuleId& module_id,
const CircuitLibrary& circuit_lib,
const ConfigProtocol& config_protocol,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const TopModuleNumConfigBits& num_config_bits);
int load_top_module_shift_register_banks_from_fabric_key(const FabricKey& fabric_key,
MemoryBankShiftRegisterBanks& blwl_sr_banks);
void sync_memory_bank_shift_register_banks_with_config_protocol_settings(ModuleManager& module_manager,
MemoryBankShiftRegisterBanks& blwl_sr_banks,
const ConfigProtocol& config_protocol,
const ModuleId& top_module,
const CircuitLibrary& circuit_lib);
} /* end namespace openfpga */

View File

@ -32,6 +32,7 @@ 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) {
std::string timer_message = std::string("Write fabric key to XML file '") + fname + std::string("'");
@ -65,10 +66,20 @@ int write_fabric_key_to_xml_file(const ModuleManager& module_manager,
size_t num_regions = module_manager.regions(top_module).size();
fabric_key.reserve_regions(num_regions);
/* Create regions for the keys and load keys by region */
/* Create regions and build a id map */
std::map<ConfigRegionId, FabricRegionId> region_id_map;
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
FabricRegionId fabric_region = fabric_key.create_region();
region_id_map[config_region] = fabric_region;
}
/* Create regions for the keys and load keys by region */
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
/* Must have a valid one-to-one region mapping */
auto result = region_id_map.find(config_region);
VTR_ASSERT_SAFE(result != region_id_map.end());
FabricRegionId fabric_region = result->second;
/* Each configuration protocol has some child which should not be in the list. They are typically decoders */
size_t curr_region_num_config_child = module_manager.region_configurable_children(top_module, config_region).size();
size_t num_child_to_skip = estimate_num_configurable_children_to_skip_by_config_protocol(config_protocol, curr_region_num_config_child);
@ -97,6 +108,38 @@ int write_fabric_key_to_xml_file(const ModuleManager& module_manager,
}
}
/* Skip invalid region, some architecture may not have BL/WL banks */
if (0 < blwl_sr_banks.regions().size()) {
/* Add BL shift register bank information, if there is any */
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
auto result = region_id_map.find(config_region);
/* Must have a valid one-to-one region mapping */
VTR_ASSERT_SAFE(result != region_id_map.end());
FabricRegionId fabric_region = result->second;
for (const FabricBitLineBankId& bank : blwl_sr_banks.bl_banks(config_region)) {
FabricBitLineBankId fabric_bank = fabric_key.create_bl_shift_register_bank(fabric_region);
for (const BasicPort& data_port : blwl_sr_banks.bl_bank_data_ports(config_region, bank)) {
fabric_key.add_data_port_to_bl_shift_register_bank(fabric_region, fabric_bank, data_port);
}
}
}
/* Add WL shift register bank information, if there is any */
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
auto result = region_id_map.find(config_region);
/* Must have a valid one-to-one region mapping */
VTR_ASSERT_SAFE(result != region_id_map.end());
FabricRegionId fabric_region = result->second;
for (const FabricWordLineBankId& bank : blwl_sr_banks.wl_banks(config_region)) {
FabricWordLineBankId fabric_bank = fabric_key.create_wl_shift_register_bank(fabric_region);
for (const BasicPort& data_port : blwl_sr_banks.wl_bank_data_ports(config_region, bank)) {
fabric_key.add_data_port_to_wl_shift_register_bank(fabric_region, fabric_bank, data_port);
}
}
}
}
VTR_LOGV(verbose,
"Created %lu regions and %lu keys for the top module %s.\n",
num_regions, num_keys, top_module_name.c_str());

View File

@ -7,6 +7,7 @@
#include <string.h>
#include "module_manager.h"
#include "config_protocol.h"
#include "memory_bank_shift_register_banks.h"
/********************************************************************
* Function declaration
@ -18,6 +19,7 @@ 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);
} /* end namespace openfpga */

View File

@ -1,114 +1,495 @@
#include <algorithm>
#include "vtr_assert.h"
#include "openfpga_reserved_words.h"
#include "memory_bank_shift_register_banks.h"
/* begin namespace openfpga */
namespace openfpga {
std::vector<ModuleId> MemoryBankShiftRegisterBanks::shift_register_bank_unique_modules() const {
std::vector<ModuleId> sr_bank_modules;
for (const auto& region : sr_instance_sink_child_ids_) {
for (const auto& pair : region) {
if (sr_bank_modules.end() == std::find(sr_bank_modules.begin(), sr_bank_modules.end(), pair.first.first)) {
sr_bank_modules.push_back(pair.first.first);
ModuleManager::region_range MemoryBankShiftRegisterBanks::regions() const {
return vtr::make_range(config_region_ids_.begin(), config_region_ids_.end());
}
std::vector<size_t> MemoryBankShiftRegisterBanks::bl_bank_unique_sizes() const {
std::vector<size_t> unique_sizes;
for (const auto& region : bl_bank_data_ports_) {
for (const auto& bank : region) {
ConfigRegionId region_id = ConfigRegionId(&region - &bl_bank_data_ports_[ConfigRegionId(0)]);
FabricBitLineBankId bank_id = FabricBitLineBankId(&bank - &region[FabricBitLineBankId(0)]);
size_t cur_bank_size = bl_bank_size(region_id, bank_id);
if (unique_sizes.end() == std::find(unique_sizes.begin(), unique_sizes.end(), cur_bank_size)) {
unique_sizes.push_back(cur_bank_size);
}
}
}
return sr_bank_modules;
}
std::vector<ModuleId> MemoryBankShiftRegisterBanks::shift_register_bank_modules(const ConfigRegionId& region) const {
std::vector<ModuleId> sr_bank_modules;
VTR_ASSERT(valid_region_id(region));
for (const auto& pair : sr_instance_sink_child_ids_[region]) {
sr_bank_modules.push_back(pair.first.first);
}
return sr_bank_modules;
}
std::vector<size_t> MemoryBankShiftRegisterBanks::shift_register_bank_instances(const ConfigRegionId& region) const {
std::vector<size_t> sr_bank_instances;
VTR_ASSERT(valid_region_id(region));
for (const auto& pair : sr_instance_sink_child_ids_[region]) {
sr_bank_instances.push_back(pair.first.second);
}
return sr_bank_instances;
}
std::vector<size_t> MemoryBankShiftRegisterBanks::shift_register_bank_sink_child_ids(const ConfigRegionId& region,
const ModuleId& sr_module,
const size_t& sr_instance) const {
VTR_ASSERT(valid_region_id(region));
auto result = sr_instance_sink_child_ids_[region].find(std::make_pair(sr_module, sr_instance));
/* Return an empty vector if not found */
if (result != sr_instance_sink_child_ids_[region].end()) {
return result->second;
}
return std::vector<size_t>();
}
std::vector<size_t> MemoryBankShiftRegisterBanks::shift_register_bank_sink_pin_ids(const ConfigRegionId& region,
const ModuleId& sr_module,
const size_t& sr_instance) const {
VTR_ASSERT(valid_region_id(region));
auto result = sr_instance_sink_child_pin_ids_[region].find(std::make_pair(sr_module, sr_instance));
/* Return an empty vector if not found */
if (result != sr_instance_sink_child_pin_ids_[region].end()) {
return result->second;
}
return std::vector<size_t>();
return unique_sizes;
}
std::vector<size_t> MemoryBankShiftRegisterBanks::shift_register_bank_source_blwl_ids(const ConfigRegionId& region,
const ModuleId& sr_module,
const size_t& sr_instance) const {
VTR_ASSERT(valid_region_id(region));
auto result = sr_instance_source_blwl_ids_[region].find(std::make_pair(sr_module, sr_instance));
/* Return an empty vector if not found */
if (result != sr_instance_source_blwl_ids_[region].end()) {
return result->second;
std::vector<ModuleId> MemoryBankShiftRegisterBanks::bl_bank_unique_modules() const {
std::vector<ModuleId> unique_modules;
for (const auto& region : bl_bank_modules_) {
for (const auto& bank : region) {
if (unique_modules.end() == std::find(unique_modules.begin(), unique_modules.end(), bank)) {
unique_modules.push_back(bank);
}
}
}
return std::vector<size_t>();
return unique_modules;
}
size_t MemoryBankShiftRegisterBanks::bl_bank_size(const ConfigRegionId& region_id, const FabricBitLineBankId& bank_id) const {
size_t cur_bank_size = 0;
for (const auto& data_port : bl_bank_data_ports(region_id, bank_id)) {
cur_bank_size += data_port.get_width();
}
return cur_bank_size;
}
FabricKey::fabric_bit_line_bank_range MemoryBankShiftRegisterBanks::bl_banks(const ConfigRegionId& region_id) const {
VTR_ASSERT(valid_region_id(region_id));
return vtr::make_range(bl_bank_ids_[region_id].begin(), bl_bank_ids_[region_id].end());
}
std::vector<size_t> MemoryBankShiftRegisterBanks::wl_bank_unique_sizes() const {
std::vector<size_t> unique_sizes;
for (const auto& region : wl_bank_data_ports_) {
for (const auto& bank : region) {
ConfigRegionId region_id = ConfigRegionId(&region - &wl_bank_data_ports_[ConfigRegionId(0)]);
FabricWordLineBankId bank_id = FabricWordLineBankId(&bank - &region[FabricWordLineBankId(0)]);
size_t cur_bank_size = wl_bank_size(region_id, bank_id);
if (unique_sizes.end() == std::find(unique_sizes.begin(), unique_sizes.end(), cur_bank_size)) {
unique_sizes.push_back(cur_bank_size);
}
}
}
return unique_sizes;
}
std::vector<ModuleId> MemoryBankShiftRegisterBanks::wl_bank_unique_modules() const {
std::vector<ModuleId> unique_modules;
for (const auto& region : wl_bank_modules_) {
for (const auto& bank : region) {
if (unique_modules.end() == std::find(unique_modules.begin(), unique_modules.end(), bank)) {
unique_modules.push_back(bank);
}
}
}
return unique_modules;
}
size_t MemoryBankShiftRegisterBanks::wl_bank_size(const ConfigRegionId& region_id, const FabricWordLineBankId& bank_id) const {
size_t cur_bank_size = 0;
for (const auto& data_port : wl_bank_data_ports(region_id, bank_id)) {
cur_bank_size += data_port.get_width();
}
return cur_bank_size;
}
FabricKey::fabric_word_line_bank_range MemoryBankShiftRegisterBanks::wl_banks(const ConfigRegionId& region_id) const {
VTR_ASSERT(valid_region_id(region_id));
return vtr::make_range(wl_bank_ids_[region_id].begin(), wl_bank_ids_[region_id].end());
}
std::vector<BasicPort> MemoryBankShiftRegisterBanks::bl_bank_data_ports(const ConfigRegionId& region_id, const FabricBitLineBankId& bank_id) const {
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
return bl_bank_data_ports_[region_id][bank_id];
}
std::vector<BasicPort> MemoryBankShiftRegisterBanks::wl_bank_data_ports(const ConfigRegionId& region_id, const FabricWordLineBankId& bank_id) const {
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
return wl_bank_data_ports_[region_id][bank_id];
}
FabricBitLineBankId MemoryBankShiftRegisterBanks::find_bl_shift_register_bank_id(const ConfigRegionId& region,
const BasicPort& bl_port) const {
if (is_bl_bank_dirty_) {
build_bl_port_fast_lookup();
}
VTR_ASSERT(valid_region_id(region));
const auto& result = bl_ports_to_sr_bank_ids_[region].find(bl_port);
if (result == bl_ports_to_sr_bank_ids_[region].end()) {
return FabricBitLineBankId::INVALID();
}
return result->second;
}
BasicPort MemoryBankShiftRegisterBanks::find_bl_shift_register_bank_data_port(const ConfigRegionId& region,
const BasicPort& bl_port) const {
if (is_bl_bank_dirty_) {
build_bl_port_fast_lookup();
}
VTR_ASSERT(valid_region_id(region));
const auto& result = bl_ports_to_sr_bank_ports_[region].find(bl_port);
if (result == bl_ports_to_sr_bank_ports_[region].end()) {
return BasicPort();
}
return result->second;
}
std::vector<size_t> MemoryBankShiftRegisterBanks::bl_shift_register_bank_sink_child_ids(const ConfigRegionId& region_id,
const FabricBitLineBankId& bank_id,
const BasicPort& src_port) const {
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
auto result = bl_bank_sink_child_ids_[region_id][bank_id].find(src_port);
if (result == bl_bank_sink_child_ids_[region_id][bank_id].end()) {
return std::vector<size_t>(); /* Not found, return an empty list */
}
return result->second;
}
std::vector<size_t> MemoryBankShiftRegisterBanks::bl_shift_register_bank_sink_child_pin_ids(const ConfigRegionId& region_id,
const FabricBitLineBankId& bank_id,
const BasicPort& src_port) const {
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
auto result = bl_bank_sink_child_pin_ids_[region_id][bank_id].find(src_port);
if (result == bl_bank_sink_child_pin_ids_[region_id][bank_id].end()) {
return std::vector<size_t>(); /* Not found, return an empty list */
}
return result->second;
}
std::vector<BasicPort> MemoryBankShiftRegisterBanks::bl_shift_register_bank_source_ports(const ConfigRegionId& region_id,
const FabricBitLineBankId& bank_id) const {
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
std::vector<BasicPort> src_ports;
size_t cur_pin =0;
for (const BasicPort& wide_port : bl_bank_data_ports(region_id, bank_id)) {
for (size_t ipin = 0; ipin < wide_port.pins().size(); ++ipin) {
src_ports.push_back(BasicPort(std::string(MEMORY_BL_PORT_NAME), cur_pin, cur_pin));
cur_pin++;
}
}
return src_ports;
}
ModuleId MemoryBankShiftRegisterBanks::bl_shift_register_bank_module(const ConfigRegionId& region_id,
const FabricBitLineBankId& bank_id) const {
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
return bl_bank_modules_[region_id][bank_id];
}
size_t MemoryBankShiftRegisterBanks::bl_shift_register_bank_instance(const ConfigRegionId& region_id,
const FabricBitLineBankId& bank_id) const {
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
return bl_bank_instances_[region_id][bank_id];
}
FabricWordLineBankId MemoryBankShiftRegisterBanks::find_wl_shift_register_bank_id(const ConfigRegionId& region,
const BasicPort& wl_port) const {
if (is_wl_bank_dirty_) {
build_wl_port_fast_lookup();
}
VTR_ASSERT(valid_region_id(region));
const auto& result = wl_ports_to_sr_bank_ids_[region].find(wl_port);
if (result == wl_ports_to_sr_bank_ids_[region].end()) {
return FabricWordLineBankId::INVALID();
}
return result->second;
}
BasicPort MemoryBankShiftRegisterBanks::find_wl_shift_register_bank_data_port(const ConfigRegionId& region,
const BasicPort& wl_port) const {
if (is_wl_bank_dirty_) {
build_wl_port_fast_lookup();
}
VTR_ASSERT(valid_region_id(region));
const auto& result = wl_ports_to_sr_bank_ports_[region].find(wl_port);
if (result == wl_ports_to_sr_bank_ports_[region].end()) {
return BasicPort();
}
return result->second;
}
void MemoryBankShiftRegisterBanks::resize_regions(const size_t& num_regions) {
sr_instance_sink_child_ids_.resize(num_regions);
sr_instance_sink_child_pin_ids_.resize(num_regions);
sr_instance_source_blwl_ids_.resize(num_regions);
config_region_ids_.resize(num_regions);
for (size_t iregion = 0; iregion < num_regions; ++iregion) {
config_region_ids_[ConfigRegionId(iregion)] = ConfigRegionId(iregion);
}
bl_bank_ids_.resize(num_regions);
bl_bank_data_ports_.resize(num_regions);
bl_bank_modules_.resize(num_regions);
bl_bank_instances_.resize(num_regions);
bl_bank_sink_child_ids_.resize(num_regions);
bl_bank_sink_child_pin_ids_.resize(num_regions);
wl_bank_ids_.resize(num_regions);
wl_bank_data_ports_.resize(num_regions);
wl_bank_modules_.resize(num_regions);
wl_bank_instances_.resize(num_regions);
wl_bank_sink_child_ids_.resize(num_regions);
wl_bank_sink_child_pin_ids_.resize(num_regions);
}
void MemoryBankShiftRegisterBanks::add_shift_register_instance(const ConfigRegionId& region,
const ModuleId& sr_module,
const size_t& sr_instance) {
VTR_ASSERT(valid_region_id(region));
sr_instance_sink_child_ids_[region][std::make_pair(sr_module, sr_instance)];
sr_instance_sink_child_pin_ids_[region][std::make_pair(sr_module, sr_instance)];
sr_instance_source_blwl_ids_[region][std::make_pair(sr_module, sr_instance)];
void MemoryBankShiftRegisterBanks::link_bl_shift_register_bank_to_module(const ConfigRegionId& region_id,
const FabricBitLineBankId& bank_id,
const ModuleId& module_id) {
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
bl_bank_modules_[region_id][bank_id] = module_id;
}
void MemoryBankShiftRegisterBanks::add_shift_register_sink_nodes(const ConfigRegionId& region,
const ModuleId& sr_module,
const size_t& sr_instance,
const size_t& sink_child_id,
const size_t& sink_child_pin_id) {
VTR_ASSERT(valid_region_id(region));
sr_instance_sink_child_ids_[region][std::make_pair(sr_module, sr_instance)].push_back(sink_child_id);
sr_instance_sink_child_pin_ids_[region][std::make_pair(sr_module, sr_instance)].push_back(sink_child_pin_id);
void MemoryBankShiftRegisterBanks::link_bl_shift_register_bank_to_instance(const ConfigRegionId& region_id,
const FabricBitLineBankId& bank_id,
const size_t& instance_id) {
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
bl_bank_instances_[region_id][bank_id] = instance_id;
}
void MemoryBankShiftRegisterBanks::add_shift_register_source_blwls(const ConfigRegionId& region,
const ModuleId& sr_module,
const size_t& sr_instance,
const size_t& sink_blwl_id) {
VTR_ASSERT(valid_region_id(region));
sr_instance_source_blwl_ids_[region][std::make_pair(sr_module, sr_instance)].push_back(sink_blwl_id);
}
void MemoryBankShiftRegisterBanks::link_wl_shift_register_bank_to_module(const ConfigRegionId& region_id,
const FabricWordLineBankId& bank_id,
const ModuleId& module_id) {
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
wl_bank_modules_[region_id][bank_id] = module_id;
}
void MemoryBankShiftRegisterBanks::link_wl_shift_register_bank_to_instance(const ConfigRegionId& region_id,
const FabricWordLineBankId& bank_id,
const size_t& instance_id) {
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
wl_bank_instances_[region_id][bank_id] = instance_id;
}
void MemoryBankShiftRegisterBanks::add_bl_shift_register_bank_sink_node(const ConfigRegionId& region,
const FabricBitLineBankId& bank,
const BasicPort& src_port,
const size_t& sink_child_id,
const size_t& sink_child_pin_id) {
VTR_ASSERT(valid_bl_bank_id(region, bank));
bl_bank_sink_child_ids_[region][bank][src_port].push_back(sink_child_id);
bl_bank_sink_child_pin_ids_[region][bank][src_port].push_back(sink_child_pin_id);
}
void MemoryBankShiftRegisterBanks::add_wl_shift_register_bank_sink_node(const ConfigRegionId& region,
const FabricWordLineBankId& bank,
const BasicPort& src_port,
const size_t& sink_child_id,
const size_t& sink_child_pin_id) {
VTR_ASSERT(valid_wl_bank_id(region, bank));
wl_bank_sink_child_ids_[region][bank][src_port].push_back(sink_child_id);
wl_bank_sink_child_pin_ids_[region][bank][src_port].push_back(sink_child_pin_id);
}
void MemoryBankShiftRegisterBanks::reserve_bl_shift_register_banks(const ConfigRegionId& region_id, const size_t& num_banks) {
VTR_ASSERT(valid_region_id(region_id));
bl_bank_ids_[region_id].reserve(num_banks);
bl_bank_data_ports_[region_id].reserve(num_banks);
bl_bank_modules_[region_id].reserve(num_banks);
bl_bank_instances_[region_id].reserve(num_banks);
bl_bank_sink_child_ids_[region_id].reserve(num_banks);
bl_bank_sink_child_pin_ids_[region_id].reserve(num_banks);
}
void MemoryBankShiftRegisterBanks::reserve_bl_shift_register_banks(const FabricRegionId& region_id, const size_t& num_banks) {
ConfigRegionId config_region_id = ConfigRegionId(size_t(region_id));
reserve_bl_shift_register_banks(config_region_id, num_banks);
}
void MemoryBankShiftRegisterBanks::reserve_wl_shift_register_banks(const ConfigRegionId& region_id, const size_t& num_banks) {
VTR_ASSERT(valid_region_id(region_id));
wl_bank_ids_[region_id].reserve(num_banks);
wl_bank_data_ports_[region_id].reserve(num_banks);
wl_bank_modules_[region_id].reserve(num_banks);
wl_bank_instances_[region_id].reserve(num_banks);
wl_bank_sink_child_ids_[region_id].reserve(num_banks);
wl_bank_sink_child_pin_ids_[region_id].reserve(num_banks);
}
void MemoryBankShiftRegisterBanks::reserve_wl_shift_register_banks(const FabricRegionId& region_id, const size_t& num_banks) {
ConfigRegionId config_region_id = ConfigRegionId(size_t(region_id));
reserve_wl_shift_register_banks(config_region_id, num_banks);
}
FabricBitLineBankId MemoryBankShiftRegisterBanks::create_bl_shift_register_bank(const ConfigRegionId& region_id) {
VTR_ASSERT(valid_region_id(region_id));
/* Create a new id */
FabricBitLineBankId bank = FabricBitLineBankId(bl_bank_ids_[region_id].size());
bl_bank_ids_[region_id].push_back(bank);
bl_bank_data_ports_[region_id].emplace_back();
bl_bank_modules_[region_id].push_back(ModuleId::INVALID());
bl_bank_instances_[region_id].emplace_back();
bl_bank_sink_child_ids_[region_id].emplace_back();
bl_bank_sink_child_pin_ids_[region_id].emplace_back();
return bank;
}
FabricBitLineBankId MemoryBankShiftRegisterBanks::create_bl_shift_register_bank(const FabricRegionId& region_id) {
ConfigRegionId config_region_id = ConfigRegionId(size_t(region_id));
return create_bl_shift_register_bank(config_region_id);
}
void MemoryBankShiftRegisterBanks::add_data_port_to_bl_shift_register_bank(const FabricRegionId& region_id,
const FabricBitLineBankId& bank_id,
const openfpga::BasicPort& data_port) {
ConfigRegionId config_region_id = ConfigRegionId(size_t(region_id));
add_data_port_to_bl_shift_register_bank(config_region_id, bank_id, data_port);
}
void MemoryBankShiftRegisterBanks::add_data_port_to_bl_shift_register_bank(const ConfigRegionId& region_id,
const FabricBitLineBankId& bank_id,
const openfpga::BasicPort& data_port) {
VTR_ASSERT(valid_bl_bank_id(region_id, bank_id));
bl_bank_data_ports_[region_id][bank_id].push_back(data_port);
is_bl_bank_dirty_ = true;
}
FabricWordLineBankId MemoryBankShiftRegisterBanks::create_wl_shift_register_bank(const FabricRegionId& region_id) {
ConfigRegionId config_region_id = ConfigRegionId(size_t(region_id));
return create_wl_shift_register_bank(config_region_id);
}
FabricWordLineBankId MemoryBankShiftRegisterBanks::create_wl_shift_register_bank(const ConfigRegionId& region_id) {
VTR_ASSERT(valid_region_id(region_id));
/* Create a new id */
FabricWordLineBankId bank = FabricWordLineBankId(wl_bank_ids_[region_id].size());
wl_bank_ids_[region_id].push_back(bank);
wl_bank_data_ports_[region_id].emplace_back();
wl_bank_modules_[region_id].push_back(ModuleId::INVALID());
wl_bank_instances_[region_id].emplace_back();
wl_bank_sink_child_ids_[region_id].emplace_back();
wl_bank_sink_child_pin_ids_[region_id].emplace_back();
return bank;
}
void MemoryBankShiftRegisterBanks::add_data_port_to_wl_shift_register_bank(const FabricRegionId& region_id,
const FabricWordLineBankId& bank_id,
const openfpga::BasicPort& data_port) {
ConfigRegionId config_region_id = ConfigRegionId(size_t(region_id));
add_data_port_to_wl_shift_register_bank(config_region_id, bank_id, data_port);
}
void MemoryBankShiftRegisterBanks::add_data_port_to_wl_shift_register_bank(const ConfigRegionId& region_id,
const FabricWordLineBankId& bank_id,
const openfpga::BasicPort& data_port) {
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
wl_bank_data_ports_[region_id][bank_id].push_back(data_port);
is_wl_bank_dirty_ = true;
}
std::vector<size_t> MemoryBankShiftRegisterBanks::wl_shift_register_bank_sink_child_ids(const ConfigRegionId& region_id,
const FabricWordLineBankId& bank_id,
const BasicPort& src_port) const {
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
auto result = wl_bank_sink_child_ids_[region_id][bank_id].find(src_port);
if (result == wl_bank_sink_child_ids_[region_id][bank_id].end()) {
return std::vector<size_t>(); /* Not found, return an empty list */
}
return result->second;
}
ModuleId MemoryBankShiftRegisterBanks::wl_shift_register_bank_module(const ConfigRegionId& region_id,
const FabricWordLineBankId& bank_id) const {
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
return wl_bank_modules_[region_id][bank_id];
}
size_t MemoryBankShiftRegisterBanks::wl_shift_register_bank_instance(const ConfigRegionId& region_id,
const FabricWordLineBankId& bank_id) const {
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
return wl_bank_instances_[region_id][bank_id];
}
std::vector<size_t> MemoryBankShiftRegisterBanks::wl_shift_register_bank_sink_child_pin_ids(const ConfigRegionId& region_id,
const FabricWordLineBankId& bank_id,
const BasicPort& src_port) const {
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
auto result = wl_bank_sink_child_pin_ids_[region_id][bank_id].find(src_port);
if (result == wl_bank_sink_child_pin_ids_[region_id][bank_id].end()) {
return std::vector<size_t>(); /* Not found, return an empty list */
}
return result->second;
}
std::vector<BasicPort> MemoryBankShiftRegisterBanks::wl_shift_register_bank_source_ports(const ConfigRegionId& region_id,
const FabricWordLineBankId& bank_id) const {
VTR_ASSERT(valid_wl_bank_id(region_id, bank_id));
std::vector<BasicPort> src_ports;
size_t cur_pin = 0;
for (const BasicPort& wide_port : wl_bank_data_ports(region_id, bank_id)) {
for (size_t ipin = 0; ipin < wide_port.pins().size(); ++ipin) {
src_ports.push_back(BasicPort(std::string(MEMORY_WL_PORT_NAME), cur_pin, cur_pin));
cur_pin++;
}
}
return src_ports;
}
bool MemoryBankShiftRegisterBanks::valid_region_id(const ConfigRegionId& region) const {
return size_t(region) < sr_instance_sink_child_ids_.size();
return size_t(region) < bl_bank_ids_.size();
}
bool MemoryBankShiftRegisterBanks::valid_bl_bank_id(const ConfigRegionId& region_id, const FabricBitLineBankId& bank_id) const {
if (!valid_region_id(region_id)) {
return false;
}
return ( size_t(bank_id) < bl_bank_ids_[region_id].size() ) && ( bank_id == bl_bank_ids_[region_id][bank_id] );
}
bool MemoryBankShiftRegisterBanks::valid_wl_bank_id(const ConfigRegionId& region_id, const FabricWordLineBankId& bank_id) const {
if (!valid_region_id(region_id)) {
return false;
}
return ( size_t(bank_id) < wl_bank_ids_[region_id].size() ) && ( bank_id == wl_bank_ids_[region_id][bank_id] );
}
bool MemoryBankShiftRegisterBanks::empty() const {
return bl_bank_ids_.empty() && wl_bank_ids_.empty();
}
void MemoryBankShiftRegisterBanks::build_bl_port_fast_lookup() const {
bl_ports_to_sr_bank_ids_.resize(bl_bank_data_ports_.size());
bl_ports_to_sr_bank_ports_.resize(bl_bank_data_ports_.size());
for (const auto& region : bl_bank_data_ports_) {
for (const auto& bank : region) {
size_t cur_pin = 0;
for (const auto& port : bank) {
for (const size_t& bl_index : port.pins()) {
BasicPort bl_port(std::string(MEMORY_BL_PORT_NAME), bl_index, bl_index);
BasicPort sr_bl_port(std::string(MEMORY_BL_PORT_NAME), cur_pin, cur_pin);
ConfigRegionId region_id = ConfigRegionId(&region - &bl_bank_data_ports_[ConfigRegionId(0)]);
FabricBitLineBankId bank_id = FabricBitLineBankId(&bank - &region[FabricBitLineBankId(0)]);
bl_ports_to_sr_bank_ids_[region_id][bl_port] = bank_id;
bl_ports_to_sr_bank_ports_[region_id][bl_port] = sr_bl_port;
cur_pin++;
}
}
}
}
/* Clear the flag, now fast look-up is synchronized */
is_bl_bank_dirty_ = false;
}
void MemoryBankShiftRegisterBanks::build_wl_port_fast_lookup() const {
wl_ports_to_sr_bank_ids_.resize(wl_bank_data_ports_.size());
wl_ports_to_sr_bank_ports_.resize(wl_bank_data_ports_.size());
for (const auto& region : wl_bank_data_ports_) {
for (const auto& bank : region) {
size_t cur_pin = 0;
for (const auto& port : bank) {
for (const size_t& wl_index : port.pins()) {
BasicPort wl_port(std::string(MEMORY_WL_PORT_NAME), wl_index, wl_index);
BasicPort sr_wl_port(std::string(MEMORY_WL_PORT_NAME), cur_pin, cur_pin);
ConfigRegionId region_id = ConfigRegionId(&region - &wl_bank_data_ports_[ConfigRegionId(0)]);
FabricWordLineBankId bank_id = FabricWordLineBankId(&bank - &region[FabricWordLineBankId(0)]);
wl_ports_to_sr_bank_ids_[region_id][wl_port] = bank_id;
wl_ports_to_sr_bank_ports_[region_id][wl_port] = sr_wl_port;
cur_pin++;
}
}
}
}
/* Clear the flag, now fast look-up is synchronized */
is_wl_bank_dirty_ = false;
}
} /* end namespace openfpga */

View File

@ -4,6 +4,7 @@
#include <map>
#include <vector>
#include "vtr_vector.h"
#include "fabric_key.h"
#include "module_manager.h"
/* begin namespace openfpga */
@ -21,65 +22,215 @@ namespace openfpga {
* @note This data structure is mainly used as a database for adding connections around shift register banks in top-level module
******************************************************************************/
class MemoryBankShiftRegisterBanks {
public: /* Accessors: aggregates */
ModuleManager::region_range regions() const;
FabricKey::fabric_bit_line_bank_range bl_banks(const ConfigRegionId& region_id) const;
FabricKey::fabric_word_line_bank_range wl_banks(const ConfigRegionId& region_id) const;
public: /* Accessors */
/* @brief Return a list of modules of unique shift register banks across all the regions */
std::vector<ModuleId> shift_register_bank_unique_modules() const;
/* @brief Return a list of unique sizes of shift register banks for BL protocol */
std::vector<size_t> bl_bank_unique_sizes() const;
/* @brief Return a list of modules of shift register banks under a specific configuration region of top-level module */
std::vector<ModuleId> shift_register_bank_modules(const ConfigRegionId& region) const;
/* @brief Return a list of unique modules of shift register banks for BL protocol */
std::vector<ModuleId> bl_bank_unique_modules() const;
/* @brief Return a list of instances of shift register banks under a specific configuration region of top-level module */
std::vector<size_t> shift_register_bank_instances(const ConfigRegionId& region) const;
/* @brief Return the size of a BL shift register bank */
size_t bl_bank_size(const ConfigRegionId& region_id, const FabricBitLineBankId& bank_id) const;
/* @brief Return a list of ids of reconfigurable children for a given instance of shift register bank
* under a specific configuration region of top-level module
/* @brief Return a list of data ports which will be driven by a BL shift register bank */
std::vector<BasicPort> bl_bank_data_ports(const ConfigRegionId& region_id, const FabricBitLineBankId& bank_id) const;
/** @brief find the BL shift register bank id to which a BL port is connected to */
FabricBitLineBankId find_bl_shift_register_bank_id(const ConfigRegionId& region, const BasicPort& bl_port) const;
/** @brief find the data port of a BL shift register bank id to which a BL port is connected to */
BasicPort find_bl_shift_register_bank_data_port(const ConfigRegionId& region, const BasicPort& bl_port) const;
/** @brief Return the module id of a BL shift register bank */
ModuleId bl_shift_register_bank_module(const ConfigRegionId& region_id,
const FabricBitLineBankId& bank_id) const;
/** @brief Return the instance id of a BL shift register bank */
size_t bl_shift_register_bank_instance(const ConfigRegionId& region_id,
const FabricBitLineBankId& bank_id) const;
/** @brief return the child ids at top-level module to which a data port (1-bit) of a BL shift register bank is connected to
* @note a BL may drive multiple children (children on the same column share the same BLs)
*/
std::vector<size_t> shift_register_bank_sink_child_ids(const ConfigRegionId& region,
const ModuleId& sr_module,
const size_t& sr_instance) const;
std::vector<size_t> bl_shift_register_bank_sink_child_ids(const ConfigRegionId& region_id,
const FabricBitLineBankId& bank_id,
const BasicPort& src_port) const;
/* @brief Return a list of BL/WL ids of reconfigurable children for a given instance of shift register bank
* under a specific configuration region of top-level module
/** @brief return the child pin id of the child module at top-level module
* to which a data port (1-bit) of a BL shift register bank is connected to
* @note a BL may drive multiple children (children on the same column share the same BLs)
*/
std::vector<size_t> shift_register_bank_sink_pin_ids(const ConfigRegionId& region,
const ModuleId& sr_module,
const size_t& sr_instance) const;
std::vector<size_t> bl_shift_register_bank_sink_child_pin_ids(const ConfigRegionId& region_id,
const FabricBitLineBankId& bank_id,
const BasicPort& src_port) const;
/* @brief Return a list of BL/WL ids of a given instance of shift register bank
* under a specific configuration region of top-level module
/** @brief Return a list of single-bit ports which are the data ports of a BL shift register bank */
std::vector<BasicPort> bl_shift_register_bank_source_ports(const ConfigRegionId& region_id,
const FabricBitLineBankId& bank_id) const;
/* @brief Return a list of unique sizes of shift register banks for WL protocol */
std::vector<size_t> wl_bank_unique_sizes() const;
/* @brief Return a list of unique modules of shift register banks for WL protocol */
std::vector<ModuleId> wl_bank_unique_modules() const;
/* @brief Return the size of a WL shift register bank */
size_t wl_bank_size(const ConfigRegionId& region_id, const FabricWordLineBankId& bank_id) const;
/* @brief Return a list of data ports which will be driven by a WL shift register bank */
std::vector<BasicPort> wl_bank_data_ports(const ConfigRegionId& region_id, const FabricWordLineBankId& bank_id) const;
/** @brief find the WL shift register bank id to which a BL port is connected to */
FabricWordLineBankId find_wl_shift_register_bank_id(const ConfigRegionId& region, const BasicPort& wl_port) const;
/** @brief find the data port of a WL shift register bank id to which a BL port is connected to */
BasicPort find_wl_shift_register_bank_data_port(const ConfigRegionId& region, const BasicPort& wl_port) const;
/** @brief Return the module id of a WL shift register bank */
ModuleId wl_shift_register_bank_module(const ConfigRegionId& region_id,
const FabricWordLineBankId& bank_id) const;
/** @brief Return the instance id of a WL shift register bank */
size_t wl_shift_register_bank_instance(const ConfigRegionId& region_id,
const FabricWordLineBankId& bank_id) const;
/** @brief return the child id at top-level module to which a data port (1-bit) of a WL shift register bank is connected to
* @note a WL may drive multiple children (children on the same row share the same WLs)
*/
std::vector<size_t> shift_register_bank_source_blwl_ids(const ConfigRegionId& region,
const ModuleId& sr_module,
const size_t& sr_instance) const;
std::vector<size_t> wl_shift_register_bank_sink_child_ids(const ConfigRegionId& region,
const FabricWordLineBankId& bank_id,
const BasicPort& src_port) const;
/** @brief return the child pin id of the child module at top-level module
* to which a data port (1-bit) of a WL shift register bank is connected to
* @note a WL may drive multiple children (children on the same row share the same WLs)
*/
std::vector<size_t> wl_shift_register_bank_sink_child_pin_ids(const ConfigRegionId& region,
const FabricWordLineBankId& bank_id,
const BasicPort& src_port) const;
/** @brief Return a list of single-bit ports which are the data ports of a WL shift register bank */
std::vector<BasicPort> wl_shift_register_bank_source_ports(const ConfigRegionId& region_id,
const FabricWordLineBankId& bank_id) const;
public: /* Mutators */
void resize_regions(const size_t& num_regions);
/* @brief Add the module id and instance id of a shift register under a specific configuration region of top-level module */
void add_shift_register_instance(const ConfigRegionId& region,
const ModuleId& sr_module,
const size_t& sr_instance);
/* Reserve a number of banks to be memory efficent */
void reserve_bl_shift_register_banks(const FabricRegionId& region_id, const size_t& num_banks);
void reserve_bl_shift_register_banks(const ConfigRegionId& region_id, const size_t& num_banks);
/* @brief Add the child id and pin id of BL/WL to which a shift register is connected to under a specific configuration region of top-level module */
void add_shift_register_sink_nodes(const ConfigRegionId& region,
const ModuleId& sr_module,
const size_t& sr_instance,
const size_t& sink_child_id,
const size_t& sink_child_pin_id);
/* Create a new shift register bank for BLs and return an id */
FabricBitLineBankId create_bl_shift_register_bank(const FabricRegionId& region_id);
FabricBitLineBankId create_bl_shift_register_bank(const ConfigRegionId& region_id);
/* 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);
void add_data_port_to_bl_shift_register_bank(const ConfigRegionId& region_id,
const FabricBitLineBankId& bank_id,
const openfpga::BasicPort& data_port);
/* Link a BL shift register bank to a module id */
void link_bl_shift_register_bank_to_module(const ConfigRegionId& region_id,
const FabricBitLineBankId& bank_id,
const ModuleId& module_id);
/* Link a BL shift register bank to a instance id */
void link_bl_shift_register_bank_to_instance(const ConfigRegionId& region_id,
const FabricBitLineBankId& bank_id,
const size_t& instance_id);
/* @brief Add the child id and pin id of BL to which a shift register is connected to under a specific configuration region of top-level module */
void add_bl_shift_register_bank_sink_node(const ConfigRegionId& region,
const FabricBitLineBankId& bank,
const BasicPort& src_port,
const size_t& sink_child_id,
const size_t& sink_child_pin_id);
/* Reserve a number of banks to be memory efficent */
void reserve_wl_shift_register_banks(const FabricRegionId& region_id, const size_t& num_banks);
void reserve_wl_shift_register_banks(const ConfigRegionId& region_id, const size_t& num_banks);
/* Create a new shift register bank for WLs and return an id */
FabricWordLineBankId create_wl_shift_register_bank(const FabricRegionId& region_id);
FabricWordLineBankId create_wl_shift_register_bank(const ConfigRegionId& region_id);
/* 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);
void add_data_port_to_wl_shift_register_bank(const ConfigRegionId& region_id,
const FabricWordLineBankId& bank_id,
const openfpga::BasicPort& data_port);
/* Link a WL shift register bank to a module id */
void link_wl_shift_register_bank_to_module(const ConfigRegionId& region_id,
const FabricWordLineBankId& bank_id,
const ModuleId& module_id);
/* Link a WL shift register bank to a instance id */
void link_wl_shift_register_bank_to_instance(const ConfigRegionId& region_id,
const FabricWordLineBankId& bank_id,
const size_t& instance_id);
/* @brief Add the child id and pin id of WL to which a shift register is connected to under a specific configuration region of top-level module */
void add_wl_shift_register_bank_sink_node(const ConfigRegionId& region,
const FabricWordLineBankId& bank,
const BasicPort& src_port,
const size_t& sink_child_id,
const size_t& sink_child_pin_id);
/* @brief Add the BL/WL id under a specific configuration region of top-level module to which a shift register is connected to */
void add_shift_register_source_blwls(const ConfigRegionId& region,
const ModuleId& sr_module,
const size_t& sr_instance,
const size_t& sink_blwl_id);
public: /* Validators */
bool valid_region_id(const ConfigRegionId& region) const;
bool valid_bl_bank_id(const ConfigRegionId& region_id, const FabricBitLineBankId& bank_id) const;
bool valid_wl_bank_id(const ConfigRegionId& region_id, const FabricWordLineBankId& bank_id) const;
bool empty() const;
private: /* Internal Mutators */
/** @brief Build the mapping from a BL/WL port to shift register bank and assoicated pins
* @note we use const here because the caller functions, e.g., find_bl_shift_register_bank_id(), is const
* even though it does modify internal data
*/
void build_bl_port_fast_lookup() const;
void build_wl_port_fast_lookup() const;
private: /* Internal data */
/* [config_region][(shift_register_module, shift_register_instance)][i] = (reconfigurable_child_id, blwl_port_pin_index)*/
vtr::vector<ConfigRegionId, std::map<std::pair<ModuleId, size_t>, std::vector<size_t>>> sr_instance_sink_child_ids_;
vtr::vector<ConfigRegionId, std::map<std::pair<ModuleId, size_t>, std::vector<size_t>>> sr_instance_sink_child_pin_ids_;
vtr::vector<ConfigRegionId, std::map<std::pair<ModuleId, size_t>, std::vector<size_t>>> sr_instance_source_blwl_ids_;
vtr::vector<ConfigRegionId, ConfigRegionId> config_region_ids_;
/* General information about the BL shift register bank */
vtr::vector<ConfigRegionId, vtr::vector<FabricBitLineBankId, FabricBitLineBankId>> bl_bank_ids_;
vtr::vector<ConfigRegionId, vtr::vector<FabricBitLineBankId, std::vector<BasicPort>>> bl_bank_data_ports_;
vtr::vector<ConfigRegionId, vtr::vector<FabricBitLineBankId, ModuleId>> bl_bank_modules_;
vtr::vector<ConfigRegionId, vtr::vector<FabricBitLineBankId, size_t>> bl_bank_instances_;
vtr::vector<ConfigRegionId, vtr::vector<FabricBitLineBankId, std::map<BasicPort, std::vector<size_t>>>> bl_bank_sink_child_ids_;
vtr::vector<ConfigRegionId, vtr::vector<FabricBitLineBankId, std::map<BasicPort, std::vector<size_t>>>> bl_bank_sink_child_pin_ids_;
/* General information about the WL shift register bank */
vtr::vector<ConfigRegionId, vtr::vector<FabricWordLineBankId, FabricWordLineBankId>> wl_bank_ids_;
vtr::vector<ConfigRegionId, vtr::vector<FabricWordLineBankId, std::vector<BasicPort>>> wl_bank_data_ports_;
vtr::vector<ConfigRegionId, vtr::vector<FabricWordLineBankId, ModuleId>> wl_bank_modules_;
vtr::vector<ConfigRegionId, vtr::vector<FabricWordLineBankId, size_t>> wl_bank_instances_;
vtr::vector<ConfigRegionId, vtr::vector<FabricWordLineBankId, std::map<BasicPort, std::vector<size_t>>>> wl_bank_sink_child_ids_;
vtr::vector<ConfigRegionId, vtr::vector<FabricWordLineBankId, std::map<BasicPort, std::vector<size_t>>>> wl_bank_sink_child_pin_ids_;
/* Fast look-up: given a BL/Wl port, e.g., bl[i], find out
* - the shift register bank id
* - the output pin id of the shift register bank
*/
mutable vtr::vector<ConfigRegionId, std::map<BasicPort, FabricBitLineBankId>> bl_ports_to_sr_bank_ids_;
mutable vtr::vector<ConfigRegionId, std::map<BasicPort, BasicPort>> bl_ports_to_sr_bank_ports_;
mutable vtr::vector<ConfigRegionId, std::map<BasicPort, FabricWordLineBankId>> wl_ports_to_sr_bank_ids_;
mutable vtr::vector<ConfigRegionId, std::map<BasicPort, BasicPort>> wl_ports_to_sr_bank_ports_;
/* A flag to indicate that the general information of the shift register banks have been modified, fast look-up has to be updated */
mutable bool is_bl_bank_dirty_ = false;
mutable bool is_wl_bank_dirty_ = false;
};
} /* end namespace openfpga */

View File

@ -244,6 +244,7 @@ int write_memory_bank_shift_register_fabric_bitstream_to_text_file(std::fstream&
const bool& fast_configuration,
const bool& bit_value_to_skip,
const FabricBitstream& fabric_bitstream,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const bool& keep_dont_care_bits) {
int status = 0;
@ -251,7 +252,7 @@ int write_memory_bank_shift_register_fabric_bitstream_to_text_file(std::fstream&
if (keep_dont_care_bits) {
dont_care_bit = DONT_CARE_CHAR;
}
MemoryBankShiftRegisterFabricBitstream fabric_bits = build_memory_bank_shift_register_fabric_bitstream(fabric_bitstream, fast_configuration, bit_value_to_skip, dont_care_bit);
MemoryBankShiftRegisterFabricBitstream fabric_bits = build_memory_bank_shift_register_fabric_bitstream(fabric_bitstream, blwl_sr_banks, fast_configuration, bit_value_to_skip, dont_care_bit);
/* Output information about how to intepret the bitstream */
fp << "// Bitstream word count: " << fabric_bits.num_words() << std::endl;
@ -363,6 +364,7 @@ int write_frame_based_fabric_bitstream_to_text_file(std::fstream& fp,
*******************************************************************/
int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manager,
const FabricBitstream& fabric_bitstream,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const ConfigProtocol& config_protocol,
const FabricGlobalPortInfo& global_ports,
const std::string& fname,
@ -439,6 +441,7 @@ int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manage
apply_fast_configuration,
bit_value_to_skip,
fabric_bitstream,
blwl_sr_banks,
keep_dont_care_bits);
}
break;

View File

@ -9,6 +9,7 @@
#include "bitstream_manager.h"
#include "fabric_bitstream.h"
#include "config_protocol.h"
#include "memory_bank_shift_register_banks.h"
#include "fabric_global_port_info.h"
/********************************************************************
@ -20,6 +21,7 @@ namespace openfpga {
int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manager,
const FabricBitstream& fabric_bitstream,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const ConfigProtocol& config_protocol,
const FabricGlobalPortInfo& global_ports,
const std::string& fname,

View File

@ -55,7 +55,7 @@ namespace openfpga {
********************************************************************/
void fpga_fabric_verilog(ModuleManager &module_manager,
NetlistManager &netlist_manager,
const std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const CircuitLibrary &circuit_lib,
const MuxLibrary &mux_lib,
const DecoderLibrary &decoder_lib,
@ -149,6 +149,7 @@ void fpga_fabric_verilog(ModuleManager &module_manager,
int fpga_verilog_full_testbench(const ModuleManager &module_manager,
const BitstreamManager &bitstream_manager,
const FabricBitstream &fabric_bitstream,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const AtomContext &atom_ctx,
const PlacementContext &place_ctx,
const PinConstraints& pin_constraints,
@ -175,7 +176,7 @@ int fpga_verilog_full_testbench(const ModuleManager &module_manager,
/* Generate full testbench for verification, including configuration phase and operating phase */
std::string top_testbench_file_path = src_dir_path + netlist_name + std::string(AUTOCHECK_TOP_TESTBENCH_VERILOG_FILE_POSTFIX);
print_verilog_full_testbench(module_manager,
bitstream_manager, fabric_bitstream,
bitstream_manager, fabric_bitstream, blwl_sr_banks,
circuit_lib,
config_protocol,
fabric_global_port_info,

View File

@ -36,7 +36,7 @@ namespace openfpga {
void fpga_fabric_verilog(ModuleManager& module_manager,
NetlistManager& netlist_manager,
const std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const CircuitLibrary& circuit_lib,
const MuxLibrary& mux_lib,
const DecoderLibrary& decoder_lib,
@ -48,6 +48,7 @@ void fpga_fabric_verilog(ModuleManager& module_manager,
int fpga_verilog_full_testbench(const ModuleManager& module_manager,
const BitstreamManager& bitstream_manager,
const FabricBitstream& fabric_bitstream,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const AtomContext& atom_ctx,
const PlacementContext& place_ctx,
const PinConstraints& pin_constraints,

View File

@ -34,7 +34,7 @@ namespace openfpga {
********************************************************************/
void print_verilog_submodule_shift_register_banks(const ModuleManager& module_manager,
NetlistManager& netlist_manager,
const std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const std::string& submodule_dir,
const FabricVerilogOption& options) {
@ -54,17 +54,26 @@ void print_verilog_submodule_shift_register_banks(const ModuleManager& module_ma
print_verilog_file_header(fp, "Shift register banks used in FPGA");
/* Create the memory circuits for the multiplexer */
for (const auto& sr_bank : blwl_sr_banks) {
for (const ModuleId& sr_module : sr_bank.shift_register_bank_unique_modules()) {
VTR_ASSERT(true == module_manager.valid_module_id(sr_module));
/* Write the module content in Verilog format */
write_verilog_module_to_file(fp, module_manager, sr_module,
options.explicit_port_mapping(),
options.default_net_type());
for (const ModuleId& sr_module : blwl_sr_banks.bl_bank_unique_modules()) {
VTR_ASSERT(true == module_manager.valid_module_id(sr_module));
/* Write the module content in Verilog format */
write_verilog_module_to_file(fp, module_manager, sr_module,
options.explicit_port_mapping(),
options.default_net_type());
/* Add an empty line as a splitter */
fp << std::endl;
}
/* Add an empty line as a splitter */
fp << std::endl;
}
for (const ModuleId& sr_module : blwl_sr_banks.wl_bank_unique_modules()) {
VTR_ASSERT(true == module_manager.valid_module_id(sr_module));
/* Write the module content in Verilog format */
write_verilog_module_to_file(fp, module_manager, sr_module,
options.explicit_port_mapping(),
options.default_net_type());
/* Add an empty line as a splitter */
fp << std::endl;
}
/* Close the file stream */

View File

@ -20,7 +20,7 @@ namespace openfpga {
void print_verilog_submodule_shift_register_banks(const ModuleManager& module_manager,
NetlistManager& netlist_manager,
const std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const std::string& submodule_dir,
const FabricVerilogOption& options);

View File

@ -34,7 +34,7 @@ namespace openfpga {
********************************************************************/
void print_verilog_submodule(ModuleManager& module_manager,
NetlistManager& netlist_manager,
const std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const MuxLibrary& mux_lib,
const DecoderLibrary& decoder_lib,
const CircuitLibrary& circuit_lib,

View File

@ -20,7 +20,7 @@ namespace openfpga {
void print_verilog_submodule(ModuleManager& module_manager,
NetlistManager& netlist_manager,
const std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const MuxLibrary& mux_lib,
const DecoderLibrary& decoder_lib,
const CircuitLibrary& circuit_lib,

View File

@ -1132,6 +1132,7 @@ int print_verilog_top_testbench_configuration_protocol_stimulus(std::fstream& fp
const bool& fast_configuration,
const bool& bit_value_to_skip,
const FabricBitstream& fabric_bitstream,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const float& prog_clock_period,
const float& timescale) {
/* Validate the file stream */
@ -1147,7 +1148,8 @@ int print_verilog_top_testbench_configuration_protocol_stimulus(std::fstream& fp
return print_verilog_top_testbench_configuration_protocol_ql_memory_bank_stimulus(fp,
config_protocol, sim_settings,
module_manager, top_module,
fast_configuration, bit_value_to_skip, fabric_bitstream,
fast_configuration, bit_value_to_skip,
fabric_bitstream, blwl_sr_banks,
prog_clock_period, timescale);
break;
case CONFIG_MEM_MEMORY_BANK:
@ -1738,7 +1740,8 @@ void print_verilog_full_testbench_bitstream(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module,
const BitstreamManager& bitstream_manager,
const FabricBitstream& fabric_bitstream) {
const FabricBitstream& fabric_bitstream,
const MemoryBankShiftRegisterBanks& blwl_sr_banks) {
/* Branch on the type of configuration protocol */
switch (config_protocol.type()) {
@ -1771,7 +1774,7 @@ void print_verilog_full_testbench_bitstream(std::fstream& fp,
fast_configuration,
bit_value_to_skip,
module_manager, top_module,
fabric_bitstream);
fabric_bitstream, blwl_sr_banks);
break;
case CONFIG_MEM_FRAME_BASED:
print_verilog_full_testbench_frame_decoder_bitstream(fp, bitstream_file,
@ -1893,6 +1896,7 @@ void print_verilog_top_testbench_check(std::fstream& fp,
int print_verilog_full_testbench(const ModuleManager& module_manager,
const BitstreamManager& bitstream_manager,
const FabricBitstream& fabric_bitstream,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const CircuitLibrary& circuit_lib,
const ConfigProtocol& config_protocol,
const FabricGlobalPortInfo& global_ports,
@ -1984,7 +1988,8 @@ int print_verilog_full_testbench(const ModuleManager& module_manager,
status = print_verilog_top_testbench_configuration_protocol_stimulus(fp,
config_protocol, simulation_parameters,
module_manager, top_module,
fast_configuration, bit_value_to_skip, fabric_bitstream,
fast_configuration, bit_value_to_skip,
fabric_bitstream, blwl_sr_banks,
prog_clock_period,
VERILOG_SIM_TIMESCALE);
@ -2057,7 +2062,7 @@ int print_verilog_full_testbench(const ModuleManager& module_manager,
apply_fast_configuration,
bit_value_to_skip,
module_manager, top_module,
bitstream_manager, fabric_bitstream);
bitstream_manager, fabric_bitstream, blwl_sr_banks);
/* Add signal initialization:
* Bypass writing codes to files due to the autogenerated codes are very large.

View File

@ -17,6 +17,7 @@
#include "fabric_global_port_info.h"
#include "vpr_netlist_annotation.h"
#include "simulation_setting.h"
#include "memory_bank_shift_register_banks.h"
#include "verilog_testbench_options.h"
/********************************************************************
@ -29,6 +30,7 @@ namespace openfpga {
int print_verilog_full_testbench(const ModuleManager& module_manager,
const BitstreamManager& bitstream_manager,
const FabricBitstream& fabric_bitstream,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const CircuitLibrary& circuit_lib,
const ConfigProtocol& config_protocol,
const FabricGlobalPortInfo& global_ports,

View File

@ -42,6 +42,8 @@ namespace openfpga {
constexpr char* TOP_TB_BL_SHIFT_REGISTER_CLOCK_PORT_NAME = "bl_sr_clock";
constexpr char* TOP_TB_WL_SHIFT_REGISTER_CLOCK_PORT_NAME = "wl_sr_clock";
constexpr char* TOP_TB_VIRTUAL_BL_SHIFT_REGISTER_CLOCK_PORT_NAME = "virtual_bl_sr_clock";
constexpr char* TOP_TB_VIRTUAL_WL_SHIFT_REGISTER_CLOCK_PORT_NAME = "virtual_wl_sr_clock";
constexpr char* TOP_TB_START_BL_SHIFT_REGISTER_PORT_NAME = "start_bl_sr";
constexpr char* TOP_TB_START_WL_SHIFT_REGISTER_PORT_NAME = "start_wl_sr";
constexpr char* TOP_TB_BL_SHIFT_REGISTER_COUNT_PORT_NAME = "bl_sr_count";
@ -90,9 +92,12 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp,
}
/* BL Shift register clock and registers */
BasicPort virtual_sr_clock_port(std::string(TOP_TB_VIRTUAL_BL_SHIFT_REGISTER_CLOCK_PORT_NAME), 1);
fp << generate_verilog_port(VERILOG_PORT_REG, virtual_sr_clock_port) << ";" << std::endl;
BasicPort sr_clock_port(std::string(TOP_TB_BL_SHIFT_REGISTER_CLOCK_PORT_NAME), 1);
fp << generate_verilog_port(VERILOG_PORT_REG, sr_clock_port) << ";" << std::endl;
/* Register to enable/disable bl/wl shift register clocks */
BasicPort start_bl_sr_port(TOP_TB_START_BL_SHIFT_REGISTER_PORT_NAME, 1);
fp << generate_verilog_port(VERILOG_PORT_REG, start_bl_sr_port) << ";" << std::endl;
@ -132,6 +137,8 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp,
}
/* WL Shift register clock and registers */
BasicPort virtual_sr_clock_port(std::string(TOP_TB_VIRTUAL_WL_SHIFT_REGISTER_CLOCK_PORT_NAME), 1);
fp << generate_verilog_port(VERILOG_PORT_REG, virtual_sr_clock_port) << ";" << std::endl;
BasicPort sr_clock_port(std::string(TOP_TB_WL_SHIFT_REGISTER_CLOCK_PORT_NAME), 1);
fp << generate_verilog_port(VERILOG_PORT_REG, sr_clock_port) << ";" << std::endl;
@ -243,6 +250,49 @@ void print_verilog_top_testbench_global_shift_register_clock_ports_stimuli(std::
}
}
/**
* @brief Generate the Verilog codes for a shift register virtual clock that controls BL/WL protocols
* The virtual clock is the reference clock, which include 1 additional clock cycle for reset
* when compared to the actual clock
*/
static
void print_verilog_full_testbench_ql_memory_bank_shift_register_virtual_clock_generator(std::fstream& fp,
const BasicPort& start_sr_port,
const BasicPort& sr_clock_port,
const float& sr_clock_period) {
/* Validate the file stream */
valid_file_stream(fp);
fp << "always";
fp << " @(posedge " << generate_verilog_port(VERILOG_PORT_CONKT, start_sr_port) << ")";
fp << " begin";
fp << std::endl;
fp << "\t";
fp << generate_verilog_port_constant_values(sr_clock_port, std::vector<size_t>(sr_clock_port.get_width(), 0), true);
fp << ";" << std::endl;
fp << "\t";
fp << "while (" << generate_verilog_port(VERILOG_PORT_CONKT, start_sr_port) << ") begin";
fp << std::endl;
fp << "\t\t";
fp << "#" << sr_clock_period << " ";
print_verilog_register_connection(fp, sr_clock_port, sr_clock_port, true);
fp << "\t";
fp << "end";
fp << std::endl;
fp << "\t";
fp << generate_verilog_port_constant_values(sr_clock_port, std::vector<size_t>(sr_clock_port.get_width(), 0), true);
fp << ";" << std::endl;
fp << "end";
fp << std::endl;
}
/**
* @brief Generate the Verilog codes for a shift register clocks that controls BL/WL protocols
*/
@ -259,6 +309,11 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(
fp << " begin";
fp << std::endl;
/* Skip the first the clock cycle which is reserved for reset */
fp << "\t";
fp << "#" << sr_clock_period * 2. << ";" << std::endl;
fp << std::endl;
fp << "\t";
fp << generate_verilog_port_constant_values(sr_clock_port, std::vector<size_t>(sr_clock_port.get_width(), 0), true);
fp << ";" << std::endl;
@ -326,6 +381,7 @@ int print_verilog_top_testbench_configuration_protocol_ql_memory_bank_stimulus(s
const bool& fast_configuration,
const bool& bit_value_to_skip,
const FabricBitstream& fabric_bitstream,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const float& prog_clock_period,
const float& timescale) {
ModulePortId en_port_id = module_manager.find_module_port(top_module,
@ -342,20 +398,26 @@ int print_verilog_top_testbench_configuration_protocol_ql_memory_bank_stimulus(s
/* Stimulus only for shift-register-based BL/WL protocols */
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME) + std::string(TOP_TB_CLOCK_REG_POSTFIX), 1);
BasicPort virtual_bl_sr_clock_port(TOP_TB_VIRTUAL_BL_SHIFT_REGISTER_CLOCK_PORT_NAME, 1);
BasicPort virtual_wl_sr_clock_port(TOP_TB_VIRTUAL_WL_SHIFT_REGISTER_CLOCK_PORT_NAME, 1);
BasicPort bl_sr_clock_port(TOP_TB_BL_SHIFT_REGISTER_CLOCK_PORT_NAME, 1);
BasicPort wl_sr_clock_port(TOP_TB_WL_SHIFT_REGISTER_CLOCK_PORT_NAME, 1);
BasicPort start_bl_sr_port(TOP_TB_START_BL_SHIFT_REGISTER_PORT_NAME, 1);
BasicPort start_wl_sr_port(TOP_TB_START_WL_SHIFT_REGISTER_PORT_NAME, 1);
/* Reorganize the fabric bitstream by the same address across regions */
if (CONFIG_MEM_QL_MEMORY_BANK == config_protocol.type()) {
if ( (CONFIG_MEM_QL_MEMORY_BANK == config_protocol.type())
&& (BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type())
&& (BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type()) ) {
MemoryBankShiftRegisterFabricBitstream fabric_bits_by_addr = build_memory_bank_shift_register_fabric_bitstream(fabric_bitstream,
blwl_sr_banks,
fast_configuration,
bit_value_to_skip);
/* Compute the auto-tuned clock period first, this is the lower bound of the shift register clock periods:
* - the BL/WL shift register clock only works in the second half of the programming clock period
* - add 2 idle clocks to avoid racing between programming clock and shift register clocks at edge
* - consider two additional clocks to avoid racing between programming clock and shift register clocks at edge
* TODO: To figure out what is the min. slack required here. See something strange in HDL simulation
*/
float bl_sr_clock_period = 0.25 * prog_clock_period / (fabric_bits_by_addr.bl_word_size() + 2) / timescale;
float wl_sr_clock_period = 0.25 * prog_clock_period / (fabric_bits_by_addr.wl_word_size() + 2) / timescale;
@ -385,11 +447,16 @@ int print_verilog_top_testbench_configuration_protocol_ql_memory_bank_stimulus(s
}
if (BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()) {
print_verilog_comment(fp, "----- BL Shift register virtual clock generator -----");
print_verilog_full_testbench_ql_memory_bank_shift_register_virtual_clock_generator(fp, start_bl_sr_port, virtual_bl_sr_clock_port, bl_sr_clock_period);
print_verilog_comment(fp, "----- BL Shift register clock generator -----");
print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(fp, start_bl_sr_port, bl_sr_clock_port, bl_sr_clock_period);
}
if (BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type()) {
print_verilog_comment(fp, "----- WL Shift register virtual clock generator -----");
print_verilog_full_testbench_ql_memory_bank_shift_register_virtual_clock_generator(fp, start_wl_sr_port, virtual_wl_sr_clock_port, wl_sr_clock_period);
print_verilog_comment(fp, "----- WL Shift register clock generator -----");
print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(fp, start_wl_sr_port, wl_sr_clock_port, wl_sr_clock_period);
}
@ -541,12 +608,14 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f
const bool& bit_value_to_skip,
const ModuleManager& module_manager,
const ModuleId& top_module,
const FabricBitstream& fabric_bitstream) {
const FabricBitstream& fabric_bitstream,
const MemoryBankShiftRegisterBanks& blwl_sr_banks) {
/* Validate the file stream */
valid_file_stream(fp);
/* Reorganize the fabric bitstream by the same address across regions */
MemoryBankShiftRegisterFabricBitstream fabric_bits_by_addr = build_memory_bank_shift_register_fabric_bitstream(fabric_bitstream,
blwl_sr_banks,
fast_configuration,
bit_value_to_skip);
@ -638,13 +707,36 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f
fp << ";";
fp << std::endl;
BasicPort bl_sr_clock_port(TOP_TB_BL_SHIFT_REGISTER_CLOCK_PORT_NAME, 1);
BasicPort wl_sr_clock_port(TOP_TB_WL_SHIFT_REGISTER_CLOCK_PORT_NAME, 1);
fp << "\t";
fp << generate_verilog_port_constant_values(bl_sr_clock_port, std::vector<size_t>(bl_sr_clock_port.get_width(), 0), true);
fp << ";";
fp << std::endl;
fp << "\t";
fp << generate_verilog_port_constant_values(wl_sr_clock_port, std::vector<size_t>(wl_sr_clock_port.get_width(), 0), true);
fp << ";";
fp << std::endl;
BasicPort virtual_bl_sr_clock_port(TOP_TB_VIRTUAL_BL_SHIFT_REGISTER_CLOCK_PORT_NAME, 1);
BasicPort virtual_wl_sr_clock_port(TOP_TB_VIRTUAL_WL_SHIFT_REGISTER_CLOCK_PORT_NAME, 1);
fp << "\t";
fp << generate_verilog_port_constant_values(virtual_bl_sr_clock_port, std::vector<size_t>(virtual_bl_sr_clock_port.get_width(), 0), true);
fp << ";";
fp << std::endl;
fp << "\t";
fp << generate_verilog_port_constant_values(virtual_wl_sr_clock_port, std::vector<size_t>(virtual_wl_sr_clock_port.get_width(), 0), true);
fp << ";";
fp << std::endl;
fp << "end";
fp << std::endl;
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME) + std::string(TOP_TB_CLOCK_REG_POSTFIX), 1);
BasicPort bl_sr_clock_port(TOP_TB_BL_SHIFT_REGISTER_CLOCK_PORT_NAME, 1);
BasicPort wl_sr_clock_port(TOP_TB_WL_SHIFT_REGISTER_CLOCK_PORT_NAME, 1);
print_verilog_comment(fp, "----- Begin bitstream loading during configuration phase -----");
fp << "always";
@ -705,7 +797,7 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f
/* Load data to BL shift register chains */
fp << "always";
fp << " @(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, bl_sr_clock_port) << ")";
fp << " @(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, virtual_bl_sr_clock_port) << ")";
fp << " begin";
fp << std::endl;
@ -721,6 +813,18 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f
fp << generate_verilog_port_constant_values(start_bl_sr_port, std::vector<size_t>(start_bl_sr_port.get_width(), 0), true);
fp << ";" << std::endl;
fp << "\t";
fp << "end" << std::endl;
fp << "\t";
fp << "if (";
fp << TOP_TB_BL_SHIFT_REGISTER_COUNT_PORT_NAME;
fp << " >= ";
fp << "`" << TOP_TB_BITSTREAM_BL_WORD_SIZE_VARIABLE;
fp << ") begin";
fp << std::endl;
fp << "\t\t";
fp << TOP_TB_BL_SHIFT_REGISTER_COUNT_PORT_NAME << " = 0;";
fp << std::endl;
@ -749,7 +853,7 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f
/* Load data to WL shift register chains */
fp << "always";
fp << " @(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, wl_sr_clock_port) << ")";
fp << " @(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, virtual_wl_sr_clock_port) << ")";
fp << " begin";
fp << std::endl;
@ -765,6 +869,17 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f
fp << generate_verilog_port_constant_values(start_wl_sr_port, std::vector<size_t>(start_wl_sr_port.get_width(), 0), true);
fp << ";" << std::endl;
fp << "\t";
fp << "end" << std::endl;
fp << "\t";
fp << "if (";
fp << TOP_TB_WL_SHIFT_REGISTER_COUNT_PORT_NAME;
fp << " >= ";
fp << "`" << TOP_TB_BITSTREAM_WL_WORD_SIZE_VARIABLE;
fp << ") begin";
fp << std::endl;
fp << "\t\t";
fp << TOP_TB_WL_SHIFT_REGISTER_COUNT_PORT_NAME << " = 0;";
fp << std::endl;
@ -940,7 +1055,8 @@ void print_verilog_full_testbench_ql_memory_bank_bitstream(std::fstream& fp,
const bool& bit_value_to_skip,
const ModuleManager& module_manager,
const ModuleId& top_module,
const FabricBitstream& fabric_bitstream) {
const FabricBitstream& fabric_bitstream,
const MemoryBankShiftRegisterBanks& blwl_sr_banks) {
if ( (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type())
&& (BLWL_PROTOCOL_DECODER == config_protocol.wl_protocol_type()) ) {
print_verilog_full_testbench_ql_memory_bank_decoder_bitstream(fp, bitstream_file,
@ -961,7 +1077,7 @@ void print_verilog_full_testbench_ql_memory_bank_bitstream(std::fstream& fp,
fast_configuration,
bit_value_to_skip,
module_manager, top_module,
fabric_bitstream);
fabric_bitstream, blwl_sr_banks);
}
}

View File

@ -17,6 +17,7 @@
#include "fabric_global_port_info.h"
#include "vpr_netlist_annotation.h"
#include "simulation_setting.h"
#include "memory_bank_shift_register_banks.h"
#include "verilog_testbench_options.h"
/********************************************************************
@ -53,6 +54,7 @@ int print_verilog_top_testbench_configuration_protocol_ql_memory_bank_stimulus(s
const bool& fast_configuration,
const bool& bit_value_to_skip,
const FabricBitstream& fabric_bitstream,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const float& prog_clock_period,
const float& timescale);
@ -67,7 +69,8 @@ void print_verilog_full_testbench_ql_memory_bank_bitstream(std::fstream& fp,
const bool& bit_value_to_skip,
const ModuleManager& module_manager,
const ModuleId& top_module,
const FabricBitstream& fabric_bitstream);
const FabricBitstream& fabric_bitstream,
const MemoryBankShiftRegisterBanks& blwl_sr_banks);
} /* end namespace openfpga */

View File

@ -12,6 +12,7 @@
#include "vtr_log.h"
/* Headers from openfpgautil library */
#include "openfpga_reserved_words.h"
#include "openfpga_decode.h"
#include "fabric_bitstream_utils.h"
@ -344,7 +345,7 @@ MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(cons
}
/********************************************************************
* Reshape a list of vectors by aligning all of them to the last element
* Reshape a list of vectors by aligning all of them to the first element
* For example:
* - Align vectors to the last element
*
@ -356,15 +357,16 @@ MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(cons
* - Fill void in each vector with desired bits (Here assume fill 'x'
* index ---------------------->
* vector 0: 000000001111101010
* vector 1: xxxx00000011010101
* vector 2: xx0010101111000110
* vector 1: 00000011010101xxxx
* vector 2: 0010101111000110xx
*
* - Rotate the array by 90 degree
* index ----------------------->
* vector 0: 0xx
* vector 1: 0xx
* vector 0: 000
* vector 1: 000
* vector 2: 001
* ...
* vector N: 010
* vector N: 0xx
*
*******************************************************************/
static
@ -397,9 +399,111 @@ std::vector<std::string> reshape_bitstream_vectors_to_first_element(const std::v
return rotated_vectors;
}
/** @brief Split each BL vector in a configuration region into multiple shift register banks
* For example
* Original vector: 1xxx010xxx1
* Resulting vector (2 register register banks):
* 1xxx0
* 10xxx1
*/
static
std::vector<std::string> redistribute_bl_vectors_to_shift_register_banks(const std::vector<std::string> bl_vectors,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const char& dont_care_bit) {
std::vector<std::string> multi_bank_bl_vec;
/* Resize the vector by counting the dimension */
/* Compute the start index of each region */
vtr::vector<ConfigRegionId, size_t> region_start_index;
region_start_index.resize(blwl_sr_banks.regions().size(), 0);
size_t total_num_banks = 0;
for (const auto& region : blwl_sr_banks.regions()) {
region_start_index[region] = total_num_banks;
total_num_banks += blwl_sr_banks.bl_banks(region).size();
}
multi_bank_bl_vec.resize(total_num_banks);
/* Resize each bank to be memory efficient */
size_t vec_start_index = 0;
for (const auto& region : blwl_sr_banks.regions()) {
for (const auto& bank : blwl_sr_banks.bl_banks(region)) {
size_t bank_size = blwl_sr_banks.bl_bank_size(region, bank);
multi_bank_bl_vec[vec_start_index].resize(bank_size, dont_care_bit);
vec_start_index++;
}
}
for (const std::string& region_bl_vec : bl_vectors) {
ConfigRegionId region = ConfigRegionId(&region_bl_vec - &bl_vectors[0]);
for (size_t ibit = 0; ibit < region_bl_vec.size(); ++ibit) {
/* Find the shift register bank id and the offset in data lines */
BasicPort bl_port(std::string(MEMORY_BL_PORT_NAME), ibit, ibit);
FabricBitLineBankId bank_id = blwl_sr_banks.find_bl_shift_register_bank_id(region, bl_port);
BasicPort sr_port = blwl_sr_banks.find_bl_shift_register_bank_data_port(region, bl_port);
VTR_ASSERT(1 == sr_port.get_width());
size_t vec_index = region_start_index[region] + size_t(bank_id);
multi_bank_bl_vec[vec_index][sr_port.get_lsb()] = region_bl_vec[ibit];
}
}
return multi_bank_bl_vec;
}
/** @brief Split each WL vector in a configuration region into multiple shift register banks
* For example
* Original vector: 1xxx010xxx1
* Resulting vector (2 register register banks):
* 1xxx0
* 10xxx1
*/
static
std::vector<std::string> redistribute_wl_vectors_to_shift_register_banks(const std::vector<std::string> wl_vectors,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const char& dont_care_bit) {
std::vector<std::string> multi_bank_wl_vec;
/* Resize the vector by counting the dimension */
/* Compute the start index of each region */
vtr::vector<ConfigRegionId, size_t> region_start_index;
region_start_index.resize(blwl_sr_banks.regions().size(), 0);
size_t total_num_banks = 0;
for (const auto& region : blwl_sr_banks.regions()) {
region_start_index[region] = total_num_banks;
total_num_banks += blwl_sr_banks.wl_banks(region).size();
}
multi_bank_wl_vec.resize(total_num_banks);
/* Resize each bank to be memory efficient */
size_t vec_start_index = 0;
for (const auto& region : blwl_sr_banks.regions()) {
for (const auto& bank : blwl_sr_banks.wl_banks(region)) {
size_t bank_size = blwl_sr_banks.wl_bank_size(region, bank);
multi_bank_wl_vec[vec_start_index].resize(bank_size, dont_care_bit);
vec_start_index++;
}
}
for (const std::string& region_wl_vec : wl_vectors) {
ConfigRegionId region = ConfigRegionId(&region_wl_vec - &wl_vectors[0]);
for (size_t ibit = 0; ibit < region_wl_vec.size(); ++ibit) {
/* Find the shift register bank id and the offset in data lines */
BasicPort wl_port(std::string(MEMORY_WL_PORT_NAME), ibit, ibit);
FabricWordLineBankId bank_id = blwl_sr_banks.find_wl_shift_register_bank_id(region, wl_port);
BasicPort sr_port = blwl_sr_banks.find_wl_shift_register_bank_data_port(region, wl_port);
VTR_ASSERT(1 == sr_port.get_width());
size_t vec_index = region_start_index[region] + size_t(bank_id);
multi_bank_wl_vec[vec_index][sr_port.get_lsb()] = region_wl_vec[ibit];
}
}
return multi_bank_wl_vec;
}
MemoryBankShiftRegisterFabricBitstream build_memory_bank_shift_register_fabric_bitstream(const FabricBitstream& fabric_bitstream,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const bool& fast_configuration,
//const std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
const bool& bit_value_to_skip,
const char& dont_care_bit) {
MemoryBankFlattenFabricBitstream raw_fabric_bits = build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, fast_configuration, bit_value_to_skip, dont_care_bit);
@ -411,7 +515,10 @@ MemoryBankShiftRegisterFabricBitstream build_memory_bank_shift_register_fabric_b
MemoryBankShiftRegisterFabricBitstreamWordId word_id = fabric_bits.create_word();
std::vector<std::string> reshaped_bl_vectors = reshape_bitstream_vectors_to_first_element(bl_vec, dont_care_bit);
/* Redistribute the BL vector to multiple banks */
std::vector<std::string> multi_bank_bl_vec = redistribute_bl_vectors_to_shift_register_banks(bl_vec, blwl_sr_banks, dont_care_bit);
std::vector<std::string> reshaped_bl_vectors = reshape_bitstream_vectors_to_first_element(multi_bank_bl_vec, dont_care_bit);
/* Reverse the vectors due to the shift register chain nature: first-in first-out */
std::reverse(reshaped_bl_vectors.begin(), reshaped_bl_vectors.end());
/* Add the BL word to final bitstream */
@ -419,7 +526,10 @@ MemoryBankShiftRegisterFabricBitstream build_memory_bank_shift_register_fabric_b
fabric_bits.add_bl_vectors(word_id, reshaped_bl_vec);
}
std::vector<std::string> reshaped_wl_vectors = reshape_bitstream_vectors_to_first_element(wl_vec, dont_care_bit);
/* Redistribute the WL vector to multiple banks */
std::vector<std::string> multi_bank_wl_vec = redistribute_wl_vectors_to_shift_register_banks(wl_vec, blwl_sr_banks, dont_care_bit);
std::vector<std::string> reshaped_wl_vectors = reshape_bitstream_vectors_to_first_element(multi_bank_wl_vec, dont_care_bit);
/* Reverse the vectors due to the shift register chain nature: first-in first-out */
std::reverse(reshaped_wl_vectors.begin(), reshaped_wl_vectors.end());
/* Add the BL word to final bitstream */

View File

@ -95,8 +95,8 @@ MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(cons
* @note the std::map may cause large memory footprint for large bitstream databases!
*******************************************************************/
MemoryBankShiftRegisterFabricBitstream build_memory_bank_shift_register_fabric_bitstream(const FabricBitstream& fabric_bitstream,
const MemoryBankShiftRegisterBanks& blwl_sr_banks,
const bool& fast_configuration,
//const std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
const bool& bit_value_to_skip,
const char& dont_care_bit = 'x');

View File

@ -0,0 +1,25 @@
<fabric_key>
<region id="0">
<bl_shift_register_banks>
<bank id="0" range="bl[0:16]"/>
<bank id="1" range="bl[17:25]"/>
<bank id="2" range="bl[26:38]"/>
</bl_shift_register_banks>
<wl_shift_register_banks>
<bank id="0" range="wl[0:36]"/>
</wl_shift_register_banks>
<key id="0" name="grid_io_bottom" value="0" alias="grid_io_bottom_1__0_" column="2" row="0"/>
<key id="1" name="grid_io_right" value="0" alias="grid_io_right_2__1_" column="4" row="2"/>
<key id="2" name="sb_1__1_" value="0" alias="sb_1__1_" column="3" row="3"/>
<key id="3" name="cbx_1__1_" value="0" alias="cbx_1__1_" column="2" row="3"/>
<key id="4" name="grid_io_top" value="0" alias="grid_io_top_1__2_" column="2" row="4"/>
<key id="5" name="sb_0__1_" value="0" alias="sb_0__1_" column="1" row="3"/>
<key id="6" name="sb_0__0_" value="0" alias="sb_0__0_" column="1" row="1"/>
<key id="7" name="cby_0__1_" value="0" alias="cby_0__1_" column="1" row="2"/>
<key id="8" name="grid_io_left" value="0" alias="grid_io_left_0__1_" column="0" row="2"/>
<key id="9" name="sb_1__0_" value="0" alias="sb_1__0_" column="3" row="1"/>
<key id="10" name="cbx_1__0_" value="0" alias="cbx_1__0_" column="2" row="1"/>
<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>
</fabric_key>

View File

@ -1,5 +1,11 @@
<fabric_key>
<region id="0">
<bl_shift_register_banks>
<bank id="0" range="bl[0:61]"/>
</bl_shift_register_banks>
<wl_shift_register_banks>
<bank id="0" range="wl[0:33]"/>
</wl_shift_register_banks>
<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"/>
<key id="2" name="grid_io_right" value="1" alias="grid_io_right_3__1_" column="6" row="2"/>
@ -21,6 +27,12 @@
<key id="18" name="cbx_1__1_" value="0" alias="cbx_1__1_" column="2" row="3"/>
</region>
<region id="1">
<bl_shift_register_banks>
<bank id="0" range="bl[0:59]"/>
</bl_shift_register_banks>
<wl_shift_register_banks>
<bank id="0" range="wl[0:24]"/>
</wl_shift_register_banks>
<key id="19" name="grid_io_right" value="0" alias="grid_io_right_3__2_" column="6" row="4"/>
<key id="20" name="sb_2__2_" value="0" alias="sb_2__2_" column="5" row="5"/>
<key id="21" name="cbx_1__2_" value="1" alias="cbx_2__2_" column="4" row="5"/>

View File

@ -0,0 +1,224 @@
<!-- Architecture annotation for OpenFPGA framework
This annotation supports the k6_N10_40nm.xml
- General purpose logic block
- K = 6, N = 10, I = 40
- Single mode
- Routing architecture
- L = 4, fc_in = 0.15, fc_out = 0.1
-->
<openfpga_architecture>
<technology_library>
<device_library>
<device_model name="logic" type="transistor">
<lib type="industry" corner="TOP_TT" ref="M" path="${OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.pm"/>
<design vdd="0.9" pn_ratio="2"/>
<pmos name="pch" chan_length="40e-9" min_width="140e-9" variation="logic_transistor_var"/>
<nmos name="nch" chan_length="40e-9" min_width="140e-9" variation="logic_transistor_var"/>
</device_model>
<device_model name="io" type="transistor">
<lib type="academia" ref="M" path="${OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.pm"/>
<design vdd="2.5" pn_ratio="3"/>
<pmos name="pch_25" chan_length="270e-9" min_width="320e-9" variation="io_transistor_var"/>
<nmos name="nch_25" chan_length="270e-9" min_width="320e-9" variation="io_transistor_var"/>
</device_model>
</device_library>
<variation_library>
<variation name="logic_transistor_var" abs_deviation="0.1" num_sigma="3"/>
<variation name="io_transistor_var" abs_deviation="0.1" num_sigma="3"/>
</variation_library>
</technology_library>
<circuit_library>
<circuit_model type="inv_buf" name="INVTX1" prefix="INVTX1" is_default="true">
<design_technology type="cmos" topology="inverter" size="1"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<delay_matrix type="rise" in_port="in" out_port="out">
10e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in" out_port="out">
10e-12
</delay_matrix>
</circuit_model>
<circuit_model type="inv_buf" name="buf4" prefix="buf4" is_default="false">
<design_technology type="cmos" topology="buffer" size="1" num_level="2" f_per_stage="4"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<delay_matrix type="rise" in_port="in" out_port="out">
10e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in" out_port="out">
10e-12
</delay_matrix>
</circuit_model>
<circuit_model type="inv_buf" name="tap_buf4" prefix="tap_buf4" is_default="false">
<design_technology type="cmos" topology="buffer" size="1" num_level="3" f_per_stage="4"/>
<device_technology device_model_name="logic"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<delay_matrix type="rise" in_port="in" out_port="out">
10e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in" out_port="out">
10e-12
</delay_matrix>
</circuit_model>
<circuit_model type="pass_gate" name="TGATE" prefix="TGATE" is_default="true">
<design_technology type="cmos" topology="transmission_gate" nmos_size="1" pmos_size="2"/>
<device_technology device_model_name="logic"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="in" size="1"/>
<port type="input" prefix="sel" size="1"/>
<port type="input" prefix="selb" size="1"/>
<port type="output" prefix="out" size="1"/>
<delay_matrix type="rise" in_port="in sel selb" out_port="out">
10e-12 5e-12 5e-12
</delay_matrix>
<delay_matrix type="fall" in_port="in sel selb" out_port="out">
10e-12 5e-12 5e-12
</delay_matrix>
</circuit_model>
<circuit_model type="chan_wire" name="chan_segment" prefix="track_seg" is_default="true">
<design_technology type="cmos"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<wire_param model_type="pi" R="101" C="22.5e-15" num_level="1"/> <!-- model_type could be T, res_val and cap_val DON'T CARE -->
</circuit_model>
<circuit_model type="wire" name="direct_interc" prefix="direct_interc" is_default="true">
<design_technology type="cmos"/>
<input_buffer exist="false"/>
<output_buffer exist="false"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<wire_param model_type="pi" R="0" C="0" num_level="1"/> <!-- model_type could be T, res_val cap_val should be defined -->
</circuit_model>
<circuit_model type="mux" name="mux_2level" prefix="mux_2level" dump_structural_verilog="true">
<design_technology type="cmos" structure="multi_level" num_level="2" add_const_input="true" const_input_val="1"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<pass_gate_logic circuit_model_name="TGATE"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<port type="sram" prefix="sram" size="1"/>
</circuit_model>
<circuit_model type="mux" name="mux_2level_tapbuf" prefix="mux_2level_tapbuf" dump_structural_verilog="true">
<design_technology type="cmos" structure="multi_level" num_level="2" add_const_input="true" const_input_val="1"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="tap_buf4"/>
<pass_gate_logic circuit_model_name="TGATE"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<port type="sram" prefix="sram" size="1"/>
</circuit_model>
<circuit_model type="mux" name="mux_1level_tapbuf" prefix="mux_1level_tapbuf" is_default="true" dump_structural_verilog="true">
<design_technology type="cmos" structure="one_level" add_const_input="true" const_input_val="1"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="tap_buf4"/>
<pass_gate_logic circuit_model_name="TGATE"/>
<port type="input" prefix="in" size="1"/>
<port type="output" prefix="out" size="1"/>
<port type="sram" prefix="sram" size="1"/>
</circuit_model>
<!--DFF subckt ports should be defined as <D> <Q> <CLK> <RESET> <SET> -->
<circuit_model type="ff" name="DFFSRQ" prefix="DFFSRQ" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/spice/dff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/dff.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<port type="input" prefix="D" lib_name="D" size="1"/>
<port type="input" prefix="set" lib_name="SET" size="1" is_global="true" default_val="0" is_set="true"/>
<port type="input" prefix="reset" lib_name="RST" size="1" is_global="true" default_val="0" is_reset="true"/>
<port type="output" prefix="Q" lib_name="Q" size="1"/>
<port type="clock" prefix="clk" lib_name="CK" size="1" is_global="true" default_val="0" />
</circuit_model>
<circuit_model type="lut" name="lut4" prefix="lut4" dump_structural_verilog="true">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<lut_input_inverter exist="true" circuit_model_name="INVTX1"/>
<lut_input_buffer exist="true" circuit_model_name="buf4"/>
<pass_gate_logic circuit_model_name="TGATE"/>
<port type="input" prefix="in" size="4"/>
<port type="output" prefix="out" size="1"/>
<port type="sram" prefix="sram" size="16"/>
</circuit_model>
<!--Scan-chain DFF subckt ports should be defined as <D> <Q> <Qb> <CLK> <RESET> <SET> -->
<circuit_model type="sram" name="SRAM" prefix="SRAM" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/spice/sram.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/sram.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<port type="bl" prefix="bl" lib_name="D" size="1"/>
<port type="wl" prefix="wl" lib_name="WE" size="1"/>
<port type="output" prefix="out" lib_name="Q" size="1"/>
<port type="output" prefix="outb" lib_name="QN" size="1"/>
</circuit_model>
<circuit_model type="iopad" name="GPIO" prefix="GPIO" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/spice/gpio.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/gpio.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<port type="inout" prefix="PAD" size="1" is_global="true" is_io="true" is_data_io="true"/>
<port type="sram" prefix="DIR" size="1" mode_select="true" circuit_model_name="SRAM" default_val="1"/>
<port type="input" prefix="outpad" lib_name="A" size="1"/>
<port type="output" prefix="inpad" lib_name="Y" size="1"/>
</circuit_model>
<!-- The following flip-flop is used to build the shift register chains for configuring memory banks -->
<circuit_model type="ccff" name="BL_DFFRQ" prefix="BL_DFFRQ" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/spice/dff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/dff.v" is_default="true">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<port type="input" prefix="srReset" lib_name="RST" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<port type="input" prefix="D" lib_name="SIN" size="1"/>
<port type="output" prefix="Q" lib_name="SOUT" size="1"/>
<port type="bl" prefix="BL" lib_name="BL" size="1"/>
<port type="clock" prefix="bl_sr_clk" lib_name="CK" size="1" is_global="true" default_val="0" is_prog="true" is_shift_register="true"/>
</circuit_model>
<!-- The following flip-flop is used to build the shift register chains for configuring memory banks -->
<circuit_model type="ccff" name="WL_DFFRQ" prefix="WL_DFFRQ" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/spice/dff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/dff.v">
<design_technology type="cmos"/>
<input_buffer exist="true" circuit_model_name="INVTX1"/>
<output_buffer exist="true" circuit_model_name="INVTX1"/>
<port type="input" prefix="srReset" lib_name="RST" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
<port type="input" prefix="D" lib_name="SIN" size="1"/>
<port type="output" prefix="Q" lib_name="SOUT" size="1"/>
<port type="wl" prefix="wl" lib_name="WLW" size="1"/>
<port type="clock" prefix="wl_en" lib_name="WEN" size="1" is_global="true" default_val="0" is_prog="true"/>
<port type="clock" prefix="wl_sr_clk" lib_name="CK" size="1" is_global="true" default_val="0" is_prog="true" is_shift_register="true"/>
</circuit_model>
</circuit_library>
<configuration_protocol>
<organization type="ql_memory_bank" circuit_model_name="SRAM">
<bl protocol="shift_register" circuit_model_name="BL_DFFRQ" num_banks="2"/>
<wl protocol="shift_register" circuit_model_name="WL_DFFRQ" num_banks="1"/>
</organization>
</configuration_protocol>
<connection_block>
<switch name="ipin_cblock" circuit_model_name="mux_2level_tapbuf"/>
</connection_block>
<switch_block>
<switch name="0" circuit_model_name="mux_2level_tapbuf"/>
</switch_block>
<routing_segment>
<segment name="L4" circuit_model_name="chan_segment"/>
</routing_segment>
<pb_type_annotations>
<!-- physical pb_type binding in complex block IO -->
<pb_type name="io" physical_mode_name="physical" idle_mode_name="inpad"/>
<pb_type name="io[physical].iopad" circuit_model_name="GPIO" mode_bits="1"/>
<pb_type name="io[inpad].inpad" physical_pb_type_name="io[physical].iopad" mode_bits="1"/>
<pb_type name="io[outpad].outpad" physical_pb_type_name="io[physical].iopad" mode_bits="0"/>
<!-- End physical pb_type binding in complex block IO -->
<!-- physical pb_type binding in complex block CLB -->
<!-- physical mode will be the default mode if not specified -->
<pb_type name="clb">
<!-- Binding interconnect to circuit models as their physical implementation, if not defined, we use the default model -->
<interconnect name="crossbar" circuit_model_name="mux_2level"/>
</pb_type>
<pb_type name="clb.fle[n1_lut4].ble4.lut4" circuit_model_name="lut4"/>
<pb_type name="clb.fle[n1_lut4].ble4.ff" circuit_model_name="DFFSRQ"/>
<!-- End physical pb_type binding in complex block IO -->
</pb_type_annotations>
</openfpga_architecture>

View File

@ -61,6 +61,7 @@ run-task basic_tests/full_testbench/ql_memory_bank_flatten --debug --show_thread
run-task basic_tests/full_testbench/ql_memory_bank_flatten_use_wlr --debug --show_thread_logs
run-task basic_tests/full_testbench/ql_memory_bank_shift_register --debug --show_thread_logs
run-task basic_tests/full_testbench/ql_memory_bank_shift_register_use_wlr --debug --show_thread_logs
run-task basic_tests/full_testbench/ql_memory_bank_shift_register_multi_chain --debug --show_thread_logs
echo -e "Testing testbenches without self checking features";
run-task basic_tests/full_testbench/full_testbench_without_self_checking --debug --show_thread_logs
@ -84,7 +85,8 @@ run-task basic_tests/custom_fabric_netlist_location --debug --show_thread_logs
echo -e "Testing user-defined simulation settings: clock frequency and number of cycles";
run-task basic_tests/fixed_simulation_settings/fixed_operating_clock_freq --debug --show_thread_logs
run-task basic_tests/fixed_simulation_settings/fixed_shift_register_clock_freq --debug --show_thread_logs
# TODO: This feature is temporarily out of test due to the emergency in delivering netlists for multi-chain shift-register memory bank
#run-task basic_tests/fixed_simulation_settings/fixed_shift_register_clock_freq --debug --show_thread_logs
echo -e "Testing Secured FPGA fabrics";
run-task basic_tests/fabric_key/generate_vanilla_key --debug --show_thread_logs
@ -96,7 +98,9 @@ run-task basic_tests/fabric_key/load_external_key_cc_fpga --debug --show_thread_
run-task basic_tests/fabric_key/load_external_key_multi_region_cc_fpga --debug --show_thread_logs
run-task basic_tests/fabric_key/load_external_key_qlbank_fpga --debug --show_thread_logs
run-task basic_tests/fabric_key/load_external_key_multi_region_qlbank_fpga --debug --show_thread_logs
run-task basic_tests/fabric_key/load_external_key_multi_region_qlbanksr_fpga --debug --show_thread_logs
run-task basic_tests/fabric_key/load_external_key_qlbanksr_multi_chain_fpga --debug --show_thread_logs
# TODO: This feature is temporarily out of test due to the emergency in delivering netlists for multi-chain shift-register memory bank
#run-task basic_tests/fabric_key/load_external_key_multi_region_qlbanksr_fpga --debug --show_thread_logs
echo -e "Testing K4 series FPGA";
echo -e "Testing K4N4 with facturable LUTs";

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_qlbanksr_multi_chain_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_shift_register_sim_openfpga.xml
external_fabric_key_file=${PATH:OPENFPGA_PATH}/openfpga_flow/fabric_keys/k4_N4_1x1_qlbanksr_multi_chain_sample_key.xml
openfpga_vpr_device_layout=auto
[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=

View File

@ -0,0 +1,45 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# Configuration file for running experiments
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
# Each job execute fpga_flow script on combination of architecture & benchmark
# timeout_each_job is timeout for each job
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
[GENERAL]
run_engine=openfpga_shell
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
power_analysis = true
spice_output=false
verilog_output=true
timeout_each_job = 20*60
fpga_flow=yosys_vpr
[OpenFPGA_SHELL]
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/write_full_testbench_example_script.openfpga
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_multi_chain_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_shift_register_sim_openfpga.xml
openfpga_vpr_device_layout=
openfpga_fast_configuration=
[ARCHITECTURES]
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml
[BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/or2/or2.v
bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch/and2_latch.v
[SYNTHESIS_PARAM]
bench0_top = and2
bench0_chan_width = 300
bench1_top = or2
bench1_chan_width = 300
bench2_top = and2_latch
bench2_chan_width = 300
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
end_flow_with_test=