Merge pull request #17 from RapidSilicon/phy_mem_bank

Support flatten BL/WL protocol for QuickLogic memory bank
This commit is contained in:
tangxifan 2021-09-27 11:57:00 -07:00 committed by GitHub
commit 05c6f1889e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
45 changed files with 2065 additions and 246 deletions

View File

@ -40,6 +40,7 @@ Template
- ``scan_chain`` requires a circuit model type of ``ccff`` - ``scan_chain`` requires a circuit model type of ``ccff``
- ``frame_based`` requires a circuit model type of ``sram`` - ``frame_based`` requires a circuit model type of ``sram``
- ``memory_bank`` requires a circuit model type of ``sram`` - ``memory_bank`` requires a circuit model type of ``sram``
- ``ql_memory_bank`` requires a circuit model type of ``sram``
- ``standalone`` requires a circuit model type of ``sram`` - ``standalone`` requires a circuit model type of ``sram``
.. option:: num_regions="<int>" .. option:: num_regions="<int>"
@ -148,23 +149,35 @@ Users can customized the number of memory banks to be used across the fabrics. B
.. warning:: Please do NOT add inverted Bit-Line and Word-Line inputs. It is not supported yet! .. warning:: Please do NOT add inverted Bit-Line and Word-Line inputs. It is not supported yet!
QuickLogic Memory bank Example QuickLogic Memory bank Example
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The following XML code describes a physical design friendly memory-bank circuitry to configure the core logic of FPGA, as illustrated in :numref:`fig_memory_bank`. The following XML code describes a physical design friendly memory-bank circuitry to configure the core logic of FPGA, as illustrated in :numref:`fig_memory_bank`.
It will use the circuit model defined in :numref:`fig_sram_blwl`. It will use the circuit model defined in :numref:`fig_sram_blwl`.
The BL and WL protocols can be customized through the XML syntax ``bl`` and ``wl``.
.. note:: If not specified, the BL/WL protocols will use decoders.
.. code-block:: xml .. code-block:: xml
<configuration_protocol> <configuration_protocol>
<organization type="ql_memory_bank" circuit_model_name="sram_blwl"/> <organization type="ql_memory_bank" circuit_model_name="sram_blwl">
<bl protocol="<string>"/>
<wl protocol="<string>"/>
</organization>
</configuration_protocol> </configuration_protocol>
.. option:: protocol="decoder|flatten"
- ``decoder``: BLs or WLs are controlled by decoders with address lines. For BLs, the decoder includes an enable signal as well as a data input signal. This is the default option if not specified.
- ``flatten``: BLs or WLs are directly available at the FPGA fabric. In this way, all the configurable memorys on the same WL can be written through the BL signals in one clock cycle
.. note:: Memory-bank decoders does require a memory cell to have .. note:: Memory-bank decoders does require a memory cell to have
- two outputs (one regular and another inverted) - two outputs (one regular and another inverted)
- a Bit-Line input to load the data - a Bit-Line input to load the data
- a Word-Line input to enable data write - a Word-Line input to enable data write
- (optional) a Word-Line read input to enabe data readback
.. warning:: Please do NOT add inverted Bit-Line and Word-Line inputs. It is not supported yet! .. warning:: Please do NOT add inverted Bit-Line and Word-Line inputs. It is not supported yet!

View File

@ -1170,7 +1170,7 @@ CircuitModelId CircuitLibrary::add_model(const enum e_circuit_model_type& type)
/* Pass-gate-related parameters */ /* Pass-gate-related parameters */
pass_gate_logic_model_names_.emplace_back(); pass_gate_logic_model_names_.emplace_back();
pass_gate_logic_model_ids_.emplace_back(); pass_gate_logic_model_ids_.emplace_back(CircuitModelId::INVALID());
/* Delay information */ /* Delay information */
delay_types_.emplace_back(); delay_types_.emplace_back();

View File

@ -1,4 +1,5 @@
#include "vtr_assert.h" #include "vtr_assert.h"
#include "vtr_log.h"
#include "config_protocol.h" #include "config_protocol.h"
@ -32,6 +33,30 @@ int ConfigProtocol::num_regions() const {
return num_regions_; return num_regions_;
} }
e_blwl_protocol_type ConfigProtocol::bl_protocol_type() const {
return bl_protocol_type_;
}
std::string ConfigProtocol::bl_memory_model_name() const {
return bl_memory_model_name_;
}
CircuitModelId ConfigProtocol::bl_memory_model() const {
return bl_memory_model_;
}
e_blwl_protocol_type ConfigProtocol::wl_protocol_type() const {
return wl_protocol_type_;
}
std::string ConfigProtocol::wl_memory_model_name() const {
return wl_memory_model_name_;
}
CircuitModelId ConfigProtocol::wl_memory_model() const {
return wl_memory_model_;
}
/************************************************************************ /************************************************************************
* Public Mutators * Public Mutators
***********************************************************************/ ***********************************************************************/
@ -50,3 +75,51 @@ void ConfigProtocol::set_memory_model(const CircuitModelId& memory_model) {
void ConfigProtocol::set_num_regions(const int& num_regions) { void ConfigProtocol::set_num_regions(const int& num_regions) {
num_regions_ = num_regions; num_regions_ = num_regions;
} }
void ConfigProtocol::set_bl_protocol_type(const e_blwl_protocol_type& type) {
if (CONFIG_MEM_QL_MEMORY_BANK != type_) {
VTR_LOG_ERROR("BL protocol type is only applicable for configuration protocol '%d'", CONFIG_PROTOCOL_TYPE_STRING[type_]);
return;
}
bl_protocol_type_ = type;
}
void ConfigProtocol::set_bl_memory_model_name(const std::string& memory_model_name) {
if (BLWL_PROTOCOL_SHIFT_REGISTER != bl_protocol_type_) {
VTR_LOG_ERROR("BL protocol memory model is only applicable when '%d' is defined", BLWL_PROTOCOL_TYPE_STRING[bl_protocol_type_]);
return;
}
bl_memory_model_name_ = memory_model_name;
}
void ConfigProtocol::set_bl_memory_model(const CircuitModelId& memory_model) {
if (BLWL_PROTOCOL_SHIFT_REGISTER != bl_protocol_type_) {
VTR_LOG_ERROR("BL protocol memory model is only applicable when '%d' is defined", BLWL_PROTOCOL_TYPE_STRING[bl_protocol_type_]);
return;
}
bl_memory_model_ = memory_model;
}
void ConfigProtocol::set_wl_protocol_type(const e_blwl_protocol_type& type) {
if (CONFIG_MEM_QL_MEMORY_BANK != type_) {
VTR_LOG_ERROR("WL protocol type is only applicable for configuration protocol '%d'", CONFIG_PROTOCOL_TYPE_STRING[type_]);
return;
}
wl_protocol_type_ = type;
}
void ConfigProtocol::set_wl_memory_model_name(const std::string& memory_model_name) {
if (BLWL_PROTOCOL_SHIFT_REGISTER != wl_protocol_type_) {
VTR_LOG_ERROR("WL protocol memory model is only applicable when '%d' is defined", BLWL_PROTOCOL_TYPE_STRING[wl_protocol_type_]);
return;
}
wl_memory_model_name_ = memory_model_name;
}
void ConfigProtocol::set_wl_memory_model(const CircuitModelId& memory_model) {
if (BLWL_PROTOCOL_SHIFT_REGISTER != wl_protocol_type_) {
VTR_LOG_ERROR("WL protocol memory model is only applicable when '%d' is defined", BLWL_PROTOCOL_TYPE_STRING[wl_protocol_type_]);
return;
}
wl_memory_model_ = memory_model;
}

View File

@ -5,6 +5,15 @@
#include "circuit_types.h" #include "circuit_types.h"
#include "circuit_library_fwd.h" #include "circuit_library_fwd.h"
/* Data type to define the protocol through which BL/WL can be manipulated */
enum e_blwl_protocol_type {
BLWL_PROTOCOL_FLATTEN,
BLWL_PROTOCOL_DECODER,
BLWL_PROTOCOL_SHIFT_REGISTER,
NUM_BLWL_PROTOCOL_TYPES
};
constexpr std::array<const char*, NUM_BLWL_PROTOCOL_TYPES> BLWL_PROTOCOL_TYPE_STRING = {{"flatten", "decoder", "shift_register"}};
/******************************************************************** /********************************************************************
* A data structure to store configuration protocol information * A data structure to store configuration protocol information
*******************************************************************/ *******************************************************************/
@ -16,11 +25,25 @@ class ConfigProtocol {
std::string memory_model_name() const; std::string memory_model_name() const;
CircuitModelId memory_model() const; CircuitModelId memory_model() const;
int num_regions() const; int num_regions() const;
e_blwl_protocol_type bl_protocol_type() const;
std::string bl_memory_model_name() const;
CircuitModelId bl_memory_model() const;
e_blwl_protocol_type wl_protocol_type() const;
std::string wl_memory_model_name() const;
CircuitModelId wl_memory_model() const;
public: /* Public Mutators */ public: /* Public Mutators */
void set_type(const e_config_protocol_type& type); void set_type(const e_config_protocol_type& type);
void set_memory_model_name(const std::string& memory_model_name); void set_memory_model_name(const std::string& memory_model_name);
void set_memory_model(const CircuitModelId& memory_model); void set_memory_model(const CircuitModelId& memory_model);
void set_num_regions(const int& num_regions); void set_num_regions(const int& num_regions);
void set_bl_protocol_type(const e_blwl_protocol_type& type);
void set_bl_memory_model_name(const std::string& memory_model_name);
void set_bl_memory_model(const CircuitModelId& memory_model);
void set_wl_protocol_type(const e_blwl_protocol_type& type);
void set_wl_memory_model_name(const std::string& memory_model_name);
void set_wl_memory_model(const CircuitModelId& memory_model);
private: /* Internal data */ private: /* Internal data */
/* The type of configuration protocol. /* The type of configuration protocol.
* In other words, it is about how to organize and access each configurable memory * In other words, it is about how to organize and access each configurable memory
@ -33,6 +56,19 @@ class ConfigProtocol {
/* Number of configurable regions */ /* Number of configurable regions */
int num_regions_; int num_regions_;
/* BL & WL protocol: This is only applicable to memory-bank configuration protocols
* - type: defines which protocol to be used. By default, we consider decoders
* - bl/wl_memory_model: defines the circuit model to be used when building shift register chains for BL/WL configuration.
* It must be a valid CCFF circuit model. This is only applicable when shift-register protocol is selected
* for BL or WL.
*/
e_blwl_protocol_type bl_protocol_type_ = BLWL_PROTOCOL_DECODER;
std::string bl_memory_model_name_;
CircuitModelId bl_memory_model_;
e_blwl_protocol_type wl_protocol_type_ = BLWL_PROTOCOL_DECODER;
std::string wl_memory_model_name_;
CircuitModelId wl_memory_model_;
}; };
#endif #endif

View File

@ -22,6 +22,29 @@ void link_config_protocol_to_circuit_library(openfpga::Arch& openfpga_arch) {
} }
openfpga_arch.config_protocol.set_memory_model(config_memory_model); openfpga_arch.config_protocol.set_memory_model(config_memory_model);
/* Optional: we need to bind the memory model for BL/WL protocols */
if (!openfpga_arch.config_protocol.bl_memory_model_name().empty()) {
CircuitModelId bl_memory_model = openfpga_arch.circuit_lib.model(openfpga_arch.config_protocol.bl_memory_model_name());
/* Error out if the circuit model id is invalid */
if (CircuitModelId::INVALID() == bl_memory_model) {
VTR_LOG("Invalid bl memory model name '%s' defined in <configuration_protocol>!",
openfpga_arch.config_protocol.bl_memory_model_name().c_str());
exit(1);
}
openfpga_arch.config_protocol.set_bl_memory_model(bl_memory_model);
}
if (!openfpga_arch.config_protocol.wl_memory_model_name().empty()) {
CircuitModelId wl_memory_model = openfpga_arch.circuit_lib.model(openfpga_arch.config_protocol.wl_memory_model_name());
/* Error out if the circuit model id is invalid */
if (CircuitModelId::INVALID() == wl_memory_model) {
VTR_LOG("Invalid wl memory model name '%s' defined in <configuration_protocol>!",
openfpga_arch.config_protocol.wl_memory_model_name().c_str());
exit(1);
}
openfpga_arch.config_protocol.set_wl_memory_model(wl_memory_model);
}
} }
/******************************************************************** /********************************************************************

View File

@ -33,6 +33,73 @@ e_config_protocol_type string_to_config_protocol_type(const std::string& type_st
return NUM_CONFIG_PROTOCOL_TYPES; return NUM_CONFIG_PROTOCOL_TYPES;
} }
/********************************************************************
* Convert string to the enumerate of BL/WL protocol type
*******************************************************************/
static
e_blwl_protocol_type string_to_blwl_protocol_type(const std::string& type_string) {
for (size_t itype = 0; itype < NUM_BLWL_PROTOCOL_TYPES; ++itype) {
if (std::string(BLWL_PROTOCOL_TYPE_STRING[itype]) == type_string) {
return static_cast<e_blwl_protocol_type>(itype);
}
}
return NUM_BLWL_PROTOCOL_TYPES;
}
/********************************************************************
* Parse XML codes of a <bl> to an object of configuration protocol
*******************************************************************/
static
void read_xml_bl_protocol(pugi::xml_node& xml_bl_protocol,
const pugiutil::loc_data& loc_data,
ConfigProtocol& config_protocol) {
/* Find the type of configuration protocol */
const char* type_attr = get_attribute(xml_bl_protocol, "protocol", loc_data).value();
/* Translate the type of design technology to enumerate */
e_blwl_protocol_type blwl_protocol_type = string_to_blwl_protocol_type(std::string(type_attr));
if (NUM_BLWL_PROTOCOL_TYPES == blwl_protocol_type) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_bl_protocol),
"Invalid 'protocol' attribute '%s'\n",
type_attr);
}
config_protocol.set_bl_protocol_type(blwl_protocol_type);
/* Find the memory model, only applicable to shift-registor protocol */
if (BLWL_PROTOCOL_SHIFT_REGISTER == blwl_protocol_type) {
config_protocol.set_bl_memory_model_name(get_attribute(xml_bl_protocol, "circuit_model_name", loc_data).as_string());
}
}
/********************************************************************
* Parse XML codes of a <wl> to an object of configuration protocol
*******************************************************************/
static
void read_xml_wl_protocol(pugi::xml_node& xml_wl_protocol,
const pugiutil::loc_data& loc_data,
ConfigProtocol& config_protocol) {
/* Find the type of configuration protocol */
const char* type_attr = get_attribute(xml_wl_protocol, "protocol", loc_data).value();
/* Translate the type of design technology to enumerate */
e_blwl_protocol_type blwl_protocol_type = string_to_blwl_protocol_type(std::string(type_attr));
if (NUM_BLWL_PROTOCOL_TYPES == blwl_protocol_type) {
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_wl_protocol),
"Invalid 'protocol' attribute '%s'\n",
type_attr);
}
config_protocol.set_wl_protocol_type(blwl_protocol_type);
/* Find the memory model, only applicable to shift-registor protocol */
if (BLWL_PROTOCOL_SHIFT_REGISTER == blwl_protocol_type) {
config_protocol.set_wl_memory_model_name(get_attribute(xml_wl_protocol, "circuit_model_name", loc_data).as_string());
}
}
/******************************************************************** /********************************************************************
* Parse XML codes of a <organization> to an object of configuration protocol * Parse XML codes of a <organization> to an object of configuration protocol
*******************************************************************/ *******************************************************************/
@ -65,6 +132,19 @@ void read_xml_config_organization(pugi::xml_node& xml_config_orgz,
"Invalid 'num_region=%d' definition. At least 1 region should be defined!\n", "Invalid 'num_region=%d' definition. At least 1 region should be defined!\n",
config_protocol.num_regions()); config_protocol.num_regions());
} }
/* Parse BL & WL protocols */
if (config_protocol.type() == CONFIG_MEM_QL_MEMORY_BANK) {
pugi::xml_node xml_bl_protocol = get_single_child(xml_config_orgz, "bl", loc_data, pugiutil::ReqOpt::OPTIONAL);
if (xml_bl_protocol) {
read_xml_bl_protocol(xml_bl_protocol, loc_data, config_protocol);
}
pugi::xml_node xml_wl_protocol = get_single_child(xml_config_orgz, "wl", loc_data, pugiutil::ReqOpt::OPTIONAL);
if (xml_wl_protocol) {
read_xml_wl_protocol(xml_wl_protocol, loc_data, config_protocol);
}
}
} }
/******************************************************************** /********************************************************************

View File

@ -46,6 +46,53 @@ std::vector<size_t> ito1hot_vec(const size_t& in_int,
return ret; return ret;
} }
/********************************************************************
* Convert an integer to an one-hot encoding character array
* For example:
* Input integer: 3
* Binary length : 4
* Output:
* index | 0 | 1 | 2 | 3
* ret | 0 | 0 | 0 | 1
*
* If you need all zero code, set the input integer same as the binary length
* For example:
* Input integer: 4
* Binary length : 4
* Output:
* index | 0 | 1 | 2 | 3
* ret | 0 | 0 | 0 | 0
*
********************************************************************/
std::vector<char> ito1hot_charvec(const size_t& in_int,
const size_t& bin_len) {
/* Make sure we do not have any overflow! */
VTR_ASSERT ( (in_int <= bin_len) );
/* Initialize */
std::vector<char> ret(bin_len, '0');
if (bin_len == in_int) {
return ret; /* all zero case */
}
ret[in_int] = '1'; /* Keep a good sequence of bits */
return ret;
}
std::string combine_two_1hot_str(const std::string& code1,
const std::string& code2) {
VTR_ASSERT(code1.length() == code2.length());
std::string ret = code1;
for (size_t ichar = 0; ichar < code2.length(); ichar++) {
VTR_ASSERT('0' == code2[ichar] || '1' == code2[ichar]);
if ('1' == code2[ichar]) {
ret[ichar] = code2[ichar];
}
}
return ret;
}
/******************************************************************** /********************************************************************
* Converter an integer to a binary vector * Converter an integer to a binary vector
* For example: * For example:

View File

@ -22,6 +22,21 @@ constexpr char DONT_CARE_CHAR = 'x';
std::vector<size_t> ito1hot_vec(const size_t& in_int, std::vector<size_t> ito1hot_vec(const size_t& in_int,
const size_t& bin_len); const size_t& bin_len);
std::vector<char> ito1hot_charvec(const size_t& in_int,
const size_t& bin_len);
/********************************************************************
* @brief Combine to two 1-hot codes which are in string format
* Any unique '1' will be merged
* For example:
* Code 1: 001000110
* Code 2: 010001001
* Output: 011001111
* @note This function requires two codes in the same length
********************************************************************/
std::string combine_two_1hot_str(const std::string& code1,
const std::string& code2);
std::vector<size_t> itobin_vec(const size_t& in_int, std::vector<size_t> itobin_vec(const size_t& in_int,
const size_t& bin_len); const size_t& bin_len);

