diff --git a/docs/source/manual/arch_lang/config_protocol.rst b/docs/source/manual/arch_lang/config_protocol.rst index 1c124ddc0..26f9a304d 100644 --- a/docs/source/manual/arch_lang/config_protocol.rst +++ b/docs/source/manual/arch_lang/config_protocol.rst @@ -167,8 +167,8 @@ The BL and WL protocols can be customized through the XML syntax ``bl`` and ``wl - - + + @@ -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="" + + 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 diff --git a/docs/source/manual/file_formats/fabric_key.rst b/docs/source/manual/file_formats/fabric_key.rst index 185e1b40a..b3088aa6b 100644 --- a/docs/source/manual/file_formats/fabric_key.rst +++ b/docs/source/manual/file_formats/fabric_key.rst @@ -24,21 +24,54 @@ The following example shows how to define multiple configuration regions in the + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -200,3 +233,46 @@ This key contains only ``name``, ``value``, ``row`` and ``column``. + +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 ````. +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:: + + - ``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 ````. +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:: + + - ``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 + diff --git a/libopenfpga/libfabrickey/src/fabric_key.cpp b/libopenfpga/libfabrickey/src/fabric_key.cpp index d15c86e56..500dec09a 100644 --- a/libopenfpga/libfabrickey/src/fabric_key.cpp +++ b/libopenfpga/libfabrickey/src/fabric_key.cpp @@ -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 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 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& 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] ); +} diff --git a/libopenfpga/libfabrickey/src/fabric_key.h b/libopenfpga/libfabrickey/src/fabric_key.h index 6e9025f9e..45569f269 100644 --- a/libopenfpga/libfabrickey/src/fabric_key.h +++ b/libopenfpga/libfabrickey/src/fabric_key.h @@ -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::const_iterator fabric_key_iterator; typedef vtr::vector::const_iterator fabric_region_iterator; + typedef vtr::vector::const_iterator fabric_bit_line_bank_iterator; + typedef vtr::vector::const_iterator fabric_word_line_bank_iterator; /* Create range */ typedef vtr::Range fabric_region_range; typedef vtr::Range fabric_key_range; + typedef vtr::Range fabric_bit_line_bank_range; + typedef vtr::Range 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 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 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 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& 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& 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 region_ids_; @@ -129,6 +166,16 @@ class FabricKey { /* Optional alias for each key, with which a key can also be represented */ vtr::vector key_alias_; + + /* Unique ids for each BL shift register bank */ + vtr::vector> bl_bank_ids_; + /* Data ports to be connected to each BL shift register bank */ + vtr::vector>> bl_bank_data_ports_; + + /* Unique ids for each WL shift register bank */ + vtr::vector> wl_bank_ids_; + /* Data ports to be connected to each WL shift register bank */ + vtr::vector>> wl_bank_data_ports_; }; #endif diff --git a/libopenfpga/libfabrickey/src/fabric_key_fwd.h b/libopenfpga/libfabrickey/src/fabric_key_fwd.h index 249093fd2..7309daa23 100644 --- a/libopenfpga/libfabrickey/src/fabric_key_fwd.h +++ b/libopenfpga/libfabrickey/src/fabric_key_fwd.h @@ -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 FabricRegionId; typedef vtr::StrongId FabricKeyId; +typedef vtr::StrongId FabricBitLineBankId; +typedef vtr::StrongId FabricWordLineBankId; /* Short declaration of class */ class FabricKey; diff --git a/libopenfpga/libfabrickey/src/read_xml_fabric_key.cpp b/libopenfpga/libfabrickey/src/read_xml_fabric_key.cpp index 1c42b07bb..15fc61fe1 100644 --- a/libopenfpga/libfabrickey/src/read_xml_fabric_key.cpp +++ b/libopenfpga/libfabrickey/src/read_xml_fabric_key.cpp @@ -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 under 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 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 under 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 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 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); } /******************************************************************** diff --git a/libopenfpga/libfabrickey/src/write_xml_fabric_key.cpp b/libopenfpga/libfabrickey/src/write_xml_fabric_key.cpp index aa38c8140..ffd64ea54 100644 --- a/libopenfpga/libfabrickey/src/write_xml_fabric_key.cpp +++ b/libopenfpga/libfabrickey/src/write_xml_fabric_key.cpp @@ -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 << "" << "\n"; + + for (const auto& bank : fabric_key.bl_banks(region)) { + openfpga::write_tab_to_file(fp, 3); + fp << "" << "\n"; + } + + openfpga::write_tab_to_file(fp, 2); + fp << "" << "\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 << "" << "\n"; + + for (const auto& bank : fabric_key.wl_banks(region)) { + openfpga::write_tab_to_file(fp, 3); + fp << "" << "\n"; + } + + openfpga::write_tab_to_file(fp, 2); + fp << "" << "\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 << "\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); diff --git a/openfpga/src/base/openfpga_bitstream.cpp b/openfpga/src/base/openfpga_bitstream.cpp index ea390ae08..9dff1c7a8 100644 --- a/openfpga/src/base/openfpga_bitstream.cpp +++ b/openfpga/src/base/openfpga_bitstream.cpp @@ -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), diff --git a/openfpga/src/base/openfpga_build_fabric.cpp b/openfpga/src/base/openfpga_build_fabric.cpp index 211048eb3..4e576ef6c 100644 --- a/openfpga/src/base/openfpga_build_fabric.cpp +++ b/openfpga/src/base/openfpga_build_fabric.cpp @@ -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) { diff --git a/openfpga/src/base/openfpga_context.h b/openfpga/src/base/openfpga_context.h index dbb611fe6..f4d356550 100644 --- a/openfpga/src/base/openfpga_context.h +++ b/openfpga/src/base/openfpga_context.h @@ -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& 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& 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 blwl_sr_banks_; + openfpga::MemoryBankShiftRegisterBanks blwl_sr_banks_; /* Fabric module graph */ openfpga::ModuleManager module_graph_; diff --git a/openfpga/src/base/openfpga_verilog.cpp b/openfpga/src/base/openfpga_verilog.cpp index 2f3dd892f..4d4a615e7 100644 --- a/openfpga/src/base/openfpga_verilog.cpp +++ b/openfpga/src/base/openfpga_verilog.cpp @@ -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, diff --git a/openfpga/src/fabric/build_device_module.cpp b/openfpga/src/fabric/build_device_module.cpp index 3541616fc..53ae7f3fc 100644 --- a/openfpga/src/fabric/build_device_module.cpp +++ b/openfpga/src/fabric/build_device_module.cpp @@ -31,7 +31,7 @@ namespace openfpga { *******************************************************************/ int build_device_module_graph(ModuleManager& module_manager, DecoderLibrary& decoder_lib, - std::array& blwl_sr_banks, + MemoryBankShiftRegisterBanks& blwl_sr_banks, const OpenfpgaContext& openfpga_ctx, const DeviceContext& vpr_device_ctx, const bool& frame_view, diff --git a/openfpga/src/fabric/build_device_module.h b/openfpga/src/fabric/build_device_module.h index 1cde17ba7..1c21fd069 100644 --- a/openfpga/src/fabric/build_device_module.h +++ b/openfpga/src/fabric/build_device_module.h @@ -17,7 +17,7 @@ namespace openfpga { int build_device_module_graph(ModuleManager& module_manager, DecoderLibrary& decoder_lib, - std::array& blwl_sr_banks, + MemoryBankShiftRegisterBanks& blwl_sr_banks, const OpenfpgaContext& openfpga_ctx, const DeviceContext& vpr_device_ctx, const bool& frame_view, diff --git a/openfpga/src/fabric/build_top_module.cpp b/openfpga/src/fabric/build_top_module.cpp index c5b3aee45..2aad3f1f4 100644 --- a/openfpga/src/fabric/build_top_module.cpp +++ b/openfpga/src/fabric/build_top_module.cpp @@ -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 add_top_module_connection_block_instances(ModuleManager& mod *******************************************************************/ int build_top_module(ModuleManager& module_manager, DecoderLibrary& decoder_lib, - std::array& 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(blwl_sr_banks), top_module_num_config_bits); } diff --git a/openfpga/src/fabric/build_top_module.h b/openfpga/src/fabric/build_top_module.h index 3ddaea09a..c1b3a6f93 100644 --- a/openfpga/src/fabric/build_top_module.h +++ b/openfpga/src/fabric/build_top_module.h @@ -30,7 +30,7 @@ namespace openfpga { int build_top_module(ModuleManager& module_manager, DecoderLibrary& decoder_lib, - std::array& blwl_sr_banks, + MemoryBankShiftRegisterBanks& blwl_sr_banks, const CircuitLibrary& circuit_lib, const VprDeviceAnnotation& vpr_device_annotation, const DeviceGrid& grids, diff --git a/openfpga/src/fabric/build_top_module_memory.cpp b/openfpga/src/fabric/build_top_module_memory.cpp index e48167970..aee05c61c 100644 --- a/openfpga/src/fabric/build_top_module_memory.cpp +++ b/openfpga/src/fabric/build_top_module_memory.cpp @@ -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 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& 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& blwl_sr_banks, + MemoryBankShiftRegisterBanks& blwl_sr_banks, const ModuleId& parent_module, const CircuitLibrary& circuit_lib, const ConfigProtocol& config_protocol, diff --git a/openfpga/src/fabric/build_top_module_memory.h b/openfpga/src/fabric/build_top_module_memory.h index 4819a56f6..244f6bfee 100644 --- a/openfpga/src/fabric/build_top_module_memory.h +++ b/openfpga/src/fabric/build_top_module_memory.h @@ -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& blwl_sr_banks, + MemoryBankShiftRegisterBanks& blwl_sr_banks, const ModuleId& parent_module, const CircuitLibrary& circuit_lib, const ConfigProtocol& config_protocol, diff --git a/openfpga/src/fabric/build_top_module_memory_bank.cpp b/openfpga/src/fabric/build_top_module_memory_bank.cpp index 18accc9bb..5ed22c70c 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.cpp +++ b/openfpga/src/fabric/build_top_module_memory_bank.cpp @@ -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 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 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 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 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& 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 */ diff --git a/openfpga/src/fabric/build_top_module_memory_bank.h b/openfpga/src/fabric/build_top_module_memory_bank.h index d3a3d2f77..3d76ec3f4 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.h +++ b/openfpga/src/fabric/build_top_module_memory_bank.h @@ -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& 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 */ diff --git a/openfpga/src/fabric/fabric_key_writer.cpp b/openfpga/src/fabric/fabric_key_writer.cpp index 38cb599db..7ac8f90ea 100644 --- a/openfpga/src/fabric/fabric_key_writer.cpp +++ b/openfpga/src/fabric/fabric_key_writer.cpp @@ -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 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()); diff --git a/openfpga/src/fabric/fabric_key_writer.h b/openfpga/src/fabric/fabric_key_writer.h index bdb860354..d80a7180f 100644 --- a/openfpga/src/fabric/fabric_key_writer.h +++ b/openfpga/src/fabric/fabric_key_writer.h @@ -7,6 +7,7 @@ #include #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 */ diff --git a/openfpga/src/fabric/memory_bank_shift_register_banks.cpp b/openfpga/src/fabric/memory_bank_shift_register_banks.cpp index 9dcd98cf3..39eaa8ad3 100644 --- a/openfpga/src/fabric/memory_bank_shift_register_banks.cpp +++ b/openfpga/src/fabric/memory_bank_shift_register_banks.cpp @@ -1,114 +1,495 @@ #include #include "vtr_assert.h" +#include "openfpga_reserved_words.h" #include "memory_bank_shift_register_banks.h" /* begin namespace openfpga */ namespace openfpga { -std::vector MemoryBankShiftRegisterBanks::shift_register_bank_unique_modules() const { - std::vector 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 MemoryBankShiftRegisterBanks::bl_bank_unique_sizes() const { + std::vector unique_sizes; + for (const auto& region : bl_bank_data_ports_) { + for (const auto& bank : region) { + ConfigRegionId region_id = ConfigRegionId(®ion - &bl_bank_data_ports_[ConfigRegionId(0)]); + FabricBitLineBankId bank_id = FabricBitLineBankId(&bank - ®ion[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 MemoryBankShiftRegisterBanks::shift_register_bank_modules(const ConfigRegionId& region) const { - std::vector 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 MemoryBankShiftRegisterBanks::shift_register_bank_instances(const ConfigRegionId& region) const { - std::vector 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 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(); -} - -std::vector 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(); + return unique_sizes; } -std::vector 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 MemoryBankShiftRegisterBanks::bl_bank_unique_modules() const { + std::vector 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(); + 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 MemoryBankShiftRegisterBanks::wl_bank_unique_sizes() const { + std::vector unique_sizes; + for (const auto& region : wl_bank_data_ports_) { + for (const auto& bank : region) { + ConfigRegionId region_id = ConfigRegionId(®ion - &wl_bank_data_ports_[ConfigRegionId(0)]); + FabricWordLineBankId bank_id = FabricWordLineBankId(&bank - ®ion[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 MemoryBankShiftRegisterBanks::wl_bank_unique_modules() const { + std::vector 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 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 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 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(); /* Not found, return an empty list */ + } + return result->second; +} + +std::vector 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(); /* Not found, return an empty list */ + } + return result->second; +} + +std::vector 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 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 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(); /* 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 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(); /* Not found, return an empty list */ + } + return result->second; +} + +std::vector 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 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(®ion - &bl_bank_data_ports_[ConfigRegionId(0)]); + FabricBitLineBankId bank_id = FabricBitLineBankId(&bank - ®ion[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(®ion - &wl_bank_data_ports_[ConfigRegionId(0)]); + FabricWordLineBankId bank_id = FabricWordLineBankId(&bank - ®ion[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 */ diff --git a/openfpga/src/fabric/memory_bank_shift_register_banks.h b/openfpga/src/fabric/memory_bank_shift_register_banks.h index 6114f93d8..32df3444e 100644 --- a/openfpga/src/fabric/memory_bank_shift_register_banks.h +++ b/openfpga/src/fabric/memory_bank_shift_register_banks.h @@ -4,6 +4,7 @@ #include #include #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 shift_register_bank_unique_modules() const; + /* @brief Return a list of unique sizes of shift register banks for BL protocol */ + std::vector 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 shift_register_bank_modules(const ConfigRegionId& region) const; + /* @brief Return a list of unique modules of shift register banks for BL protocol */ + std::vector 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 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 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 shift_register_bank_sink_child_ids(const ConfigRegionId& region, - const ModuleId& sr_module, - const size_t& sr_instance) const; + std::vector 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 shift_register_bank_sink_pin_ids(const ConfigRegionId& region, - const ModuleId& sr_module, - const size_t& sr_instance) const; + std::vector 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 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 wl_bank_unique_sizes() const; + + /* @brief Return a list of unique modules of shift register banks for WL protocol */ + std::vector 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 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 shift_register_bank_source_blwl_ids(const ConfigRegionId& region, - const ModuleId& sr_module, - const size_t& sr_instance) const; + std::vector 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 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 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, std::vector>> sr_instance_sink_child_ids_; - vtr::vector, std::vector>> sr_instance_sink_child_pin_ids_; - vtr::vector, std::vector>> sr_instance_source_blwl_ids_; + vtr::vector config_region_ids_; + + /* General information about the BL shift register bank */ + vtr::vector> bl_bank_ids_; + vtr::vector>> bl_bank_data_ports_; + vtr::vector> bl_bank_modules_; + vtr::vector> bl_bank_instances_; + vtr::vector>>> bl_bank_sink_child_ids_; + vtr::vector>>> bl_bank_sink_child_pin_ids_; + + /* General information about the WL shift register bank */ + vtr::vector> wl_bank_ids_; + vtr::vector>> wl_bank_data_ports_; + vtr::vector> wl_bank_modules_; + vtr::vector> wl_bank_instances_; + vtr::vector>>> wl_bank_sink_child_ids_; + vtr::vector>>> 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> bl_ports_to_sr_bank_ids_; + mutable vtr::vector> bl_ports_to_sr_bank_ports_; + mutable vtr::vector> wl_ports_to_sr_bank_ids_; + mutable vtr::vector> 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 */ diff --git a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp index 51be3783a..9854398dd 100644 --- a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp @@ -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; diff --git a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.h b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.h index 6a30cf773..e63cea5c9 100644 --- a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.h +++ b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.h @@ -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, diff --git a/openfpga/src/fpga_verilog/verilog_api.cpp b/openfpga/src/fpga_verilog/verilog_api.cpp index 8ac019781..b3cc6e858 100644 --- a/openfpga/src/fpga_verilog/verilog_api.cpp +++ b/openfpga/src/fpga_verilog/verilog_api.cpp @@ -55,7 +55,7 @@ namespace openfpga { ********************************************************************/ void fpga_fabric_verilog(ModuleManager &module_manager, NetlistManager &netlist_manager, - const std::array& 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, diff --git a/openfpga/src/fpga_verilog/verilog_api.h b/openfpga/src/fpga_verilog/verilog_api.h index ef550c76d..6f83d3684 100644 --- a/openfpga/src/fpga_verilog/verilog_api.h +++ b/openfpga/src/fpga_verilog/verilog_api.h @@ -36,7 +36,7 @@ namespace openfpga { void fpga_fabric_verilog(ModuleManager& module_manager, NetlistManager& netlist_manager, - const std::array& 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, diff --git a/openfpga/src/fpga_verilog/verilog_shift_register_banks.cpp b/openfpga/src/fpga_verilog/verilog_shift_register_banks.cpp index 4d629a0cb..3b482a752 100644 --- a/openfpga/src/fpga_verilog/verilog_shift_register_banks.cpp +++ b/openfpga/src/fpga_verilog/verilog_shift_register_banks.cpp @@ -34,7 +34,7 @@ namespace openfpga { ********************************************************************/ void print_verilog_submodule_shift_register_banks(const ModuleManager& module_manager, NetlistManager& netlist_manager, - const std::array& 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 */ diff --git a/openfpga/src/fpga_verilog/verilog_shift_register_banks.h b/openfpga/src/fpga_verilog/verilog_shift_register_banks.h index 2de1bedee..433104a62 100644 --- a/openfpga/src/fpga_verilog/verilog_shift_register_banks.h +++ b/openfpga/src/fpga_verilog/verilog_shift_register_banks.h @@ -20,7 +20,7 @@ namespace openfpga { void print_verilog_submodule_shift_register_banks(const ModuleManager& module_manager, NetlistManager& netlist_manager, - const std::array& blwl_sr_banks, + const MemoryBankShiftRegisterBanks& blwl_sr_banks, const std::string& submodule_dir, const FabricVerilogOption& options); diff --git a/openfpga/src/fpga_verilog/verilog_submodule.cpp b/openfpga/src/fpga_verilog/verilog_submodule.cpp index 0cb2c97a4..b98dd6ecb 100644 --- a/openfpga/src/fpga_verilog/verilog_submodule.cpp +++ b/openfpga/src/fpga_verilog/verilog_submodule.cpp @@ -34,7 +34,7 @@ namespace openfpga { ********************************************************************/ void print_verilog_submodule(ModuleManager& module_manager, NetlistManager& netlist_manager, - const std::array& blwl_sr_banks, + const MemoryBankShiftRegisterBanks& blwl_sr_banks, const MuxLibrary& mux_lib, const DecoderLibrary& decoder_lib, const CircuitLibrary& circuit_lib, diff --git a/openfpga/src/fpga_verilog/verilog_submodule.h b/openfpga/src/fpga_verilog/verilog_submodule.h index d25ec4844..a5f88df16 100644 --- a/openfpga/src/fpga_verilog/verilog_submodule.h +++ b/openfpga/src/fpga_verilog/verilog_submodule.h @@ -20,7 +20,7 @@ namespace openfpga { void print_verilog_submodule(ModuleManager& module_manager, NetlistManager& netlist_manager, - const std::array& blwl_sr_banks, + const MemoryBankShiftRegisterBanks& blwl_sr_banks, const MuxLibrary& mux_lib, const DecoderLibrary& decoder_lib, const CircuitLibrary& circuit_lib, diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp index f45e84c9d..af50ce55d 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp @@ -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. diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.h b/openfpga/src/fpga_verilog/verilog_top_testbench.h index aff108d72..bbad08125 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.h +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.h @@ -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, diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp index c933cc939..7f6076c21 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp @@ -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(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(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(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(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(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(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(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(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(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); } } diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h index e3a4edc7e..6bcd50903 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h @@ -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 */ diff --git a/openfpga/src/utils/fabric_bitstream_utils.cpp b/openfpga/src/utils/fabric_bitstream_utils.cpp index a4f676b81..cd60d5879 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.cpp +++ b/openfpga/src/utils/fabric_bitstream_utils.cpp @@ -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 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 redistribute_bl_vectors_to_shift_register_banks(const std::vector bl_vectors, + const MemoryBankShiftRegisterBanks& blwl_sr_banks, + const char& dont_care_bit) { + std::vector multi_bank_bl_vec; + + /* Resize the vector by counting the dimension */ + /* Compute the start index of each region */ + vtr::vector 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(®ion_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 redistribute_wl_vectors_to_shift_register_banks(const std::vector wl_vectors, + const MemoryBankShiftRegisterBanks& blwl_sr_banks, + const char& dont_care_bit) { + std::vector multi_bank_wl_vec; + + /* Resize the vector by counting the dimension */ + /* Compute the start index of each region */ + vtr::vector 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(®ion_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& 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 reshaped_bl_vectors = reshape_bitstream_vectors_to_first_element(bl_vec, dont_care_bit); + /* Redistribute the BL vector to multiple banks */ + std::vector multi_bank_bl_vec = redistribute_bl_vectors_to_shift_register_banks(bl_vec, blwl_sr_banks, dont_care_bit); + + std::vector 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 reshaped_wl_vectors = reshape_bitstream_vectors_to_first_element(wl_vec, dont_care_bit); + /* Redistribute the WL vector to multiple banks */ + std::vector multi_bank_wl_vec = redistribute_wl_vectors_to_shift_register_banks(wl_vec, blwl_sr_banks, dont_care_bit); + + std::vector 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 */ diff --git a/openfpga/src/utils/fabric_bitstream_utils.h b/openfpga/src/utils/fabric_bitstream_utils.h index ff822802e..3cb1285bb 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.h +++ b/openfpga/src/utils/fabric_bitstream_utils.h @@ -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& blwl_sr_banks, const bool& bit_value_to_skip, const char& dont_care_bit = 'x'); diff --git a/openfpga_flow/fabric_keys/k4_N4_1x1_qlbanksr_multi_chain_sample_key.xml b/openfpga_flow/fabric_keys/k4_N4_1x1_qlbanksr_multi_chain_sample_key.xml new file mode 100644 index 000000000..0cb89d6fe --- /dev/null +++ b/openfpga_flow/fabric_keys/k4_N4_1x1_qlbanksr_multi_chain_sample_key.xml @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openfpga_flow/fabric_keys/k4_N4_2x2_multi_region_qlbanksr_sample_key.xml b/openfpga_flow/fabric_keys/k4_N4_2x2_multi_region_qlbanksr_sample_key.xml index 0b96c1930..9bf434709 100644 --- a/openfpga_flow/fabric_keys/k4_N4_2x2_multi_region_qlbanksr_sample_key.xml +++ b/openfpga_flow/fabric_keys/k4_N4_2x2_multi_region_qlbanksr_sample_key.xml @@ -1,5 +1,11 @@ + + + + + + @@ -21,6 +27,12 @@ + + + + + + diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_multi_chain_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_multi_chain_openfpga.xml new file mode 100644 index 000000000..0c4598128 --- /dev/null +++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_multi_chain_openfpga.xml @@ -0,0 +1,224 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + + + + + + 10e-12 5e-12 5e-12 + + + 10e-12 5e-12 5e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/openfpga_flow/regression_test_scripts/basic_reg_test.sh b/openfpga_flow/regression_test_scripts/basic_reg_test.sh index 5381920fe..76db04426 100755 --- a/openfpga_flow/regression_test_scripts/basic_reg_test.sh +++ b/openfpga_flow/regression_test_scripts/basic_reg_test.sh @@ -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"; diff --git a/openfpga_flow/tasks/basic_tests/fabric_key/load_external_key_qlbanksr_multi_chain_fpga/config/task.conf b/openfpga_flow/tasks/basic_tests/fabric_key/load_external_key_qlbanksr_multi_chain_fpga/config/task.conf new file mode 100644 index 000000000..651f0accf --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/fabric_key/load_external_key_qlbanksr_multi_chain_fpga/config/task.conf @@ -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= diff --git a/openfpga_flow/tasks/basic_tests/full_testbench/ql_memory_bank_shift_register_multi_chain/config/task.conf b/openfpga_flow/tasks/basic_tests/full_testbench/ql_memory_bank_shift_register_multi_chain/config/task.conf new file mode 100644 index 000000000..f9e2febb6 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/full_testbench/ql_memory_bank_shift_register_multi_chain/config/task.conf @@ -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=