View File

@ -51,11 +51,6 @@ BasicPort::BasicPort(const std::string& name, const size_t& width) {
set_origin_port_width(-1); set_origin_port_width(-1);
} }
/* Copy constructor */
BasicPort::BasicPort(const BasicPort& basic_port) {
set(basic_port);
}
/************************************************************************ /************************************************************************
* Accessors * Accessors
***********************************************************************/ ***********************************************************************/

View File

@ -18,7 +18,6 @@ class BasicPort {
BasicPort(const char* name, const size_t& width); BasicPort(const char* name, const size_t& width);
BasicPort(const std::string& name, const size_t& lsb, const size_t& msb); BasicPort(const std::string& name, const size_t& lsb, const size_t& msb);
BasicPort(const std::string& name, const size_t& width); BasicPort(const std::string& name, const size_t& width);
BasicPort(const BasicPort& basic_port); /* Copy constructor */
public: /* Overloaded operators */ public: /* Overloaded operators */
bool operator== (const BasicPort& portA) const; bool operator== (const BasicPort& portA) const;
bool operator< (const BasicPort& portA) const; bool operator< (const BasicPort& portA) const;

View File

@ -132,7 +132,7 @@ int build_fabric(OpenfpgaContext& openfpga_ctx,
VTR_ASSERT(false == fkey_fname.empty()); VTR_ASSERT(false == fkey_fname.empty());
curr_status = write_fabric_key_to_xml_file(openfpga_ctx.module_graph(), curr_status = write_fabric_key_to_xml_file(openfpga_ctx.module_graph(),
fkey_fname, fkey_fname,
openfpga_ctx.arch().config_protocol.type(), openfpga_ctx.arch().config_protocol,
cmd_context.option_enable(cmd, opt_verbose)); cmd_context.option_enable(cmd, opt_verbose));
/* If there is any error, final status cannot be overwritten by a success flag */ /* If there is any error, final status cannot be overwritten by a success flag */
if (CMD_EXEC_SUCCESS != curr_status) { if (CMD_EXEC_SUCCESS != curr_status) {

View File

@ -813,6 +813,15 @@ std::string generate_sram_local_port_name(const CircuitLibrary& circuit_lib,
return port_name; return port_name;
} }
/*********************************************************************
* Generate the BL/WL port names for the top-level module of an FPGA fabric
* Each BL/WL bus drive a specific configuration region has an unique name
*********************************************************************/
std::string generate_regional_blwl_port_name(const std::string& blwl_port_prefix,
const ConfigRegionId& region_id) {
return blwl_port_prefix + std::string("_config_region_") + std::to_string(size_t(region_id));
}
/********************************************************************* /*********************************************************************
* Generate the port name for the input bus of a routing multiplexer * Generate the port name for the input bus of a routing multiplexer
* This is very useful in Verilog code generation where the inputs of * This is very useful in Verilog code generation where the inputs of

View File

@ -16,6 +16,7 @@
#include "circuit_library.h" #include "circuit_library.h"
#include "device_grid.h" #include "device_grid.h"
#include "openfpga_port.h" #include "openfpga_port.h"
#include "module_manager_fwd.h"
/******************************************************************** /********************************************************************
* Function declaration * Function declaration
@ -183,6 +184,9 @@ std::string generate_sram_local_port_name(const CircuitLibrary& circuit_lib,
const e_config_protocol_type& sram_orgz_type, const e_config_protocol_type& sram_orgz_type,
const e_circuit_model_port_type& port_type); const e_circuit_model_port_type& port_type);
std::string generate_regional_blwl_port_name(const std::string& blwl_port_prefix,
const ConfigRegionId& region_id);
std::string generate_mux_input_bus_port_name(const CircuitLibrary& circuit_lib, std::string generate_mux_input_bus_port_name(const CircuitLibrary& circuit_lib,
const CircuitModelId& mux_model, const CircuitModelId& mux_model,
const size_t& mux_size, const size_t& mux_size,

View File

@ -56,9 +56,8 @@ int read_arch(OpenfpgaContext& openfpga_context,
return CMD_EXEC_FATAL_ERROR; return CMD_EXEC_FATAL_ERROR;
} }
if (false == check_configurable_memory_circuit_model(openfpga_context.arch().config_protocol.type(), if (false == check_configurable_memory_circuit_model(openfpga_context.arch().config_protocol,
openfpga_context.arch().circuit_lib, openfpga_context.arch().circuit_lib)) {
openfpga_context.arch().config_protocol.memory_model())) {
return CMD_EXEC_FATAL_ERROR; return CMD_EXEC_FATAL_ERROR;
} }

View File

@ -422,7 +422,7 @@ int build_top_module(ModuleManager& module_manager,
if (0 < module_manager.configurable_children(top_module).size()) { if (0 < module_manager.configurable_children(top_module).size()) {
add_top_module_nets_memory_config_bus(module_manager, decoder_lib, add_top_module_nets_memory_config_bus(module_manager, decoder_lib,
top_module, top_module,
circuit_lib, sram_model, circuit_lib,
config_protocol, circuit_lib.design_tech_type(sram_model), config_protocol, circuit_lib.design_tech_type(sram_model),
top_module_num_config_bits); top_module_num_config_bits);
} }

View File

@ -852,35 +852,7 @@ void add_top_module_sram_ports(ModuleManager& module_manager,
break; break;
} }
case CONFIG_MEM_QL_MEMORY_BANK: { case CONFIG_MEM_QL_MEMORY_BANK: {
BasicPort en_port(std::string(DECODER_ENABLE_PORT_NAME), 1); add_top_module_ql_memory_bank_sram_ports(module_manager, module_id, circuit_lib, config_protocol, num_config_bits);
module_manager.add_port(module_id, en_port, ModuleManager::MODULE_INPUT_PORT);
/* BL address size is the largest among all the regions */
size_t bl_addr_size = 0;
for (const ConfigRegionId& config_region : module_manager.regions(module_id)) {
bl_addr_size = std::max(bl_addr_size, find_mux_local_decoder_addr_size(num_config_bits[config_region].first));
}
BasicPort bl_addr_port(std::string(DECODER_BL_ADDRESS_PORT_NAME), bl_addr_size);
module_manager.add_port(module_id, bl_addr_port, ModuleManager::MODULE_INPUT_PORT);
/* WL address size is the largest among all the regions */
size_t wl_addr_size = 0;
for (const ConfigRegionId& config_region : module_manager.regions(module_id)) {
wl_addr_size = std::max(wl_addr_size, find_mux_local_decoder_addr_size(num_config_bits[config_region].second));
}
BasicPort wl_addr_port(std::string(DECODER_WL_ADDRESS_PORT_NAME), wl_addr_size);
module_manager.add_port(module_id, wl_addr_port, ModuleManager::MODULE_INPUT_PORT);
/* Optional: If we have WLR port, we should add a read-back port */
if (!circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_WLR).empty()) {
BasicPort readback_port(std::string(DECODER_READBACK_PORT_NAME), config_protocol.num_regions());
module_manager.add_port(module_id, readback_port, ModuleManager::MODULE_INPUT_PORT);
}
/* Data input should be dependent on the number of configuration regions*/
BasicPort din_port(std::string(DECODER_DATA_IN_PORT_NAME), config_protocol.num_regions());
module_manager.add_port(module_id, din_port, ModuleManager::MODULE_INPUT_PORT);
break; break;
} }
case CONFIG_MEM_SCAN_CHAIN: { case CONFIG_MEM_SCAN_CHAIN: {
@ -1765,7 +1737,6 @@ void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
DecoderLibrary& decoder_lib, DecoderLibrary& decoder_lib,
const ModuleId& parent_module, const ModuleId& parent_module,
const CircuitLibrary& circuit_lib, const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const ConfigProtocol& config_protocol, const ConfigProtocol& config_protocol,
const TopModuleNumConfigBits& num_config_bits) { const TopModuleNumConfigBits& num_config_bits) {
switch (config_protocol.type()) { switch (config_protocol.type()) {
@ -1783,7 +1754,7 @@ void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
add_top_module_nets_cmos_memory_bank_config_bus(module_manager, decoder_lib, parent_module, num_config_bits); add_top_module_nets_cmos_memory_bank_config_bus(module_manager, decoder_lib, parent_module, num_config_bits);
break; break;
case CONFIG_MEM_QL_MEMORY_BANK: case CONFIG_MEM_QL_MEMORY_BANK:
add_top_module_nets_cmos_ql_memory_bank_config_bus(module_manager, decoder_lib, parent_module, circuit_lib, sram_model, num_config_bits); add_top_module_nets_cmos_ql_memory_bank_config_bus(module_manager, decoder_lib, parent_module, circuit_lib, config_protocol, num_config_bits);
break; break;
case CONFIG_MEM_FRAME_BASED: case CONFIG_MEM_FRAME_BASED:
add_top_module_nets_cmos_memory_frame_config_bus(module_manager, decoder_lib, parent_module, num_config_bits); add_top_module_nets_cmos_memory_frame_config_bus(module_manager, decoder_lib, parent_module, num_config_bits);
@ -1831,7 +1802,6 @@ void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
DecoderLibrary& decoder_lib, DecoderLibrary& decoder_lib,
const ModuleId& parent_module, const ModuleId& parent_module,
const CircuitLibrary& circuit_lib, const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const ConfigProtocol& config_protocol, const ConfigProtocol& config_protocol,
const e_circuit_model_design_tech& mem_tech, const e_circuit_model_design_tech& mem_tech,
const TopModuleNumConfigBits& num_config_bits) { const TopModuleNumConfigBits& num_config_bits) {
@ -1843,7 +1813,6 @@ void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
add_top_module_nets_cmos_memory_config_bus(module_manager, decoder_lib, add_top_module_nets_cmos_memory_config_bus(module_manager, decoder_lib,
parent_module, parent_module,
circuit_lib, circuit_lib,
sram_model,
config_protocol, config_protocol,
num_config_bits); num_config_bits);
break; break;

View File

@ -66,7 +66,6 @@ void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
DecoderLibrary& decoder_lib, DecoderLibrary& decoder_lib,
const ModuleId& parent_module, const ModuleId& parent_module,
const CircuitLibrary& circuit_lib, const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const ConfigProtocol& config_protocol, const ConfigProtocol& config_protocol,
const e_circuit_model_design_tech& mem_tech, const e_circuit_model_design_tech& mem_tech,
const TopModuleNumConfigBits& num_config_bits); const TopModuleNumConfigBits& num_config_bits);

View File

@ -31,13 +31,15 @@
namespace openfpga { namespace openfpga {
/********************************************************************* /*********************************************************************
* Top-level function to add nets for quicklogic memory banks * This function to add nets for quicklogic memory banks
* Each configuration region has independent memory bank circuitry * Each configuration region has independent memory bank circuitry
* - Find the number of BLs and WLs required for each region * - Find the number of BLs and WLs required for each region
* - Create BL and WL decoders, and add them to decoder library * - Create BL and WL decoders, and add them to decoder library
* - Create nets to connect from top-level module inputs to inputs of decoders * - Create nets to connect from top-level module inputs to inputs of decoders
* - Create nets to connect from outputs of decoders to BL/WL of configurable children * - Create nets to connect from outputs of decoders to BL/WL of configurable children
* *
* @note this function only adds the BL configuration bus for decoders
*
* Detailed schematic of how memory banks are connected in the top-level: * Detailed schematic of how memory banks are connected in the top-level:
* Consider a random Region X, local BL address lines are aligned to the LSB of the * Consider a random Region X, local BL address lines are aligned to the LSB of the
* top-level BL address lines * top-level BL address lines
@ -120,7 +122,8 @@ namespace openfpga {
* +---------+ * +---------+
* *
**********************************************************************/ **********************************************************************/
void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_manager, static
void add_top_module_nets_cmos_ql_memory_bank_bl_decoder_config_bus(ModuleManager& module_manager,
DecoderLibrary& decoder_lib, DecoderLibrary& decoder_lib,
const ModuleId& top_module, const ModuleId& top_module,
const CircuitLibrary& circuit_lib, const CircuitLibrary& circuit_lib,
@ -137,26 +140,12 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma
/* Data in port should match the number of configuration regions */ /* Data in port should match the number of configuration regions */
VTR_ASSERT(din_port_info.get_width() == module_manager.regions(top_module).size()); VTR_ASSERT(din_port_info.get_width() == module_manager.regions(top_module).size());
/* Find readback port from the top-level module */
ModulePortId readback_port = module_manager.find_module_port(top_module, std::string(DECODER_READBACK_PORT_NAME));
BasicPort readback_port_info;
/* Readback port if available, should be a 1-bit port */
if (readback_port) {
readback_port_info = module_manager.module_port(top_module, readback_port);
VTR_ASSERT(readback_port_info.get_width() == 1);
}
/* Find BL and WL address port from the top-level module */ /* Find BL and WL address port from the top-level module */
ModulePortId bl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_BL_ADDRESS_PORT_NAME)); ModulePortId bl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_BL_ADDRESS_PORT_NAME));
BasicPort bl_addr_port_info = module_manager.module_port(top_module, bl_addr_port); BasicPort bl_addr_port_info = module_manager.module_port(top_module, bl_addr_port);
ModulePortId wl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_WL_ADDRESS_PORT_NAME));
BasicPort wl_addr_port_info = module_manager.module_port(top_module, wl_addr_port);
/* Find the top-level number of BLs and WLs required to access each memory bit */ /* Find the top-level number of BLs and WLs required to access each memory bit */
size_t bl_addr_size = bl_addr_port_info.get_width(); size_t bl_addr_size = bl_addr_port_info.get_width();
size_t wl_addr_size = wl_addr_port_info.get_width();
/* Each memory bank has a unified number of BL/WLs */ /* Each memory bank has a unified number of BL/WLs */
size_t num_bls = 0; size_t num_bls = 0;
@ -164,11 +153,6 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma
num_bls = std::max(num_bls, curr_config_bits.first); num_bls = std::max(num_bls, curr_config_bits.first);
} }
size_t num_wls = 0;
for (const auto& curr_config_bits : num_config_bits) {
num_wls = std::max(num_wls, curr_config_bits.second);
}
/* Create separated memory bank circuitry, i.e., BL/WL decoders for each region */ /* Create separated memory bank circuitry, i.e., BL/WL decoders for each region */
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
/************************************************************** /**************************************************************
@ -199,34 +183,6 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma
size_t curr_bl_decoder_instance_id = module_manager.num_instance(top_module, bl_decoder_module); size_t curr_bl_decoder_instance_id = module_manager.num_instance(top_module, bl_decoder_module);
module_manager.add_child_module(top_module, bl_decoder_module); module_manager.add_child_module(top_module, bl_decoder_module);
/**************************************************************
* Add the WL decoder module
* Search the decoder library
* If we find one, we use the module.
* Otherwise, we create one and add it to the decoder library
*/
DecoderId wl_decoder_id = decoder_lib.find_decoder(wl_addr_size, num_wls,
true, false, false, readback_port != ModulePortId::INVALID());
if (DecoderId::INVALID() == wl_decoder_id) {
wl_decoder_id = decoder_lib.add_decoder(wl_addr_size, num_wls, true, false, false, readback_port != ModulePortId::INVALID());
}
VTR_ASSERT(DecoderId::INVALID() != wl_decoder_id);
/* Create a module if not existed yet */
std::string wl_decoder_module_name = generate_memory_decoder_subckt_name(wl_addr_size, num_wls);
ModuleId wl_decoder_module = module_manager.find_module(wl_decoder_module_name);
if (ModuleId::INVALID() == wl_decoder_module) {
/* BL decoder has the same ports as the frame-based decoders
* We reuse it here
*/
wl_decoder_module = build_wl_memory_decoder_module(module_manager,
decoder_lib,
wl_decoder_id);
}
VTR_ASSERT(ModuleId::INVALID() != wl_decoder_module);
size_t curr_wl_decoder_instance_id = module_manager.num_instance(top_module, wl_decoder_module);
module_manager.add_child_module(top_module, wl_decoder_module);
/************************************************************** /**************************************************************
* Add module nets from the top module to BL decoder's inputs * Add module nets from the top module to BL decoder's inputs
*/ */
@ -267,57 +223,15 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma
/* Configure the net sink */ /* Configure the net sink */
module_manager.add_module_net_sink(top_module, din_net, bl_decoder_module, curr_bl_decoder_instance_id, bl_decoder_din_port, bl_decoder_din_port_info.pins()[0]); module_manager.add_module_net_sink(top_module, din_net, bl_decoder_module, curr_bl_decoder_instance_id, bl_decoder_din_port, bl_decoder_din_port_info.pins()[0]);
/**************************************************************
* Add module nets from the top module to WL decoder's inputs
*/
ModulePortId wl_decoder_en_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_ENABLE_PORT_NAME));
BasicPort wl_decoder_en_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_en_port);
ModulePortId wl_decoder_addr_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_ADDRESS_PORT_NAME));
BasicPort wl_decoder_addr_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_addr_port);
ModulePortId wl_decoder_readback_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_READBACK_PORT_NAME));
BasicPort wl_decoder_readback_port_info;
if (wl_decoder_readback_port) {
wl_decoder_readback_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_readback_port);
}
/* Top module Enable port -> WL Decoder Enable port */
add_module_bus_nets(module_manager,
top_module,
top_module, 0, en_port,
wl_decoder_module, curr_wl_decoder_instance_id, wl_decoder_en_port);
/* Top module Address port -> WL Decoder Address port */
add_module_bus_nets(module_manager,
top_module,
top_module, 0, wl_addr_port,
wl_decoder_module, curr_wl_decoder_instance_id, wl_decoder_addr_port);
/* Top module readback port -> WL Decoder readback port */
if (wl_decoder_readback_port) {
add_module_bus_nets(module_manager,
top_module,
top_module, 0, readback_port,
wl_decoder_module, curr_wl_decoder_instance_id, wl_decoder_readback_port);
}
/************************************************************** /**************************************************************
* Precompute the BLs and WLs distribution across the FPGA fabric * 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 * The distribution is a matrix which contains the starting index of BL/WL for each column or row
*/ */
std::pair<int, int> child_x_range = compute_memory_bank_regional_configurable_child_x_range(module_manager, top_module, config_region); std::pair<int, int> child_x_range = compute_memory_bank_regional_configurable_child_x_range(module_manager, top_module, config_region);
std::pair<int, int> child_y_range = compute_memory_bank_regional_configurable_child_y_range(module_manager, top_module, config_region);
std::map<int, size_t> num_bls_per_tile = compute_memory_bank_regional_bitline_numbers_per_tile(module_manager, top_module, std::map<int, size_t> num_bls_per_tile = compute_memory_bank_regional_bitline_numbers_per_tile(module_manager, top_module,
config_region, config_region,
circuit_lib, sram_model); circuit_lib, sram_model);
std::map<int, size_t> num_wls_per_tile = compute_memory_bank_regional_wordline_numbers_per_tile(module_manager, top_module,
config_region,
circuit_lib, sram_model);
std::map<int, size_t> bl_start_index_per_tile = compute_memory_bank_regional_blwl_start_index_per_tile(child_x_range, num_bls_per_tile); std::map<int, size_t> bl_start_index_per_tile = compute_memory_bank_regional_blwl_start_index_per_tile(child_x_range, num_bls_per_tile);
std::map<int, size_t> wl_start_index_per_tile = compute_memory_bank_regional_blwl_start_index_per_tile(child_y_range, num_wls_per_tile);
/************************************************************** /**************************************************************
* Add nets from BL data out to each configurable child * Add nets from BL data out to each configurable child
@ -378,20 +292,158 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma
} }
} }
/**************************************************************
* Add the BL and WL decoders to the end of configurable children list
* Note: this MUST be done after adding all the module nets to other regular configurable children
*/
module_manager.add_configurable_child(top_module, bl_decoder_module, curr_bl_decoder_instance_id);
module_manager.add_configurable_child_to_region(top_module,
config_region,
bl_decoder_module,
curr_bl_decoder_instance_id,
module_manager.configurable_children(top_module).size() - 1);
}
}
/*********************************************************************
* Top-level function to add nets for quicklogic memory banks
* Each configuration region has independent memory bank circuitry
* - Find the number of BLs and WLs required for each region
* - Create BL and WL decoders, and add them to decoder library
* - Create nets to connect from top-level module inputs to inputs of decoders
* - Create nets to connect from outputs of decoders to BL/WL of configurable children
*
* @note this function only adds the WL configuration bus for decoders
*
* @note see detailed explanation on the bus connection in function add_top_module_nets_cmos_ql_memory_bank_bl_decoder_config_bus()
**********************************************************************/
static
void add_top_module_nets_cmos_ql_memory_bank_wl_decoder_config_bus(ModuleManager& module_manager,
DecoderLibrary& decoder_lib,
const ModuleId& top_module,
const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const TopModuleNumConfigBits& num_config_bits) {
/* Find Enable port from the top-level module */
ModulePortId en_port = module_manager.find_module_port(top_module, std::string(DECODER_ENABLE_PORT_NAME));
BasicPort en_port_info = module_manager.module_port(top_module, en_port);
/* Find readback port from the top-level module */
ModulePortId readback_port = module_manager.find_module_port(top_module, std::string(DECODER_READBACK_PORT_NAME));
BasicPort readback_port_info;
/* Readback port if available, should be a 1-bit port */
if (readback_port) {
readback_port_info = module_manager.module_port(top_module, readback_port);
VTR_ASSERT(readback_port_info.get_width() == 1);
}
/* Find BL and WL address port from the top-level module */
ModulePortId wl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_WL_ADDRESS_PORT_NAME));
BasicPort wl_addr_port_info = module_manager.module_port(top_module, wl_addr_port);
/* Find the top-level number of BLs and WLs required to access each memory bit */
size_t wl_addr_size = wl_addr_port_info.get_width();
/* Each memory bank has a unified number of BL/WLs */
size_t num_wls = 0;
for (const auto& curr_config_bits : num_config_bits) {
num_wls = std::max(num_wls, curr_config_bits.second);
}
/* Create separated memory bank circuitry, i.e., BL/WL decoders for each region */
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
/**************************************************************
* Add the WL decoder module
* Search the decoder library
* If we find one, we use the module.
* Otherwise, we create one and add it to the decoder library
*/
DecoderId wl_decoder_id = decoder_lib.find_decoder(wl_addr_size, num_wls,
true, false, false, readback_port != ModulePortId::INVALID());
if (DecoderId::INVALID() == wl_decoder_id) {
wl_decoder_id = decoder_lib.add_decoder(wl_addr_size, num_wls, true, false, false, readback_port != ModulePortId::INVALID());
}
VTR_ASSERT(DecoderId::INVALID() != wl_decoder_id);
/* Create a module if not existed yet */
std::string wl_decoder_module_name = generate_memory_decoder_subckt_name(wl_addr_size, num_wls);
ModuleId wl_decoder_module = module_manager.find_module(wl_decoder_module_name);
if (ModuleId::INVALID() == wl_decoder_module) {
/* BL decoder has the same ports as the frame-based decoders
* We reuse it here
*/
wl_decoder_module = build_wl_memory_decoder_module(module_manager,
decoder_lib,
wl_decoder_id);
}
VTR_ASSERT(ModuleId::INVALID() != wl_decoder_module);
size_t curr_wl_decoder_instance_id = module_manager.num_instance(top_module, wl_decoder_module);
module_manager.add_child_module(top_module, wl_decoder_module);
/**************************************************************
* Add module nets from the top module to WL decoder's inputs
*/
ModulePortId wl_decoder_en_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_ENABLE_PORT_NAME));
BasicPort wl_decoder_en_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_en_port);
ModulePortId wl_decoder_addr_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_ADDRESS_PORT_NAME));
BasicPort wl_decoder_addr_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_addr_port);
ModulePortId wl_decoder_readback_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_READBACK_PORT_NAME));
BasicPort wl_decoder_readback_port_info;
if (wl_decoder_readback_port) {
wl_decoder_readback_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_readback_port);
}
/* Top module Enable port -> WL Decoder Enable port */
add_module_bus_nets(module_manager,
top_module,
top_module, 0, en_port,
wl_decoder_module, curr_wl_decoder_instance_id, wl_decoder_en_port);
/* Top module Address port -> WL Decoder Address port */
add_module_bus_nets(module_manager,
top_module,
top_module, 0, wl_addr_port,
wl_decoder_module, curr_wl_decoder_instance_id, wl_decoder_addr_port);
/* Top module readback port -> WL Decoder readback port */
if (wl_decoder_readback_port) {
add_module_bus_nets(module_manager,
top_module,
top_module, 0, readback_port,
wl_decoder_module, curr_wl_decoder_instance_id, wl_decoder_readback_port);
}
/**************************************************************
* 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
*/
std::pair<int, int> child_y_range = compute_memory_bank_regional_configurable_child_y_range(module_manager, top_module, config_region);
std::map<int, size_t> num_wls_per_tile = compute_memory_bank_regional_wordline_numbers_per_tile(module_manager, top_module,
config_region,
circuit_lib, sram_model);
std::map<int, size_t> wl_start_index_per_tile = compute_memory_bank_regional_blwl_start_index_per_tile(child_y_range, num_wls_per_tile);
/************************************************************** /**************************************************************
* Add nets from WL data out to each configurable child * Add nets from WL data out to each configurable child
*/ */
ModulePortId wl_decoder_dout_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_DATA_OUT_PORT_NAME)); ModulePortId wl_decoder_dout_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_DATA_OUT_PORT_NAME));
BasicPort wl_decoder_dout_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_dout_port); BasicPort wl_decoder_dout_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_dout_port);
/* Note we skip the last child which is the bl decoder added */
for (size_t child_id = 0; child_id < module_manager.region_configurable_children(top_module, config_region).size(); ++child_id) { for (size_t child_id = 0; child_id < module_manager.region_configurable_children(top_module, config_region).size(); ++child_id) {
ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id]; ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id];
vtr::Point<int> coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id]; vtr::Point<int> coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id];
size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[child_id]; size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[child_id];
/* Find the WL port */ /* Find the WL port. If the child does not have WL port, bypass it. It is usually a decoder module */
ModulePortId child_wl_port = module_manager.find_module_port(child_module, std::string(MEMORY_WL_PORT_NAME)); ModulePortId child_wl_port = module_manager.find_module_port(child_module, std::string(MEMORY_WL_PORT_NAME));
if (!child_wl_port) {
continue;
}
BasicPort child_wl_port_info = module_manager.module_port(child_module, child_wl_port); BasicPort child_wl_port_info = module_manager.module_port(child_module, child_wl_port);
size_t cur_wl_index = 0; size_t cur_wl_index = 0;
@ -428,8 +480,11 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma
size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[child_id]; size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[child_id];
/* Find the WL port */ /* Find the WLR port. If the child does not have WLR port, bypass it. It is usually a decoder module */
ModulePortId child_wlr_port = module_manager.find_module_port(child_module, std::string(MEMORY_WLR_PORT_NAME)); ModulePortId child_wlr_port = module_manager.find_module_port(child_module, std::string(MEMORY_WLR_PORT_NAME));
if (!child_wlr_port) {
continue;
}
BasicPort child_wlr_port_info = module_manager.module_port(child_module, child_wlr_port); BasicPort child_wlr_port_info = module_manager.module_port(child_module, child_wlr_port);
size_t cur_wlr_index = 0; size_t cur_wlr_index = 0;
@ -458,13 +513,6 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma
* Add the BL and WL decoders to the end of configurable children list * Add the BL and WL decoders to the end of configurable children list
* Note: this MUST be done after adding all the module nets to other regular configurable children * Note: this MUST be done after adding all the module nets to other regular configurable children
*/ */
module_manager.add_configurable_child(top_module, bl_decoder_module, curr_bl_decoder_instance_id);
module_manager.add_configurable_child_to_region(top_module,
config_region,
bl_decoder_module,
curr_bl_decoder_instance_id,
module_manager.configurable_children(top_module).size() - 1);
module_manager.add_configurable_child(top_module, wl_decoder_module, curr_wl_decoder_instance_id); module_manager.add_configurable_child(top_module, wl_decoder_module, curr_wl_decoder_instance_id);
module_manager.add_configurable_child_to_region(top_module, module_manager.add_configurable_child_to_region(top_module,
config_region, config_region,
@ -474,4 +522,406 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma
} }
} }
/*********************************************************************
* This function to add nets for quicklogic memory banks using flatten BLs and WLs
* Each configuration region has independent BL/WLs
* - Find the number of BLs and WLs required for each region
* - Create nets to connect from top-level module inputs to BL/WL of configurable children
*
* @note this function only adds the BL configuration bus
*
* Detailed schematic of each memory bank:
* @note The numbers are just made to show a simplified example, practical cases are more complicated!
*
* BL[0:9] BL[10:17] BL[18:22]
* | | |
* | | |
* WL[0:3]-->-----------+---------------+---- ... |------+-->
* | | | | | |
* | v | v | v
* | +-------+ | +-------+ | +------+
* +-->| SRAM | +-->| SRAM | +->| SRAM |
* | | [0:8] | | | [0:5] | ... | | [0:7]|
* | +-------+ | +-------+ | +------+
* | | |
* WL[4:14] -----------+--------------+--------- | -----+-->
* | | | | | |
* | v | v | v
* | +-------+ | +-------+ | +-------+
* +-->| SRAM | | | SRAM | +->| SRAM |
* | | [0:80]| | | [0:63]| ... | | [0:31]|
* | +-------+ | +-------+ | +-------+
* | |
* | ... ... ... | ...
* | | |
* WL[15:18] -----------+---------------+---- --- | -----+-->
* | | | | | |
* | v | v | v
* | +-------+ | +-------+ | +-------+
* +-->| SRAM | +-->| SRAM | +->| SRAM |
* | |[0:5] | | | [0:8] | ... | | [0:2] |
* | +-------+ | +-------+ | +-------+
* v v v
* WL[0:9] WL[0:7] WL[0:4]
*
**********************************************************************/
static
void add_top_module_nets_cmos_ql_memory_bank_bl_flatten_config_bus(ModuleManager& module_manager,
const ModuleId& top_module,
const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model) {
/* Create connections between BLs of top-level module and BLs of child modules for each region */
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
*/
std::pair<int, int> child_x_range = compute_memory_bank_regional_configurable_child_x_range(module_manager, top_module, config_region);
std::map<int, size_t> num_bls_per_tile = compute_memory_bank_regional_bitline_numbers_per_tile(module_manager, top_module,
config_region,
circuit_lib, sram_model);
std::map<int, size_t> bl_start_index_per_tile = compute_memory_bank_regional_blwl_start_index_per_tile(child_x_range, num_bls_per_tile);
/**************************************************************
* Add BL nets from top module to each configurable child
* BL pins of top 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
*
* BL[i .. i + sqrt(N)]
* |
* | CLB[1][H]
* | +---------+
* | | SRAM |
* +-->| [0..N] |
* | +---------+
* |
* ...
* | CLB[1][1]
* | +---------+
* | | SRAM |
* +-->| [0..N] |
* | +---------+
* |
*/
ModulePortId top_module_bl_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_BL_PORT_NAME), config_region));
BasicPort top_module_bl_port_info = module_manager.module_port(top_module, top_module_bl_port);
for (size_t child_id = 0; child_id < module_manager.region_configurable_children(top_module, config_region).size(); ++child_id) {
ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id];
vtr::Point<int> coord = module_manager.region_configurable_child_coordinates(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_bl_port = module_manager.find_module_port(child_module, std::string(MEMORY_BL_PORT_NAME));
BasicPort child_bl_port_info = module_manager.module_port(child_module, child_bl_port);
size_t cur_bl_index = 0;
for (const size_t& sink_bl_pin : child_bl_port_info.pins()) {
size_t bl_pin_id = bl_start_index_per_tile[coord.x()] + cur_bl_index;
VTR_ASSERT(bl_pin_id < top_module_bl_port_info.pins().size());
/* Create net */
ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
top_module, 0,
top_module_bl_port,
top_module_bl_port_info.pins()[bl_pin_id]);
VTR_ASSERT(ModuleNetId::INVALID() != net);
/* Add net sink */
module_manager.add_module_net_sink(top_module, net,
child_module, child_instance, child_bl_port, sink_bl_pin);
cur_bl_index++;
}
}
}
}
/*********************************************************************
* Top-level function to add nets for quicklogic memory banks using flatten BL/WLs
* Each configuration region has independent BL/WLs
* - Find the number of BLs and WLs required for each region
* - Create nets to connect from top-level module inputs to BL/WL of configurable children
*
* @note this function only adds the WL configuration bus
*
* @note see detailed explanation on the bus connection in function add_top_module_nets_cmos_ql_memory_bank_bl_flatten_config_bus()
**********************************************************************/
static
void add_top_module_nets_cmos_ql_memory_bank_wl_flatten_config_bus(ModuleManager& module_manager,
const ModuleId& top_module,
const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model) {
/* Create connections between WLs of top-level module and WLs of child modules for each region */
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
*/
std::pair<int, int> child_y_range = compute_memory_bank_regional_configurable_child_y_range(module_manager, top_module, config_region);
std::map<int, size_t> num_wls_per_tile = compute_memory_bank_regional_wordline_numbers_per_tile(module_manager, top_module,
config_region,
circuit_lib, sram_model);
std::map<int, size_t> wl_start_index_per_tile = compute_memory_bank_regional_blwl_start_index_per_tile(child_y_range, num_wls_per_tile);
/**************************************************************
* Add WL nets from top module to each configurable child
*/
ModulePortId top_module_wl_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_WL_PORT_NAME), config_region));
BasicPort top_module_wl_port_info = module_manager.module_port(top_module, top_module_wl_port);
for (size_t child_id = 0; child_id < module_manager.region_configurable_children(top_module, config_region).size(); ++child_id) {
ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id];
vtr::Point<int> coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id];
size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[child_id];
/* Find the WL port */
ModulePortId child_wl_port = module_manager.find_module_port(child_module, std::string(MEMORY_WL_PORT_NAME));
BasicPort child_wl_port_info = module_manager.module_port(child_module, child_wl_port);
size_t cur_wl_index = 0;
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;
VTR_ASSERT(wl_pin_id < top_module_wl_port_info.pins().size());
/* Create net */
ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
top_module, 0,
top_module_wl_port,
top_module_wl_port_info.pins()[wl_pin_id]);
VTR_ASSERT(ModuleNetId::INVALID() != net);
/* Add net sink */
module_manager.add_module_net_sink(top_module, net,
child_module, child_instance, child_wl_port, sink_wl_pin);
cur_wl_index++;
}
}
/**************************************************************
* Optional: Add WLR nets from top module to each configurable child
*/
ModulePortId top_module_wlr_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_WLR_PORT_NAME), config_region));
BasicPort top_module_wlr_port_info;
if (top_module_wlr_port) {
top_module_wlr_port_info = module_manager.module_port(top_module, top_module_wlr_port);
for (size_t child_id = 0; child_id < module_manager.region_configurable_children(top_module, config_region).size(); ++child_id) {
ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id];
vtr::Point<int> coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id];
size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[child_id];
/* Find the WL port */
ModulePortId child_wlr_port = module_manager.find_module_port(child_module, std::string(MEMORY_WLR_PORT_NAME));
BasicPort child_wlr_port_info = module_manager.module_port(child_module, child_wlr_port);
size_t cur_wlr_index = 0;
for (const size_t& sink_wlr_pin : child_wlr_port_info.pins()) {
size_t wlr_pin_id = wl_start_index_per_tile[coord.y()] + cur_wlr_index;
VTR_ASSERT(wlr_pin_id < top_module_wlr_port_info.pins().size());
/* Create net */
ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
top_module, 0,
top_module_wlr_port,
top_module_wlr_port_info.pins()[wlr_pin_id]);
VTR_ASSERT(ModuleNetId::INVALID() != net);
/* Add net sink */
module_manager.add_module_net_sink(top_module, net,
child_module, child_instance, child_wlr_port, sink_wlr_pin);
cur_wlr_index++;
}
}
}
}
}
/*********************************************************************
* Top-level function to add nets for quicklogic memory banks
* - Each configuration region has independent memory bank circuitry
* - BL and WL may have different circuitry and wire connection, e.g., decoder, flatten or shift-registers
* - BL control circuitry
* - Decoder: Add a BL decoder; Connect enable, address and data-in (din) between top-level and decoders; Connect data ports between between the decoder and configurable child modules
* - Flatten: Connect BLs between the top-level port and configurable child modules
* - TODO: Shift registers: add blocks of shift register chain (could be multi-head); Connect shift register outputs to configurable child modules
*
* - WL control circuitry
* - Decoder: Add a WL decoder; Connect address ports between top-level and decoders; Connect data ports between the decoder and configurable child modules
* - Flatten: Connect BLs between the top-level port and configurable child modules
* - TODO: Shift registers: add blocks of shift register chain (could be multi-head); Connect shift register outputs to configurable child modules
********************************************************************/
void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_manager,
DecoderLibrary& decoder_lib,
const ModuleId& top_module,
const CircuitLibrary& circuit_lib,
const ConfigProtocol& config_protocol,
const TopModuleNumConfigBits& num_config_bits) {
VTR_ASSERT_SAFE(CONFIG_MEM_QL_MEMORY_BANK == config_protocol.type());
CircuitModelId sram_model = config_protocol.memory_model();
switch (config_protocol.bl_protocol_type()) {
case BLWL_PROTOCOL_DECODER: {
add_top_module_nets_cmos_ql_memory_bank_bl_decoder_config_bus(module_manager, decoder_lib, top_module, circuit_lib, sram_model, num_config_bits);
break;
}
case BLWL_PROTOCOL_FLATTEN: {
add_top_module_nets_cmos_ql_memory_bank_bl_flatten_config_bus(module_manager, top_module, circuit_lib, sram_model);
break;
}
case BLWL_PROTOCOL_SHIFT_REGISTER: {
/* TODO */
break;
}
default: {
VTR_LOG_ERROR("Invalid BL protocol");
exit(1);
}
}
switch (config_protocol.wl_protocol_type()) {
case BLWL_PROTOCOL_DECODER: {
add_top_module_nets_cmos_ql_memory_bank_wl_decoder_config_bus(module_manager, decoder_lib, top_module, circuit_lib, sram_model, num_config_bits);
break;
}
case BLWL_PROTOCOL_FLATTEN: {
add_top_module_nets_cmos_ql_memory_bank_wl_flatten_config_bus(module_manager, top_module, circuit_lib, sram_model);
break;
}
case BLWL_PROTOCOL_SHIFT_REGISTER: {
/* TODO */
break;
}
default: {
VTR_LOG_ERROR("Invalid WL protocol");
exit(1);
}
}
}
/********************************************************************
* Add a list of ports that are used for SRAM configuration to the FPGA
* top-level module
* - Add ports for BL control circuitry:
* - Decoder
* - an enable signals
* - an BL address port
* - a data-in port
* - Flatten
* - BL ports
* - TODO: Shift registers
* - Head of shift register chain for BLs
* - Tail of shift register chain for BLs
*
* - Add ports for WL control circuitry:
* - Decoder
* - an WL address port
* - a Readback port (Optional, only needed when WLR is required)
* - Flatten
* - WL ports
* - WLR ports (Optional)
* - TODO: Shift registers
* - Head of shift register chain for WLs
* - Tail of shift register chain for WLs
* - a Readback port (Optional, only needed when WLR is required)
*
* @note In this memory decoders, the address size will be computed in a different way than the regular one
********************************************************************/
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 TopModuleNumConfigBits& num_config_bits) {
VTR_ASSERT_SAFE(CONFIG_MEM_QL_MEMORY_BANK == config_protocol.type());
CircuitModelId sram_model = config_protocol.memory_model();
switch (config_protocol.bl_protocol_type()) {
case BLWL_PROTOCOL_DECODER: {
/* Add enable signals */
BasicPort en_port(std::string(DECODER_ENABLE_PORT_NAME), 1);
module_manager.add_port(module_id, en_port, ModuleManager::MODULE_INPUT_PORT);
/* BL address size is the largest among all the regions */
size_t bl_addr_size = 0;
for (const ConfigRegionId& config_region : module_manager.regions(module_id)) {
bl_addr_size = std::max(bl_addr_size, find_mux_local_decoder_addr_size(num_config_bits[config_region].first));
}
BasicPort bl_addr_port(std::string(DECODER_BL_ADDRESS_PORT_NAME), bl_addr_size);
module_manager.add_port(module_id, bl_addr_port, ModuleManager::MODULE_INPUT_PORT);
/* Data input should be dependent on the number of configuration regions*/
BasicPort din_port(std::string(DECODER_DATA_IN_PORT_NAME), config_protocol.num_regions());
module_manager.add_port(module_id, din_port, ModuleManager::MODULE_INPUT_PORT);
break;
}
case BLWL_PROTOCOL_FLATTEN: {
/* Each region will have independent BLs */
for (const ConfigRegionId& config_region : module_manager.regions(module_id)) {
size_t bl_size = num_config_bits[config_region].first;
BasicPort bl_port(generate_regional_blwl_port_name(std::string(MEMORY_BL_PORT_NAME), config_region), bl_size);
module_manager.add_port(module_id, bl_port, ModuleManager::MODULE_INPUT_PORT);
}
break;
}
case BLWL_PROTOCOL_SHIFT_REGISTER: {
/* TODO */
break;
}
default: {
VTR_LOG_ERROR("Invalid BL protocol");
exit(1);
}
}
switch (config_protocol.wl_protocol_type()) {
case BLWL_PROTOCOL_DECODER: {
/* WL address size is the largest among all the regions */
size_t wl_addr_size = 0;
for (const ConfigRegionId& config_region : module_manager.regions(module_id)) {
wl_addr_size = std::max(wl_addr_size, find_mux_local_decoder_addr_size(num_config_bits[config_region].second));
}
BasicPort wl_addr_port(std::string(DECODER_WL_ADDRESS_PORT_NAME), wl_addr_size);
module_manager.add_port(module_id, wl_addr_port, ModuleManager::MODULE_INPUT_PORT);
/* Optional: If we have WLR port, we should add a read-back port */
if (!circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_WLR).empty()) {
BasicPort readback_port(std::string(DECODER_READBACK_PORT_NAME), config_protocol.num_regions());
module_manager.add_port(module_id, readback_port, ModuleManager::MODULE_INPUT_PORT);
}
break;
}
case BLWL_PROTOCOL_FLATTEN: {
/* Each region will have independent WLs */
for (const ConfigRegionId& config_region : module_manager.regions(module_id)) {
size_t wl_size = num_config_bits[config_region].second;
BasicPort wl_port(generate_regional_blwl_port_name(std::string(MEMORY_WL_PORT_NAME), config_region), wl_size);
module_manager.add_port(module_id, wl_port, ModuleManager::MODULE_INPUT_PORT);
/* Optional: If we have WLR port, we should add a read-back port */
if (!circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_WLR).empty()) {
BasicPort readback_port(std::string(MEMORY_WLR_PORT_NAME), wl_size);
module_manager.add_port(module_id, readback_port, ModuleManager::MODULE_INPUT_PORT);
}
}
break;
}
case BLWL_PROTOCOL_SHIFT_REGISTER: {
/* TODO */
break;
}
default: {
VTR_LOG_ERROR("Invalid WL protocol");
exit(1);
}
}
}
} /* end namespace openfpga */ } /* end namespace openfpga */

View File

@ -10,6 +10,7 @@
#include "vtr_vector.h" #include "vtr_vector.h"
#include "vtr_ndmatrix.h" #include "vtr_ndmatrix.h"
#include "module_manager.h" #include "module_manager.h"
#include "config_protocol.h"
#include "circuit_library.h" #include "circuit_library.h"
#include "decoder_library.h" #include "decoder_library.h"
#include "build_top_module_memory_utils.h" #include "build_top_module_memory_utils.h"
@ -25,9 +26,16 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma
DecoderLibrary& decoder_lib, DecoderLibrary& decoder_lib,
const ModuleId& top_module, const ModuleId& top_module,
const CircuitLibrary& circuit_lib, const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model, const ConfigProtocol& config_protocol,
const TopModuleNumConfigBits& num_config_bits); const TopModuleNumConfigBits& num_config_bits);
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 TopModuleNumConfigBits& num_config_bits);
} /* end namespace openfpga */ } /* end namespace openfpga */
#endif #endif

View File

@ -31,7 +31,7 @@ namespace openfpga {
***************************************************************************************/ ***************************************************************************************/
int write_fabric_key_to_xml_file(const ModuleManager& module_manager, int write_fabric_key_to_xml_file(const ModuleManager& module_manager,
const std::string& fname, const std::string& fname,
const e_config_protocol_type& config_protocol_type, const ConfigProtocol& config_protocol,
const bool& verbose) { const bool& verbose) {
std::string timer_message = std::string("Write fabric key to XML file '") + fname + std::string("'"); std::string timer_message = std::string("Write fabric key to XML file '") + fname + std::string("'");
@ -71,7 +71,7 @@ int write_fabric_key_to_xml_file(const ModuleManager& module_manager,
/* Each configuration protocol has some child which should not be in the list. They are typically decoders */ /* 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 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_type, curr_region_num_config_child); size_t num_child_to_skip = estimate_num_configurable_children_to_skip_by_config_protocol(config_protocol, curr_region_num_config_child);
curr_region_num_config_child -= num_child_to_skip; curr_region_num_config_child -= num_child_to_skip;
fabric_key.reserve_region_keys(fabric_region, curr_region_num_config_child); fabric_key.reserve_region_keys(fabric_region, curr_region_num_config_child);

View File

@ -4,8 +4,9 @@
/******************************************************************** /********************************************************************
* Include header files that are required by function declaration * Include header files that are required by function declaration
*******************************************************************/ *******************************************************************/
#include "vpr_context.h" #include <string.h>
#include "openfpga_context.h" #include "module_manager.h"
#include "config_protocol.h"
/******************************************************************** /********************************************************************
* Function declaration * Function declaration
@ -16,7 +17,7 @@ namespace openfpga {
int write_fabric_key_to_xml_file(const ModuleManager& module_manager, int write_fabric_key_to_xml_file(const ModuleManager& module_manager,
const std::string& fname, const std::string& fname,
const e_config_protocol_type& config_protocol_type, const ConfigProtocol& config_protocol,
const bool& verbose); const bool& verbose);
} /* end namespace openfpga */ } /* end namespace openfpga */

View File

@ -64,7 +64,7 @@ static
size_t rec_estimate_device_bitstream_num_bits(const ModuleManager& module_manager, size_t rec_estimate_device_bitstream_num_bits(const ModuleManager& module_manager,
const ModuleId& top_module, const ModuleId& top_module,
const ModuleId& parent_module, const ModuleId& parent_module,
const e_config_protocol_type& config_protocol_type) { const ConfigProtocol& config_protocol) {
size_t num_bits = 0; size_t num_bits = 0;
/* If a child module has no configurable children, this is a leaf node /* If a child module has no configurable children, this is a leaf node
@ -85,13 +85,13 @@ size_t rec_estimate_device_bitstream_num_bits(const ModuleManager& module_manage
if (parent_module == top_module) { if (parent_module == top_module) {
for (const ConfigRegionId& config_region : module_manager.regions(parent_module)) { for (const ConfigRegionId& config_region : module_manager.regions(parent_module)) {
size_t curr_region_num_config_child = module_manager.region_configurable_children(parent_module, config_region).size(); size_t curr_region_num_config_child = module_manager.region_configurable_children(parent_module, config_region).size();
size_t num_child_to_skip = estimate_num_configurable_children_to_skip_by_config_protocol(config_protocol_type, curr_region_num_config_child); size_t num_child_to_skip = estimate_num_configurable_children_to_skip_by_config_protocol(config_protocol, curr_region_num_config_child);
curr_region_num_config_child -= num_child_to_skip; curr_region_num_config_child -= num_child_to_skip;
/* Visit all the children in a recursively way */ /* Visit all the children in a recursively way */
for (size_t ichild = 0; ichild < curr_region_num_config_child; ++ichild) { for (size_t ichild = 0; ichild < curr_region_num_config_child; ++ichild) {
ModuleId child_module = module_manager.region_configurable_children(parent_module, config_region)[ichild]; ModuleId child_module = module_manager.region_configurable_children(parent_module, config_region)[ichild];
num_bits += rec_estimate_device_bitstream_num_bits(module_manager, top_module, child_module, config_protocol_type); num_bits += rec_estimate_device_bitstream_num_bits(module_manager, top_module, child_module, config_protocol);
} }
} }
} else { } else {
@ -102,14 +102,14 @@ size_t rec_estimate_device_bitstream_num_bits(const ModuleManager& module_manage
/* Frame-based configuration protocol will have 1 decoder /* Frame-based configuration protocol will have 1 decoder
* if there are more than 1 configurable children * if there are more than 1 configurable children
*/ */
if ( (CONFIG_MEM_FRAME_BASED == config_protocol_type) if ( (CONFIG_MEM_FRAME_BASED == config_protocol.type())
&& (2 <= num_configurable_children)) { && (2 <= num_configurable_children)) {
num_configurable_children--; num_configurable_children--;
} }
for (size_t ichild = 0; ichild < num_configurable_children; ++ichild) { for (size_t ichild = 0; ichild < num_configurable_children; ++ichild) {
ModuleId child_module = module_manager.configurable_children(parent_module)[ichild]; ModuleId child_module = module_manager.configurable_children(parent_module)[ichild];
num_bits += rec_estimate_device_bitstream_num_bits(module_manager, top_module, child_module, config_protocol_type); num_bits += rec_estimate_device_bitstream_num_bits(module_manager, top_module, child_module, config_protocol);
} }
} }
@ -157,7 +157,7 @@ BitstreamManager build_device_bitstream(const VprContext& vpr_ctx,
size_t num_bits_to_reserve = rec_estimate_device_bitstream_num_bits(openfpga_ctx.module_graph(), size_t num_bits_to_reserve = rec_estimate_device_bitstream_num_bits(openfpga_ctx.module_graph(),
top_module, top_module,
top_module, top_module,
openfpga_ctx.arch().config_protocol.type()); openfpga_ctx.arch().config_protocol);
bitstream_manager.reserve_bits(num_bits_to_reserve); bitstream_manager.reserve_bits(num_bits_to_reserve);
VTR_LOGV(verbose, "Reserved %lu configuration bits\n", num_bits_to_reserve); VTR_LOGV(verbose, "Reserved %lu configuration bits\n", num_bits_to_reserve);

View File

@ -19,6 +19,7 @@
#include "decoder_library_utils.h" #include "decoder_library_utils.h"
#include "bitstream_manager_utils.h" #include "bitstream_manager_utils.h"
#include "memory_utils.h"
#include "memory_bank_utils.h" #include "memory_bank_utils.h"
#include "build_fabric_bitstream_memory_bank.h" #include "build_fabric_bitstream_memory_bank.h"
@ -47,6 +48,7 @@ void rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(const B
const ModuleId& top_module, const ModuleId& top_module,
const ModuleId& parent_module, const ModuleId& parent_module,
const ConfigRegionId& config_region, const ConfigRegionId& config_region,
const ConfigProtocol& config_protocol,
const CircuitLibrary& circuit_lib, const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model, const CircuitModelId& sram_model,
const size_t& bl_addr_size, const size_t& bl_addr_size,
@ -72,7 +74,9 @@ void rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(const B
std::vector<ModuleId> configurable_children = module_manager.region_configurable_children(parent_module, config_region); std::vector<ModuleId> configurable_children = module_manager.region_configurable_children(parent_module, config_region);
VTR_ASSERT(2 <= configurable_children.size()); VTR_ASSERT(2 <= configurable_children.size());
size_t num_configurable_children = configurable_children.size() - 2; size_t num_config_child_to_skip = estimate_num_configurable_children_to_skip_by_config_protocol(config_protocol,
configurable_children.size());
size_t num_configurable_children = configurable_children.size() - num_config_child_to_skip;
/* Early exit if there is no configurable children */ /* Early exit if there is no configurable children */
if (0 == num_configurable_children) { if (0 == num_configurable_children) {
@ -101,6 +105,7 @@ void rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(const B
rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(bitstream_manager, child_block, rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(bitstream_manager, child_block,
module_manager, top_module, child_module, module_manager, top_module, child_module,
config_region, config_region,
config_protocol,
circuit_lib, sram_model, circuit_lib, sram_model,
bl_addr_size, wl_addr_size, bl_addr_size, wl_addr_size,
num_bls_cur_tile, bl_start_index_per_tile, num_bls_cur_tile, bl_start_index_per_tile,
@ -143,6 +148,7 @@ void rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(const B
rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(bitstream_manager, child_block, rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(bitstream_manager, child_block,
module_manager, top_module, child_module, module_manager, top_module, child_module,
config_region, config_region,
config_protocol,
circuit_lib, sram_model, circuit_lib, sram_model,
bl_addr_size, wl_addr_size, bl_addr_size, wl_addr_size,
num_bls_cur_tile, bl_start_index_per_tile, num_bls_cur_tile, bl_start_index_per_tile,
@ -166,19 +172,35 @@ void rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(const B
for (const ConfigBitId& config_bit : bitstream_manager.block_bits(parent_block)) { for (const ConfigBitId& config_bit : bitstream_manager.block_bits(parent_block)) {
FabricBitId fabric_bit = fabric_bitstream.add_bit(config_bit); FabricBitId fabric_bit = fabric_bitstream.add_bit(config_bit);
/* Find BL address */ /* The BL address to be decoded depends on the protocol
* - flatten BLs: use 1-hot decoding
* - BL decoders: fully encoded
* - Shift register: use 1-hot decoding
*/
size_t cur_bl_index = bl_start_index_per_tile.at(tile_coord.x()) + cur_mem_index[tile_coord] % num_bls_cur_tile; size_t cur_bl_index = bl_start_index_per_tile.at(tile_coord.x()) + cur_mem_index[tile_coord] % num_bls_cur_tile;
std::vector<char> bl_addr_bits_vec = itobin_charvec(cur_bl_index, bl_addr_size); std::vector<char> bl_addr_bits_vec;
if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) {
bl_addr_bits_vec = itobin_charvec(cur_bl_index, bl_addr_size);
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()
|| BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()) {
bl_addr_bits_vec = ito1hot_charvec(cur_bl_index, bl_addr_size);
}
/* Find WL address */ /* Find WL address */
size_t cur_wl_index = wl_start_index_per_tile.at(tile_coord.y()) + std::floor(cur_mem_index[tile_coord] / num_bls_cur_tile); size_t cur_wl_index = wl_start_index_per_tile.at(tile_coord.y()) + std::floor(cur_mem_index[tile_coord] / num_bls_cur_tile);
std::vector<char> wl_addr_bits_vec = itobin_charvec(cur_wl_index, wl_addr_size); std::vector<char> wl_addr_bits_vec;
if (BLWL_PROTOCOL_DECODER == config_protocol.wl_protocol_type()) {
wl_addr_bits_vec = itobin_charvec(cur_wl_index, wl_addr_size);
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()
|| BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type()) {
wl_addr_bits_vec = ito1hot_charvec(cur_wl_index, wl_addr_size);
}
/* Set BL address */ /* Set BL address */
fabric_bitstream.set_bit_bl_address(fabric_bit, bl_addr_bits_vec); fabric_bitstream.set_bit_bl_address(fabric_bit, bl_addr_bits_vec, BLWL_PROTOCOL_DECODER != config_protocol.bl_protocol_type());
/* Set WL address */ /* Set WL address */
fabric_bitstream.set_bit_wl_address(fabric_bit, wl_addr_bits_vec); fabric_bitstream.set_bit_wl_address(fabric_bit, wl_addr_bits_vec, BLWL_PROTOCOL_DECODER != config_protocol.wl_protocol_type());
/* Set data input */ /* Set data input */
fabric_bitstream.set_bit_din(fabric_bit, bitstream_manager.bit_value(config_bit)); fabric_bitstream.set_bit_din(fabric_bit, bitstream_manager.bit_value(config_bit));
@ -193,7 +215,7 @@ void rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(const B
/******************************************************************** /********************************************************************
* Main function to build a fabric-dependent bitstream * Main function to build a fabric-dependent bitstream
* by considering the configuration protocol types * by considering the QuickLogic memory banks
*******************************************************************/ *******************************************************************/
void build_module_fabric_dependent_bitstream_ql_memory_bank(const ConfigProtocol& config_protocol, void build_module_fabric_dependent_bitstream_ql_memory_bank(const ConfigProtocol& config_protocol,
const CircuitLibrary& circuit_lib, const CircuitLibrary& circuit_lib,
@ -205,13 +227,57 @@ void build_module_fabric_dependent_bitstream_ql_memory_bank(const ConfigProtocol
/* Ensure we are in the correct type of configuration protocol*/ /* Ensure we are in the correct type of configuration protocol*/
VTR_ASSERT(config_protocol.type() == CONFIG_MEM_QL_MEMORY_BANK); VTR_ASSERT(config_protocol.type() == CONFIG_MEM_QL_MEMORY_BANK);
/* Find global BL address port size */ /* For different BL control protocol, the address ports are different
ModulePortId bl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_BL_ADDRESS_PORT_NAME)); * - flatten BLs: the address port should be raw BL ports at top-level module.
BasicPort bl_addr_port_info = module_manager.module_port(top_module, bl_addr_port); * Due to each configuration region has separated BLs, the address port should be the one with largest size
* - BL decoders: the address port should be the BL address port at top-level module
* - Shift register: the address port size will be calculated by the total number of unique BLs per child module in each configuration region
* Due to each configuration region has separated BLs, the address port should be the one with largest size
*/
ModulePortId bl_addr_port;
BasicPort bl_addr_port_info;
if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) {
bl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_BL_ADDRESS_PORT_NAME));
bl_addr_port_info = module_manager.module_port(top_module, bl_addr_port);
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) {
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
ModulePortId temp_bl_addr_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_BL_PORT_NAME), config_region));
BasicPort temp_bl_addr_port_info = module_manager.module_port(top_module, temp_bl_addr_port);
if (!bl_addr_port || (temp_bl_addr_port_info.get_width() > bl_addr_port_info.get_width())) {
bl_addr_port = temp_bl_addr_port;
bl_addr_port_info = temp_bl_addr_port_info;
}
}
} else {
/* TODO */
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type());
}
/* Find global WL address port size */ /* For different WL control protocol, the address ports are different
ModulePortId wl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_WL_ADDRESS_PORT_NAME)); * - flatten WLs: the address port should be raw WL ports at top-level module.
BasicPort wl_addr_port_info = module_manager.module_port(top_module, wl_addr_port); * Due to each configuration region has separated WLs, the address port should be the one with largest size
* - WL decoders: the address port should be the WL address port at top-level module
* - Shift register: the address port size will be calculated by the total number of unique WLs per child module in each configuration region
* Due to each configuration region has separated WLs, the address port should be the one with largest size
*/
ModulePortId wl_addr_port;
BasicPort wl_addr_port_info;
if (BLWL_PROTOCOL_DECODER == config_protocol.wl_protocol_type()) {
wl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_WL_ADDRESS_PORT_NAME));
wl_addr_port_info = module_manager.module_port(top_module, wl_addr_port);
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()) {
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
ModulePortId temp_wl_addr_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_WL_PORT_NAME), config_region));
BasicPort temp_wl_addr_port_info = module_manager.module_port(top_module, temp_wl_addr_port);
if (!wl_addr_port || (temp_wl_addr_port_info.get_width() > wl_addr_port_info.get_width())) {
wl_addr_port = temp_wl_addr_port;
wl_addr_port_info = temp_wl_addr_port_info;
}
}
} else {
/* TODO */
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type());
}
/* Reserve bits before build-up */ /* Reserve bits before build-up */
fabric_bitstream.set_use_address(true); fabric_bitstream.set_use_address(true);
@ -225,18 +291,33 @@ void build_module_fabric_dependent_bitstream_ql_memory_bank(const ConfigProtocol
/* Find port information for local BL and WL decoder in this region */ /* Find port information for local BL and WL decoder in this region */
std::vector<ModuleId> configurable_children = module_manager.region_configurable_children(top_module, config_region); std::vector<ModuleId> configurable_children = module_manager.region_configurable_children(top_module, config_region);
VTR_ASSERT(2 <= configurable_children.size()); VTR_ASSERT(2 <= configurable_children.size());
ModuleId bl_decoder_module = configurable_children[configurable_children.size() - 2];
ModuleId wl_decoder_module = configurable_children[configurable_children.size() - 1];
ModulePortId bl_port = module_manager.find_module_port(bl_decoder_module, std::string(DECODER_DATA_OUT_PORT_NAME));
BasicPort bl_port_info = module_manager.module_port(bl_decoder_module, bl_port);
ModulePortId wl_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_DATA_OUT_PORT_NAME));
BasicPort wl_port_info = module_manager.module_port(wl_decoder_module, wl_port);
/* Build the bitstream for all the blocks in this region */ /* Build the bitstream for all the blocks in this region */
FabricBitRegionId fabric_bitstream_region = fabric_bitstream.add_region(); FabricBitRegionId fabric_bitstream_region = fabric_bitstream.add_region();
/* Find the BL/WL port (different region may have different sizes of BL/WLs) */
ModulePortId cur_bl_addr_port;
if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) {
cur_bl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_BL_ADDRESS_PORT_NAME));
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) {
cur_bl_addr_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_BL_PORT_NAME), config_region));
} else {
/* TODO */
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type());
}
BasicPort cur_bl_addr_port_info = module_manager.module_port(top_module, cur_bl_addr_port);
ModulePortId cur_wl_addr_port;
if (BLWL_PROTOCOL_DECODER == config_protocol.wl_protocol_type()) {
cur_wl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_WL_ADDRESS_PORT_NAME));
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()) {
cur_wl_addr_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_WL_PORT_NAME), config_region));
} else {
/* TODO */
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type());
}
BasicPort cur_wl_addr_port_info = module_manager.module_port(top_module, cur_wl_addr_port);
/************************************************************** /**************************************************************
* Precompute the BLs and WLs distribution across the FPGA fabric * 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 * The distribution is a matrix which contains the starting index of BL/WL for each column or row
@ -262,9 +343,10 @@ void build_module_fabric_dependent_bitstream_ql_memory_bank(const ConfigProtocol
rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(bitstream_manager, top_block, rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(bitstream_manager, top_block,
module_manager, top_module, top_module, module_manager, top_module, top_module,
config_region, config_region,
config_protocol,
circuit_lib, config_protocol.memory_model(), circuit_lib, config_protocol.memory_model(),
bl_addr_port_info.get_width(), cur_bl_addr_port_info.get_width(),
wl_addr_port_info.get_width(), cur_wl_addr_port_info.get_width(),
temp_num_bls_cur_tile, bl_start_index_per_tile, temp_num_bls_cur_tile, bl_start_index_per_tile,
temp_num_wls_cur_tile, wl_start_index_per_tile, temp_num_wls_cur_tile, wl_start_index_per_tile,
temp_coord, temp_coord,

View File

@ -139,24 +139,35 @@ FabricBitId FabricBitstream::add_bit(const ConfigBitId& config_bit_id) {
} }
void FabricBitstream::set_bit_address(const FabricBitId& bit_id, void FabricBitstream::set_bit_address(const FabricBitId& bit_id,
const std::vector<char>& address) { const std::vector<char>& address,
const bool& tolerant_short_address) {
VTR_ASSERT(true == valid_bit_id(bit_id)); VTR_ASSERT(true == valid_bit_id(bit_id));
VTR_ASSERT(true == use_address_); VTR_ASSERT(true == use_address_);
if (tolerant_short_address) {
VTR_ASSERT(address_length_ >= address.size());
} else {
VTR_ASSERT(address_length_ == address.size()); VTR_ASSERT(address_length_ == address.size());
}
bit_addresses_[bit_id] = address; bit_addresses_[bit_id] = address;
} }
void FabricBitstream::set_bit_bl_address(const FabricBitId& bit_id, void FabricBitstream::set_bit_bl_address(const FabricBitId& bit_id,
const std::vector<char>& address) { const std::vector<char>& address,
set_bit_address(bit_id, address); const bool& tolerant_short_address) {
set_bit_address(bit_id, address, tolerant_short_address);
} }
void FabricBitstream::set_bit_wl_address(const FabricBitId& bit_id, void FabricBitstream::set_bit_wl_address(const FabricBitId& bit_id,
const std::vector<char>& address) { const std::vector<char>& address,
const bool& tolerant_short_address) {
VTR_ASSERT(true == valid_bit_id(bit_id)); VTR_ASSERT(true == valid_bit_id(bit_id));
VTR_ASSERT(true == use_address_); VTR_ASSERT(true == use_address_);
VTR_ASSERT(true == use_wl_address_); VTR_ASSERT(true == use_wl_address_);
if (tolerant_short_address) {
VTR_ASSERT(wl_address_length_ >= address.size());
} else {
VTR_ASSERT(wl_address_length_ == address.size()); VTR_ASSERT(wl_address_length_ == address.size());
}
bit_wl_addresses_[bit_id] = address; bit_wl_addresses_[bit_id] = address;
} }

View File

@ -135,13 +135,16 @@ class FabricBitstream {
FabricBitId add_bit(const ConfigBitId& config_bit_id); FabricBitId add_bit(const ConfigBitId& config_bit_id);
void set_bit_address(const FabricBitId& bit_id, void set_bit_address(const FabricBitId& bit_id,
const std::vector<char>& address); const std::vector<char>& address,
const bool& tolerant_short_address = false);
void set_bit_bl_address(const FabricBitId& bit_id, void set_bit_bl_address(const FabricBitId& bit_id,
const std::vector<char>& address); const std::vector<char>& address,
const bool& tolerant_short_address = false);
void set_bit_wl_address(const FabricBitId& bit_id, void set_bit_wl_address(const FabricBitId& bit_id,
const std::vector<char>& address); const std::vector<char>& address,
const bool& tolerant_short_address = false);
void set_bit_din(const FabricBitId& bit_id, void set_bit_din(const FabricBitId& bit_id,
const char& din); const char& din);

View File

@ -180,6 +180,56 @@ int write_memory_bank_fabric_bitstream_to_text_file(std::fstream& fp,
return status; return status;
} }
/********************************************************************
* Write the fabric bitstream fitting a memory bank protocol
* to a plain text file
*
* Return:
* - 0 if succeed
* - 1 if critical errors occured
*******************************************************************/
static
int write_memory_bank_flatten_fabric_bitstream_to_text_file(std::fstream& fp,
const bool& bit_value_to_skip,
const FabricBitstream& fabric_bitstream) {
int status = 0;
MemoryBankFlattenFabricBitstream fabric_bits = build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, bit_value_to_skip);
/* The address sizes and data input sizes are the same across any element,
* just get it from the 1st element to save runtime
*/
size_t bl_addr_size = 0;
for (const auto& bl_vec : fabric_bits.begin()->second) {
bl_addr_size += bl_vec.size();
}
size_t wl_addr_size = 0;
for (const auto& wl_vec : fabric_bits.begin()->first) {
wl_addr_size += wl_vec.size();
}
/* Output information about how to intepret the bitstream */
fp << "// Bitstream length: " << fabric_bits.size() << std::endl;
fp << "// Bitstream width (LSB -> MSB): ";
fp << "<bl_address " << bl_addr_size << " bits>";
fp << "<wl_address " << wl_addr_size << " bits>";
fp << std::endl;
for (const auto& addr_pair : fabric_bits) {
/* Write BL address code */
for (const auto& bl_vec : addr_pair.second) {
fp << bl_vec;
}
/* Write WL address code */
for (const auto& wl_vec : addr_pair.first) {
fp << wl_vec;
}
fp << std::endl;
}
return status;
}
/******************************************************************** /********************************************************************
* Write the fabric bitstream fitting a frame-based protocol * Write the fabric bitstream fitting a frame-based protocol
* to a plain text file * to a plain text file
@ -306,7 +356,28 @@ int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manage
bitstream_manager, bitstream_manager,
fabric_bitstream); fabric_bitstream);
break; break;
case CONFIG_MEM_QL_MEMORY_BANK: case CONFIG_MEM_QL_MEMORY_BANK: {
/* Bitstream organization depends on the BL/WL protocols
* - If BL uses decoders, we have to config each memory cell one by one.
* - If BL uses flatten, we can configure all the memory cells on the same row by enabling dedicated WL
* In such case, we will merge the BL data under the same WL address
* Fast configuration is NOT applicable in this case
* - if BL uses shift-register, TODO
*/
if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) {
status = write_memory_bank_fabric_bitstream_to_text_file(fp,
apply_fast_configuration,
bit_value_to_skip,
fabric_bitstream);
} else {
VTR_ASSERT(BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()
|| BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type());
status = write_memory_bank_flatten_fabric_bitstream_to_text_file(fp,
bit_value_to_skip,
fabric_bitstream);
}
break;
}
case CONFIG_MEM_MEMORY_BANK: case CONFIG_MEM_MEMORY_BANK:
status = write_memory_bank_fabric_bitstream_to_text_file(fp, status = write_memory_bank_fabric_bitstream_to_text_file(fp,
apply_fast_configuration, apply_fast_configuration,

View File

@ -229,6 +229,8 @@ void print_verilog_top_testbench_config_protocol_port(std::fstream& fp,
print_verilog_top_testbench_config_chain_port(fp, module_manager, top_module); print_verilog_top_testbench_config_chain_port(fp, module_manager, top_module);
break; break;
case CONFIG_MEM_QL_MEMORY_BANK: case CONFIG_MEM_QL_MEMORY_BANK:
print_verilog_top_testbench_ql_memory_bank_port(fp, module_manager, top_module, config_protocol);
break;
case CONFIG_MEM_MEMORY_BANK: case CONFIG_MEM_MEMORY_BANK:
print_verilog_top_testbench_memory_bank_port(fp, module_manager, top_module); print_verilog_top_testbench_memory_bank_port(fp, module_manager, top_module);
break; break;
@ -808,7 +810,7 @@ void print_verilog_top_testbench_ports(std::fstream& fp,
* Note that this will not applicable to configuration chain!!! * Note that this will not applicable to configuration chain!!!
*******************************************************************/ *******************************************************************/
static static
size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz_type, size_t calculate_num_config_clock_cycles(const ConfigProtocol& config_protocol,
const bool& fast_configuration, const bool& fast_configuration,
const bool& bit_value_to_skip, const bool& bit_value_to_skip,
const BitstreamManager& bitstream_manager, const BitstreamManager& bitstream_manager,
@ -819,7 +821,7 @@ size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz
size_t num_config_clock_cycles = 1 + regional_bitstream_max_size; size_t num_config_clock_cycles = 1 + regional_bitstream_max_size;
/* Branch on the type of configuration protocol */ /* Branch on the type of configuration protocol */
switch (sram_orgz_type) { switch (config_protocol.type()) {
case CONFIG_MEM_STANDALONE: case CONFIG_MEM_STANDALONE:
/* We just need 1 clock cycle to load all the configuration bits /* We just need 1 clock cycle to load all the configuration bits
* since all the ports are exposed at the top-level * since all the ports are exposed at the top-level
@ -847,7 +849,25 @@ size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz
100. * ((float)num_config_clock_cycles / (float)(1 + regional_bitstream_max_size) - 1.)); 100. * ((float)num_config_clock_cycles / (float)(1 + regional_bitstream_max_size) - 1.));
} }
break; break;
case CONFIG_MEM_QL_MEMORY_BANK: case CONFIG_MEM_QL_MEMORY_BANK: {
if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) {
/* For fast configuration, we will skip all the zero data points */
num_config_clock_cycles = 1 + build_memory_bank_fabric_bitstream_by_address(fabric_bitstream).size();
if (true == fast_configuration) {
size_t full_num_config_clock_cycles = num_config_clock_cycles;
num_config_clock_cycles = 1 + find_memory_bank_fast_configuration_fabric_bitstream_size(fabric_bitstream, bit_value_to_skip);
VTR_LOG("Fast configuration reduces number of configuration clock cycles from %lu to %lu (compression_rate = %f%)\n",
full_num_config_clock_cycles,
num_config_clock_cycles,
100. * ((float)num_config_clock_cycles / (float)full_num_config_clock_cycles - 1.));
}
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) {
num_config_clock_cycles = 1 + build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, bit_value_to_skip).size();
} else if (BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()) {
/* TODO */
}
break;
}
case CONFIG_MEM_MEMORY_BANK: { case CONFIG_MEM_MEMORY_BANK: {
/* For fast configuration, we will skip all the zero data points */ /* For fast configuration, we will skip all the zero data points */
num_config_clock_cycles = 1 + build_memory_bank_fabric_bitstream_by_address(fabric_bitstream).size(); num_config_clock_cycles = 1 + build_memory_bank_fabric_bitstream_by_address(fabric_bitstream).size();
@ -1111,7 +1131,10 @@ void print_verilog_top_testbench_configuration_protocol_stimulus(std::fstream& f
case CONFIG_MEM_FRAME_BASED: { case CONFIG_MEM_FRAME_BASED: {
ModulePortId en_port_id = module_manager.find_module_port(top_module, ModulePortId en_port_id = module_manager.find_module_port(top_module,
std::string(DECODER_ENABLE_PORT_NAME)); std::string(DECODER_ENABLE_PORT_NAME));
BasicPort en_port = module_manager.module_port(top_module, en_port_id); BasicPort en_port(std::string(DECODER_ENABLE_PORT_NAME), 1);
if (en_port_id) {
en_port = module_manager.module_port(top_module, en_port_id);
}
BasicPort en_register_port(std::string(en_port.get_name() + std::string(TOP_TB_CLOCK_REG_POSTFIX)), 1); BasicPort en_register_port(std::string(en_port.get_name() + std::string(TOP_TB_CLOCK_REG_POSTFIX)), 1);
print_verilog_comment(fp, std::string("---- Generate enable signal waveform -----")); print_verilog_comment(fp, std::string("---- Generate enable signal waveform -----"));
print_verilog_shifted_clock_stimuli(fp, en_register_port, print_verilog_shifted_clock_stimuli(fp, en_register_port,
@ -1684,7 +1707,7 @@ void print_verilog_full_testbench_frame_decoder_bitstream(std::fstream& fp,
static static
void print_verilog_full_testbench_bitstream(std::fstream& fp, void print_verilog_full_testbench_bitstream(std::fstream& fp,
const std::string& bitstream_file, const std::string& bitstream_file,
const e_config_protocol_type& config_protocol_type, const ConfigProtocol& config_protocol,
const bool& fast_configuration, const bool& fast_configuration,
const bool& bit_value_to_skip, const bool& bit_value_to_skip,
const ModuleManager& module_manager, const ModuleManager& module_manager,
@ -1693,7 +1716,7 @@ void print_verilog_full_testbench_bitstream(std::fstream& fp,
const FabricBitstream& fabric_bitstream) { const FabricBitstream& fabric_bitstream) {
/* Branch on the type of configuration protocol */ /* Branch on the type of configuration protocol */
switch (config_protocol_type) { switch (config_protocol.type()) {
case CONFIG_MEM_STANDALONE: case CONFIG_MEM_STANDALONE:
print_verilog_full_testbench_vanilla_bitstream(fp, print_verilog_full_testbench_vanilla_bitstream(fp,
bitstream_file, bitstream_file,
@ -1719,6 +1742,7 @@ void print_verilog_full_testbench_bitstream(std::fstream& fp,
break; break;
case CONFIG_MEM_QL_MEMORY_BANK: case CONFIG_MEM_QL_MEMORY_BANK:
print_verilog_full_testbench_ql_memory_bank_bitstream(fp, bitstream_file, print_verilog_full_testbench_ql_memory_bank_bitstream(fp, bitstream_file,
config_protocol,
fast_configuration, fast_configuration,
bit_value_to_skip, bit_value_to_skip,
module_manager, top_module, module_manager, top_module,
@ -1916,7 +1940,7 @@ int print_verilog_full_testbench(const ModuleManager& module_manager,
} }
/* Estimate the number of configuration clock cycles */ /* Estimate the number of configuration clock cycles */
size_t num_config_clock_cycles = calculate_num_config_clock_cycles(config_protocol.type(), size_t num_config_clock_cycles = calculate_num_config_clock_cycles(config_protocol,
apply_fast_configuration, apply_fast_configuration,
bit_value_to_skip, bit_value_to_skip,
bitstream_manager, bitstream_manager,
@ -1998,7 +2022,7 @@ int print_verilog_full_testbench(const ModuleManager& module_manager,
/* load bitstream to FPGA fabric in a configuration phase */ /* load bitstream to FPGA fabric in a configuration phase */
print_verilog_full_testbench_bitstream(fp, print_verilog_full_testbench_bitstream(fp,
bitstream_file, bitstream_file,
config_protocol.type(), config_protocol,
apply_fast_configuration, apply_fast_configuration,
bit_value_to_skip, bit_value_to_skip,
module_manager, top_module, module_manager, top_module,

View File

@ -36,7 +36,258 @@
/* begin namespace openfpga */ /* begin namespace openfpga */
namespace openfpga { namespace openfpga {
void print_verilog_full_testbench_ql_memory_bank_bitstream(std::fstream& fp, void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module,
const ConfigProtocol& config_protocol) {
/* Validate the file stream */
valid_file_stream(fp);
/* Print the address port for the Bit-Line decoder here */
if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) {
print_verilog_comment(fp, std::string("---- Address port for Bit-Line decoder -----"));
ModulePortId bl_addr_port_id = module_manager.find_module_port(top_module,
std::string(DECODER_BL_ADDRESS_PORT_NAME));
BasicPort bl_addr_port = module_manager.module_port(top_module, bl_addr_port_id);
fp << generate_verilog_port(VERILOG_PORT_REG, bl_addr_port) << ";" << std::endl;
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) {
print_verilog_comment(fp, std::string("---- Bit-Line ports -----"));
for (const ConfigRegionId& region : module_manager.regions(top_module)) {
ModulePortId bl_port_id = module_manager.find_module_port(top_module,
generate_regional_blwl_port_name(std::string(MEMORY_BL_PORT_NAME), region));
BasicPort bl_port = module_manager.module_port(top_module, bl_port_id);
fp << generate_verilog_port(VERILOG_PORT_REG, bl_port) << ";" << std::endl;
}
} else {
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type());
/* TODO */
}
/* Print the address port for the Word-Line decoder here */
if (BLWL_PROTOCOL_DECODER == config_protocol.wl_protocol_type()) {
print_verilog_comment(fp, std::string("---- Address port for Word-Line decoder -----"));
ModulePortId wl_addr_port_id = module_manager.find_module_port(top_module,
std::string(DECODER_WL_ADDRESS_PORT_NAME));
BasicPort wl_addr_port = module_manager.module_port(top_module, wl_addr_port_id);
fp << generate_verilog_port(VERILOG_PORT_REG, wl_addr_port) << ";" << std::endl;
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()) {
print_verilog_comment(fp, std::string("---- Word-Line ports -----"));
for (const ConfigRegionId& region : module_manager.regions(top_module)) {
ModulePortId wl_port_id = module_manager.find_module_port(top_module,
generate_regional_blwl_port_name(std::string(MEMORY_WL_PORT_NAME), region));
BasicPort wl_port = module_manager.module_port(top_module, wl_port_id);
fp << generate_verilog_port(VERILOG_PORT_REG, wl_port) << ";" << std::endl;
}
} else {
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type());
/* TODO */
}
/* Print the data-input port: only available when BL has a decoder */
if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) {
print_verilog_comment(fp, std::string("---- Data input port for memory decoders -----"));
ModulePortId din_port_id = module_manager.find_module_port(top_module,
std::string(DECODER_DATA_IN_PORT_NAME));
BasicPort din_port = module_manager.module_port(top_module, din_port_id);
fp << generate_verilog_port(VERILOG_PORT_REG, din_port) << ";" << std::endl;
}
/* Print the optional readback port for the decoder here */
if (BLWL_PROTOCOL_DECODER == config_protocol.wl_protocol_type()) {
print_verilog_comment(fp, std::string("---- Readback port for memory decoders -----"));
ModulePortId readback_port_id = module_manager.find_module_port(top_module,
std::string(DECODER_READBACK_PORT_NAME));
if (readback_port_id) {
BasicPort readback_port = module_manager.module_port(top_module, readback_port_id);
fp << generate_verilog_port(VERILOG_PORT_WIRE, readback_port) << ";" << std::endl;
/* Disable readback in full testbenches */
print_verilog_wire_constant_values(fp, readback_port, std::vector<size_t>(readback_port.get_width(), 0));
}
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()) {
print_verilog_comment(fp, std::string("---- Word line read ports -----"));
for (const ConfigRegionId& region : module_manager.regions(top_module)) {
ModulePortId wlr_port_id = module_manager.find_module_port(top_module,
generate_regional_blwl_port_name(std::string(MEMORY_WLR_PORT_NAME), region));
if (wlr_port_id) {
BasicPort wlr_port = module_manager.module_port(top_module, wlr_port_id);
fp << generate_verilog_port(VERILOG_PORT_WIRE, wlr_port) << ";" << std::endl;
/* Disable readback in full testbenches */
print_verilog_wire_constant_values(fp, wlr_port, std::vector<size_t>(wlr_port.get_width(), 0));
}
}
}
/* Generate enable signal waveform here:
* which is a 90 degree phase shift than the programming clock
*/
print_verilog_comment(fp, std::string("---- Wire enable port of memory decoders -----"));
ModulePortId en_port_id = module_manager.find_module_port(top_module,
std::string(DECODER_ENABLE_PORT_NAME));
BasicPort en_port(std::string(DECODER_ENABLE_PORT_NAME), 1);
if (en_port_id) {
en_port = module_manager.module_port(top_module, en_port_id);
}
BasicPort en_register_port(std::string(en_port.get_name() + std::string(TOP_TB_CLOCK_REG_POSTFIX)), 1);
BasicPort config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1);
fp << generate_verilog_port(VERILOG_PORT_WIRE, en_port) << ";" << std::endl;
fp << generate_verilog_port(VERILOG_PORT_REG, en_register_port) << ";" << std::endl;
write_tab_to_file(fp, 1);
fp << "assign ";
fp << generate_verilog_port(VERILOG_PORT_CONKT, en_port);
fp << "= ";
fp << "~" << generate_verilog_port(VERILOG_PORT_CONKT, en_register_port);
fp << " & ";
fp << "~" << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port);
fp << ";" << std::endl;
}
/* Verilog codes to load bitstream from a bit file for memory bank using flatten BL/WLs */
static
void print_verilog_full_testbench_ql_memory_bank_flatten_bitstream(std::fstream& fp,
const std::string& bitstream_file,
const bool& fast_configuration,
const bool& bit_value_to_skip,
const ModuleManager& module_manager,
const ModuleId& top_module,
const FabricBitstream& fabric_bitstream) {
/* Validate the file stream */
valid_file_stream(fp);
/* No fast configuration available in this configuration protocol. Give a warning */
if (true == fast_configuration) {
VTR_LOG_WARN("Fast configuration is not available for flatten BL protocol");
}
/* Reorganize the fabric bitstream by the same address across regions */
MemoryBankFlattenFabricBitstream fabric_bits_by_addr = build_memory_bank_flatten_fabric_bitstream(fabric_bitstream,
bit_value_to_skip);
/* Feed address and data input pair one by one
* Note: the first cycle is reserved for programming reset
* We should give dummy values
*/
std::vector<BasicPort> bl_ports;
for (const ConfigRegionId& region : module_manager.regions(top_module)) {
ModulePortId cur_bl_port_id = module_manager.find_module_port(top_module,
generate_regional_blwl_port_name(std::string(MEMORY_BL_PORT_NAME), region));
bl_ports.push_back(module_manager.module_port(top_module, cur_bl_port_id));
}
std::vector<BasicPort> wl_ports;
for (const ConfigRegionId& region : module_manager.regions(top_module)) {
ModulePortId cur_wl_port_id = module_manager.find_module_port(top_module,
generate_regional_blwl_port_name(std::string(MEMORY_WL_PORT_NAME), region));
wl_ports.push_back(module_manager.module_port(top_module, cur_wl_port_id));
}
/* Calculate the total size of BL/WL ports */
size_t bl_port_width = 0;
for (const BasicPort& bl_port : bl_ports) {
bl_port_width += bl_port.get_width();
}
size_t wl_port_width = 0;
for (const BasicPort& wl_port : wl_ports) {
wl_port_width += wl_port.get_width();
}
std::vector<size_t> initial_bl_values(bl_port_width, 0);
std::vector<size_t> initial_wl_values(wl_port_width, 0);
/* Define a constant for the bitstream length */
print_verilog_define_flag(fp, std::string(TOP_TB_BITSTREAM_LENGTH_VARIABLE), fabric_bits_by_addr.size());
print_verilog_define_flag(fp, std::string(TOP_TB_BITSTREAM_WIDTH_VARIABLE), bl_port_width + wl_port_width);
/* Declare local variables for bitstream loading in Verilog */
print_verilog_comment(fp, "----- Virtual memory to store the bitstream from external file -----");
fp << "reg [0:`" << TOP_TB_BITSTREAM_WIDTH_VARIABLE << " - 1] ";
fp << TOP_TB_BITSTREAM_MEM_REG_NAME << "[0:`" << TOP_TB_BITSTREAM_LENGTH_VARIABLE << " - 1];";
fp << std::endl;
fp << "reg [$clog2(`" << TOP_TB_BITSTREAM_LENGTH_VARIABLE << "):0] " << TOP_TB_BITSTREAM_INDEX_REG_NAME << ";" << std::endl;
print_verilog_comment(fp, "----- Preload bitstream file to a virtual memory -----");
fp << "initial begin" << std::endl;
fp << "\t";
fp << "$readmemb(\"" << bitstream_file << "\", " << TOP_TB_BITSTREAM_MEM_REG_NAME << ");";
fp << std::endl;
print_verilog_comment(fp, "----- Bit-Line Address port default input -----");
fp << "\t";
fp << generate_verilog_ports_constant_values(bl_ports, initial_bl_values);
fp << ";";
fp << std::endl;
print_verilog_comment(fp, "----- Word-Line Address port default input -----");
fp << "\t";
fp << generate_verilog_ports_constant_values(wl_ports, initial_wl_values);
fp << ";";
fp << std::endl;
fp << "\t";
fp << TOP_TB_BITSTREAM_INDEX_REG_NAME << " <= 0";
fp << ";";
fp << std::endl;
fp << "end";
fp << std::endl;
print_verilog_comment(fp, "----- Begin bitstream loading during configuration phase -----");
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME) + std::string(TOP_TB_CLOCK_REG_POSTFIX), 1);
fp << "always";
fp << " @(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ")";
fp << " begin";
fp << std::endl;
fp << "\t";
fp << "if (";
fp << TOP_TB_BITSTREAM_INDEX_REG_NAME;
fp << " >= ";
fp << "`" << TOP_TB_BITSTREAM_LENGTH_VARIABLE;
fp << ") begin";
fp << std::endl;
BasicPort config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1);
fp << "\t\t";
std::vector<size_t> config_done_final_values(config_done_port.get_width(), 1);
fp << generate_verilog_port_constant_values(config_done_port, config_done_final_values, true);
fp << ";" << std::endl;
fp << "\t";
fp << "end else begin";
fp << std::endl;
std::vector<BasicPort> blwl_ports = bl_ports;
blwl_ports.insert(blwl_ports.end(), wl_ports.begin(), wl_ports.end());
fp << "\t\t";
fp << generate_verilog_ports(blwl_ports);
fp << " <= ";
fp << TOP_TB_BITSTREAM_MEM_REG_NAME << "[" << TOP_TB_BITSTREAM_INDEX_REG_NAME << "]";
fp << ";" << std::endl;
fp << "\t\t";
fp << TOP_TB_BITSTREAM_INDEX_REG_NAME;
fp << " <= ";
fp << TOP_TB_BITSTREAM_INDEX_REG_NAME << " + 1";
fp << ";" << std::endl;
fp << "\t";
fp << "end";
fp << std::endl;
fp << "end";
fp << std::endl;
print_verilog_comment(fp, "----- End bitstream loading during configuration phase -----");
}
/* Verilog codes to load bitstream from a bit file for memory bank using BL/WL decoders */
static
void print_verilog_full_testbench_ql_memory_bank_decoder_bitstream(std::fstream& fp,
const std::string& bitstream_file, const std::string& bitstream_file,
const bool& fast_configuration, const bool& fast_configuration,
const bool& bit_value_to_skip, const bool& bit_value_to_skip,
@ -172,4 +423,29 @@ void print_verilog_full_testbench_ql_memory_bank_bitstream(std::fstream& fp,
print_verilog_comment(fp, "----- End bitstream loading during configuration phase -----"); print_verilog_comment(fp, "----- End bitstream loading during configuration phase -----");
} }
void print_verilog_full_testbench_ql_memory_bank_bitstream(std::fstream& fp,
const std::string& bitstream_file,
const ConfigProtocol& config_protocol,
const bool& fast_configuration,
const bool& bit_value_to_skip,
const ModuleManager& module_manager,
const ModuleId& top_module,
const FabricBitstream& fabric_bitstream) {
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,
fast_configuration,
bit_value_to_skip,
module_manager, top_module,
fabric_bitstream);
} else if ( (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type())
&& (BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()) ) {
print_verilog_full_testbench_ql_memory_bank_flatten_bitstream(fp, bitstream_file,
fast_configuration,
bit_value_to_skip,
module_manager, top_module,
fabric_bitstream);
}
}
} /* end namespace openfpga */ } /* end namespace openfpga */

View File

@ -26,12 +26,21 @@
/* begin namespace openfpga */ /* begin namespace openfpga */
namespace openfpga { namespace openfpga {
/**
* @brief Print local wires for memory bank configuration protocols
*/
void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp,
const ModuleManager& module_manager,
const ModuleId& top_module,
const ConfigProtocol& config_protocol);
/** /**
* @brief Print stimulus for a FPGA fabric with a memory bank configuration protocol * @brief Print stimulus for a FPGA fabric with a memory bank configuration protocol
* where configuration bits are programming in serial (one by one) * where configuration bits are programming in serial (one by one)
*/ */
void print_verilog_full_testbench_ql_memory_bank_bitstream(std::fstream& fp, void print_verilog_full_testbench_ql_memory_bank_bitstream(std::fstream& fp,
const std::string& bitstream_file, const std::string& bitstream_file,
const ConfigProtocol& config_protocol,
const bool& fast_configuration, const bool& fast_configuration,
const bool& bit_value_to_skip, const bool& bit_value_to_skip,
const ModuleManager& module_manager, const ModuleManager& module_manager,

View File

@ -721,7 +721,7 @@ std::string generate_verilog_constant_values(const std::vector<size_t>& const_va
} }
/******************************************************************** /********************************************************************
* Generate a verilog port with a deposite of constant values * Generate a verilog port with a deposit of constant values
********************************************************************/ ********************************************************************/
std::string generate_verilog_port_constant_values(const BasicPort& output_port, std::string generate_verilog_port_constant_values(const BasicPort& output_port,
const std::vector<size_t>& const_values, const std::vector<size_t>& const_values,
@ -742,6 +742,32 @@ std::string generate_verilog_port_constant_values(const BasicPort& output_port,
return port_str; return port_str;
} }
/********************************************************************
* Generate a list of verilog ports with a deposit of constant values
********************************************************************/
std::string generate_verilog_ports_constant_values(const std::vector<BasicPort>& output_ports,
const std::vector<size_t>& const_values,
const bool& is_register) {
std::string port_str;
/* Must check: the port width matches */
size_t total_width = 0;
for (const BasicPort& port : output_ports) {
total_width += port.get_width();
}
VTR_ASSERT( const_values.size() == total_width );
port_str = generate_verilog_ports(output_ports);
if (is_register) {
port_str += " <= ";
} else {
VTR_ASSERT_SAFE(!is_register);
port_str += " = ";
}
port_str += generate_verilog_constant_values(const_values);
return port_str;
}
/******************************************************************** /********************************************************************
* Generate a wire connection, that assigns constant values to a * Generate a wire connection, that assigns constant values to a
* Verilog port * Verilog port

View File

@ -111,6 +111,10 @@ std::string generate_verilog_port_constant_values(const BasicPort& output_port,
const std::vector<size_t>& const_values, const std::vector<size_t>& const_values,
const bool& is_register = false); const bool& is_register = false);
std::string generate_verilog_ports_constant_values(const std::vector<BasicPort>& output_ports,
const std::vector<size_t>& const_values,
const bool& is_register = false);
void print_verilog_wire_constant_values(std::fstream& fp, void print_verilog_wire_constant_values(std::fstream& fp,
const BasicPort& output_port, const BasicPort& output_port,
const std::vector<size_t>& const_values); const std::vector<size_t>& const_values);

View File

@ -280,22 +280,50 @@ std::vector<std::string> find_circuit_library_unique_spice_netlists(const Circui
* Advanced check if the circuit model of configurable memory * Advanced check if the circuit model of configurable memory
* satisfy the needs of configuration protocol * satisfy the needs of configuration protocol
* - Configuration chain -based: we check if we have a CCFF model * - Configuration chain -based: we check if we have a CCFF model
* - Frame -based: we check if we have a SRAM model which has BL and WL * - Flatten/Frame -based: we check if we have a SRAM model which has BL and WL
* * - Memory bank: we check if we have a SRAM model. Also we need to check if we have valid CCFF models for BL/WL models (if selected)
***********************************************************************/ ***********************************************************************/
bool check_configurable_memory_circuit_model(const e_config_protocol_type& config_protocol_type, bool check_configurable_memory_circuit_model(const ConfigProtocol& config_protocol,
const CircuitLibrary& circuit_lib, const CircuitLibrary& circuit_lib) {
const CircuitModelId& config_mem_circuit_model) {
size_t num_err = 0; size_t num_err = 0;
CircuitModelId config_mem_circuit_model = config_protocol.memory_model();
switch (config_protocol_type) { switch (config_protocol.type()) {
case CONFIG_MEM_SCAN_CHAIN: case CONFIG_MEM_SCAN_CHAIN:
num_err = check_ccff_circuit_model_ports(circuit_lib, num_err = check_ccff_circuit_model_ports(circuit_lib,
config_mem_circuit_model); config_mem_circuit_model);
break; break;
case CONFIG_MEM_QL_MEMORY_BANK: {
num_err = check_sram_circuit_model_ports(circuit_lib,
config_mem_circuit_model,
true);
/* Check circuit model for BL protocol */
CircuitModelId bl_memory_model = config_protocol.bl_memory_model();
if ( BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()
&& CircuitModelId::INVALID() == bl_memory_model) {
VTR_LOG_ERROR("Expect a valid CCFF circuit model for BL protocol");
num_err++;
}
if (bl_memory_model) {
num_err += check_ccff_circuit_model_ports(circuit_lib,
bl_memory_model);
}
/* Check circuit model for WL protocol */
CircuitModelId wl_memory_model = config_protocol.wl_memory_model();
if ( BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type()
&& CircuitModelId::INVALID() == wl_memory_model) {
VTR_LOG_ERROR("Expect a valid CCFF circuit model for WL protocol");
num_err++;
}
if (wl_memory_model) {
num_err += check_ccff_circuit_model_ports(circuit_lib,
wl_memory_model);
}
break;
}
case CONFIG_MEM_STANDALONE: case CONFIG_MEM_STANDALONE:
case CONFIG_MEM_MEMORY_BANK: case CONFIG_MEM_MEMORY_BANK:
case CONFIG_MEM_QL_MEMORY_BANK:
case CONFIG_MEM_FRAME_BASED: case CONFIG_MEM_FRAME_BASED:
num_err = check_sram_circuit_model_ports(circuit_lib, num_err = check_sram_circuit_model_ports(circuit_lib,
config_mem_circuit_model, config_mem_circuit_model,

View File

@ -8,8 +8,8 @@
* Include header files that are required by function declaration * Include header files that are required by function declaration
*******************************************************************/ *******************************************************************/
#include <vector> #include <vector>
#include "circuit_types.h"
#include "circuit_library.h" #include "circuit_library.h"
#include "config_protocol.h"
/******************************************************************** /********************************************************************
* Function declaration * Function declaration
@ -41,9 +41,8 @@ std::vector<std::string> find_circuit_library_unique_verilog_netlists(const Circ
std::vector<std::string> find_circuit_library_unique_spice_netlists(const CircuitLibrary& circuit_lib); std::vector<std::string> find_circuit_library_unique_spice_netlists(const CircuitLibrary& circuit_lib);
bool check_configurable_memory_circuit_model(const e_config_protocol_type& config_protocol_type, bool check_configurable_memory_circuit_model(const ConfigProtocol& config_protocol,
const CircuitLibrary& circuit_lib, const CircuitLibrary& circuit_lib);
const CircuitModelId& config_mem_circuit_model);
CircuitPortId find_circuit_model_power_gate_en_port(const CircuitLibrary& circuit_lib, CircuitPortId find_circuit_model_power_gate_en_port(const CircuitLibrary& circuit_lib,
const CircuitModelId& circuit_model); const CircuitModelId& circuit_model);

View File

@ -188,7 +188,7 @@ size_t find_frame_based_fast_configuration_fabric_bitstream_size(const FabricBit
} }
/******************************************************************** /********************************************************************
* Reorganize the fabric bitstream for memory banks * Reorganize the fabric bitstream for memory banks which use BL and WL decoders
* by the same address across regions: * by the same address across regions:
* This is due to that the length of fabric bitstream could be different in each region. * This is due to that the length of fabric bitstream could be different in each region.
* Template: * Template:
@ -232,6 +232,94 @@ MemoryBankFabricBitstream build_memory_bank_fabric_bitstream_by_address(const Fa
return fabric_bits_by_addr; return fabric_bits_by_addr;
} }
MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream,
const bool& bit_value_to_skip) {
/* Build the bitstream by each region, here we use (WL, BL) pairs when storing bitstreams */
vtr::vector<FabricBitRegionId, std::map<std::string, std::string>> fabric_bits_per_region;
fabric_bits_per_region.resize(fabric_bitstream.num_regions());
for (const FabricBitRegionId& region : fabric_bitstream.regions()) {
for (const FabricBitId& bit_id : fabric_bitstream.region_bits(region)) {
/* Skip din because they should be pre-configured through programming reset/set */
if (fabric_bitstream.bit_din(bit_id) == bit_value_to_skip) {
continue;
}
/* Create string for BL address */
std::string bl_addr_str;
for (const char& addr_bit : fabric_bitstream.bit_bl_address(bit_id)) {
bl_addr_str.push_back(addr_bit);
}
/* Create string for WL address */
std::string wl_addr_str;
for (const char& addr_bit : fabric_bitstream.bit_wl_address(bit_id)) {
wl_addr_str.push_back(addr_bit);
}
/* Place the config bit */
auto result = fabric_bits_per_region[region].find(wl_addr_str);
if (result == fabric_bits_per_region[region].end()) {
fabric_bits_per_region[region][wl_addr_str] = bl_addr_str;
} else {
VTR_ASSERT_SAFE(result != fabric_bits_per_region[region].end());
result->second = combine_two_1hot_str(bl_addr_str, result->second);
}
}
}
/* Find all the keys for the hash tables containing bitstream of each region */
vtr::vector<FabricBitRegionId, std::vector<std::string>> fabric_bits_per_region_keys;
fabric_bits_per_region_keys.resize(fabric_bitstream.num_regions());
for (const FabricBitRegionId& region : fabric_bitstream.regions()) {
/* Pre-allocate memory, because the key size may be large */
fabric_bits_per_region_keys[region].reserve(fabric_bits_per_region[region].size());
for (const auto& pair : fabric_bits_per_region[region]) {
fabric_bits_per_region_keys[region].push_back(pair.first);
}
}
/* Find the maxium key size */
size_t max_key_size = 0;
for (const FabricBitRegionId& region : fabric_bitstream.regions()) {
max_key_size = std::max(max_key_size, fabric_bits_per_region_keys[region].size());
}
/* Find the BL/WL sizes per region; Pair convention is (BL, WL)
* The address sizes are the same across any element,
* just get it from the 1st element to save runtime
*/
vtr::vector<FabricBitRegionId, std::pair<size_t, size_t>> max_blwl_sizes_per_region;
max_blwl_sizes_per_region.resize(fabric_bitstream.num_regions());
for (const FabricBitRegionId& region : fabric_bitstream.regions()) {
max_blwl_sizes_per_region[region].first = std::max(max_blwl_sizes_per_region[region].first, fabric_bits_per_region[region].begin()->second.size());
max_blwl_sizes_per_region[region].second = std::max(max_blwl_sizes_per_region[region].second, fabric_bits_per_region[region].begin()->first.size());
}
/* Combine the bitstream from different region into a unique one. Now we follow the convention: use (WL, BL) pairs */
MemoryBankFlattenFabricBitstream fabric_bits;
for (size_t ikey = 0; ikey < max_key_size; ikey++) {
/* Prepare the final BL/WL vectors to be added to the bitstream database */
std::vector<std::string> cur_bl_vectors;
std::vector<std::string> cur_wl_vectors;
for (const FabricBitRegionId& region : fabric_bitstream.regions()) {
/* If the key id is in bound for the key list in this region, find the BL and WL and add to the final bitstream database
* If the key id is out of bound for the key list in this region, we append an all-zero string for both BL and WLs
*/
if (ikey < fabric_bits_per_region_keys[region].size()) {
cur_wl_vectors.push_back(fabric_bits_per_region_keys[region][ikey]);
cur_bl_vectors.push_back(fabric_bits_per_region[region].at(fabric_bits_per_region_keys[region][ikey]));
} else {
cur_wl_vectors.push_back(std::string(max_blwl_sizes_per_region[region].second, '0'));
cur_bl_vectors.push_back(std::string(max_blwl_sizes_per_region[region].first, '0'));
}
}
/* Add the pair to std map */
fabric_bits[cur_wl_vectors] = cur_bl_vectors;
}
return fabric_bits;
}
/******************************************************************** /********************************************************************
* For fast configuration, the number of bits to be skipped * For fast configuration, the number of bits to be skipped
* the rule to skip any configuration bit should consider the whole data input values. * the rule to skip any configuration bit should consider the whole data input values.

View File

@ -37,6 +37,33 @@ FrameFabricBitstream build_frame_based_fabric_bitstream_by_address(const FabricB
size_t find_frame_based_fast_configuration_fabric_bitstream_size(const FabricBitstream& fabric_bitstream, size_t find_frame_based_fast_configuration_fabric_bitstream_size(const FabricBitstream& fabric_bitstream,
const bool& bit_value_to_skip); const bool& bit_value_to_skip);
/* Must use (WL, BL) as pairs in the map!!!
* This is because BL data may not be unique while WL must be unique
*/
typedef std::map<std::vector<std::string>, std::vector<std::string>> MemoryBankFlattenFabricBitstream;
/********************************************************************
* @ brief Reorganize the fabric bitstream for memory banks which use flatten or shift register to manipulate BL and WLs
* For each configuration region, we will merge BL address (which are 1-hot codes) under the same WL address
*
* Quick Example
* <bl of region A>_<bl of region B> <wl of region A>_<wl of region B>
* An example:
* 010_111 000_101
*
* Note that all the BL/WLs across configuration regions are independent. We will combine them together
* Quick Example
* <bl of region A>_<bl of region B> <wl of region A>_<wl of region B>
* 001_010 000_000
* 100_100 000_000
*
* the bitstream will be merged as
* 101_110 000_000
*
* @note the std::map may cause large memory footprint for large bitstream databases!
*******************************************************************/
MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream,
const bool& bit_value_to_skip);
/* Alias to a specific organization of bitstreams for memory bank configuration protocol */ /* Alias to a specific organization of bitstreams for memory bank configuration protocol */
typedef std::map<std::pair<std::string, std::string>, std::vector<bool>> MemoryBankFabricBitstream; typedef std::map<std::pair<std::string, std::string>, std::vector<bool>> MemoryBankFabricBitstream;
MemoryBankFabricBitstream build_memory_bank_fabric_bitstream_by_address(const FabricBitstream& fabric_bitstream); MemoryBankFabricBitstream build_memory_bank_fabric_bitstream_by_address(const FabricBitstream& fabric_bitstream);

View File

@ -429,13 +429,13 @@ size_t generate_pb_sram_port_size(const e_config_protocol_type sram_orgz_type,
return sram_port_size; return sram_port_size;
} }
size_t estimate_num_configurable_children_to_skip_by_config_protocol(e_config_protocol_type config_protocol_type, size_t estimate_num_configurable_children_to_skip_by_config_protocol(const ConfigProtocol& config_protocol,
size_t curr_region_num_config_child) { size_t curr_region_num_config_child) {
size_t num_child_to_skip = 0; size_t num_child_to_skip = 0;
/* Frame-based configuration protocol will have 1 decoder /* Frame-based configuration protocol will have 1 decoder
* if there are more than 1 configurable children * if there are more than 1 configurable children
*/ */
if ( (CONFIG_MEM_FRAME_BASED == config_protocol_type) if ( (CONFIG_MEM_FRAME_BASED == config_protocol.type())
&& (2 <= curr_region_num_config_child)) { && (2 <= curr_region_num_config_child)) {
num_child_to_skip = 1; num_child_to_skip = 1;
} }
@ -443,10 +443,17 @@ size_t estimate_num_configurable_children_to_skip_by_config_protocol(e_config_pr
/* Memory configuration protocol will have 2 decoders /* Memory configuration protocol will have 2 decoders
* at the top-level * at the top-level
*/ */
if (CONFIG_MEM_MEMORY_BANK == config_protocol_type if (CONFIG_MEM_MEMORY_BANK == config_protocol.type()
|| CONFIG_MEM_QL_MEMORY_BANK == config_protocol_type) { || CONFIG_MEM_QL_MEMORY_BANK == config_protocol.type()) {
VTR_ASSERT(2 <= curr_region_num_config_child); VTR_ASSERT(2 <= curr_region_num_config_child);
num_child_to_skip = 2; num_child_to_skip = 2;
/* If flatten bus is used, BL/WL may not need decoders */
if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) {
num_child_to_skip--;
}
if (BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()) {
num_child_to_skip--;
}
} }
return num_child_to_skip; return num_child_to_skip;

View File

@ -7,6 +7,7 @@
#include <vector> #include <vector>
#include "openfpga_port.h" #include "openfpga_port.h"
#include "circuit_types.h" #include "circuit_types.h"
#include "config_protocol.h"
#include "module_manager.h" #include "module_manager.h"
/******************************************************************** /********************************************************************
@ -46,7 +47,7 @@ size_t generate_pb_sram_port_size(const e_config_protocol_type sram_orgz_type,
* (they are included in the list for bitstream generator usage) * (they are included in the list for bitstream generator usage)
* The number of decoders depends on the type of configuration protocol. * The number of decoders depends on the type of configuration protocol.
*/ */
size_t estimate_num_configurable_children_to_skip_by_config_protocol(e_config_protocol_type config_protocol_type, size_t estimate_num_configurable_children_to_skip_by_config_protocol(const ConfigProtocol& config_protocol,
size_t curr_region_num_config_child); size_t curr_region_num_config_child);
} /* end namespace openfpga */ } /* end namespace openfpga */

View File

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

View File

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

View File

@ -57,6 +57,7 @@ echo -e "Testing physical design friendly memory bank configuration protocol of
run-task basic_tests/full_testbench/ql_memory_bank --debug --show_thread_logs run-task basic_tests/full_testbench/ql_memory_bank --debug --show_thread_logs
run-task basic_tests/full_testbench/ql_memory_bank_use_wlr --debug --show_thread_logs run-task basic_tests/full_testbench/ql_memory_bank_use_wlr --debug --show_thread_logs
run-task basic_tests/full_testbench/multi_region_ql_memory_bank --debug --show_thread_logs run-task basic_tests/full_testbench/multi_region_ql_memory_bank --debug --show_thread_logs
run-task basic_tests/full_testbench/ql_memory_bank_flatten --debug --show_thread_logs
echo -e "Testing testbenches without self checking features"; echo -e "Testing testbenches without self checking features";
run-task basic_tests/full_testbench/full_testbench_without_self_checking --debug --show_thread_logs run-task basic_tests/full_testbench/full_testbench_without_self_checking --debug --show_thread_logs

View File

@ -0,0 +1,44 @@
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# Configuration file for running experiments
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
# Each job execute fpga_flow script on combination of architecture & benchmark
# timeout_each_job is timeout for each job
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
[GENERAL]
run_engine=openfpga_shell
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
power_analysis = true
spice_output=false
verilog_output=true
timeout_each_job = 20*60
fpga_flow=yosys_vpr
[OpenFPGA_SHELL]
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/write_full_testbench_example_script.openfpga
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbankflatten_openfpga.xml
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
openfpga_vpr_device_layout=
openfpga_fast_configuration=
[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=

View File

@ -11,12 +11,6 @@ namespace openfpga {
/************************************************************************ /************************************************************************
* Constructors * Constructors
***********************************************************************/ ***********************************************************************/
/* Copy Constructor */
RRChan::RRChan(const RRChan& rr_chan) {
this->set(rr_chan);
return;
}
/* default constructor */ /* default constructor */
RRChan::RRChan() { RRChan::RRChan() {
type_ = NUM_RR_TYPES; type_ = NUM_RR_TYPES;

View File

@ -43,7 +43,6 @@ namespace openfpga {
*******************************************************************/ *******************************************************************/
class RRChan { class RRChan {
public: /* Constructors */ public: /* Constructors */
RRChan(const RRChan&); /* Copy Constructor */
RRChan(); RRChan();
public: /* Accessors */ public: /* Accessors */
t_rr_type get_type() const; t_rr_type get_type() const;

View File

@ -32,13 +32,6 @@ RRGSB::RRGSB() {
opin_node_.clear(); opin_node_.clear();
} }
/* Copy constructor */
RRGSB::RRGSB(const RRGSB& src) {
/* Copy coordinate */
this->set(src);
return;
}
/************************************************************************ /************************************************************************
* Accessors * Accessors
***********************************************************************/ ***********************************************************************/

View File

@ -52,7 +52,6 @@ namespace openfpga {
*******************************************************************/ *******************************************************************/
class RRGSB { class RRGSB {
public: /* Contructors */ public: /* Contructors */
RRGSB(const RRGSB&);/* Copy constructor */
RRGSB();/* Default constructor */ RRGSB();/* Default constructor */
public: /* Accessors */ public: /* Accessors */
/* Get the number of sides of this SB */ /* Get the number of sides of this SB */