Merge pull request #17 from RapidSilicon/phy_mem_bank
Support flatten BL/WL protocol for QuickLogic memory bank
This commit is contained in:
commit
05c6f1889e
|
@ -40,6 +40,7 @@ Template
|
|||
- ``scan_chain`` requires a circuit model type of ``ccff``
|
||||
- ``frame_based`` 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``
|
||||
|
||||
.. 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!
|
||||
|
||||
|
||||
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`.
|
||||
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
|
||||
|
||||
<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>
|
||||
|
||||
.. 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
|
||||
|
||||
- two outputs (one regular and another inverted)
|
||||
- a Bit-Line input to load the data
|
||||
- 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!
|
||||
|
||||
|
|
|
@ -1170,7 +1170,7 @@ CircuitModelId CircuitLibrary::add_model(const enum e_circuit_model_type& type)
|
|||
|
||||
/* Pass-gate-related parameters */
|
||||
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_types_.emplace_back();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "vtr_assert.h"
|
||||
#include "vtr_log.h"
|
||||
|
||||
#include "config_protocol.h"
|
||||
|
||||
|
@ -32,6 +33,30 @@ int ConfigProtocol::num_regions() const {
|
|||
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
|
||||
***********************************************************************/
|
||||
|
@ -50,3 +75,51 @@ void ConfigProtocol::set_memory_model(const CircuitModelId& memory_model) {
|
|||
void ConfigProtocol::set_num_regions(const int& 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;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,15 @@
|
|||
#include "circuit_types.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
|
||||
*******************************************************************/
|
||||
|
@ -16,11 +25,25 @@ class ConfigProtocol {
|
|||
std::string memory_model_name() const;
|
||||
CircuitModelId memory_model() 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 */
|
||||
void set_type(const e_config_protocol_type& type);
|
||||
void set_memory_model_name(const std::string& memory_model_name);
|
||||
void set_memory_model(const CircuitModelId& memory_model);
|
||||
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 */
|
||||
/* The type of configuration protocol.
|
||||
* In other words, it is about how to organize and access each configurable memory
|
||||
|
@ -33,6 +56,19 @@ class ConfigProtocol {
|
|||
|
||||
/* Number of configurable 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
|
||||
|
|
|
@ -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);
|
||||
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
|
|
@ -33,6 +33,73 @@ e_config_protocol_type string_to_config_protocol_type(const std::string& type_st
|
|||
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
|
||||
*******************************************************************/
|
||||
|
@ -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",
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
|
|
|
@ -46,6 +46,53 @@ std::vector<size_t> ito1hot_vec(const size_t& in_int,
|
|||
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
|
||||
* For example:
|
||||
|
|
|
@ -22,6 +22,21 @@ constexpr char DONT_CARE_CHAR = 'x';
|
|||
std::vector<size_t> ito1hot_vec(const size_t& in_int,
|
||||
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,
|
||||
const size_t& bin_len);
|
||||
|
||||
|
|
|
@ -51,11 +51,6 @@ BasicPort::BasicPort(const std::string& name, const size_t& width) {
|
|||
set_origin_port_width(-1);
|
||||
}
|
||||
|
||||
/* Copy constructor */
|
||||
BasicPort::BasicPort(const BasicPort& basic_port) {
|
||||
set(basic_port);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Accessors
|
||||
***********************************************************************/
|
||||
|
|
|
@ -18,7 +18,6 @@ class BasicPort {
|
|||
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& width);
|
||||
BasicPort(const BasicPort& basic_port); /* Copy constructor */
|
||||
public: /* Overloaded operators */
|
||||
bool operator== (const BasicPort& portA) const;
|
||||
bool operator< (const BasicPort& portA) const;
|
||||
|
|
|
@ -132,7 +132,7 @@ int build_fabric(OpenfpgaContext& openfpga_ctx,
|
|||
VTR_ASSERT(false == fkey_fname.empty());
|
||||
curr_status = write_fabric_key_to_xml_file(openfpga_ctx.module_graph(),
|
||||
fkey_fname,
|
||||
openfpga_ctx.arch().config_protocol.type(),
|
||||
openfpga_ctx.arch().config_protocol,
|
||||
cmd_context.option_enable(cmd, opt_verbose));
|
||||
/* If there is any error, final status cannot be overwritten by a success flag */
|
||||
if (CMD_EXEC_SUCCESS != curr_status) {
|
||||
|
|
|
@ -813,6 +813,15 @@ std::string generate_sram_local_port_name(const CircuitLibrary& circuit_lib,
|
|||
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
|
||||
* This is very useful in Verilog code generation where the inputs of
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "circuit_library.h"
|
||||
#include "device_grid.h"
|
||||
#include "openfpga_port.h"
|
||||
#include "module_manager_fwd.h"
|
||||
|
||||
/********************************************************************
|
||||
* 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_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,
|
||||
const CircuitModelId& mux_model,
|
||||
const size_t& mux_size,
|
||||
|
|
|
@ -56,9 +56,8 @@ int read_arch(OpenfpgaContext& openfpga_context,
|
|||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
|
||||
if (false == check_configurable_memory_circuit_model(openfpga_context.arch().config_protocol.type(),
|
||||
openfpga_context.arch().circuit_lib,
|
||||
openfpga_context.arch().config_protocol.memory_model())) {
|
||||
if (false == check_configurable_memory_circuit_model(openfpga_context.arch().config_protocol,
|
||||
openfpga_context.arch().circuit_lib)) {
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
|
||||
|
|
|
@ -422,7 +422,7 @@ int build_top_module(ModuleManager& module_manager,
|
|||
if (0 < module_manager.configurable_children(top_module).size()) {
|
||||
add_top_module_nets_memory_config_bus(module_manager, decoder_lib,
|
||||
top_module,
|
||||
circuit_lib, sram_model,
|
||||
circuit_lib,
|
||||
config_protocol, circuit_lib.design_tech_type(sram_model),
|
||||
top_module_num_config_bits);
|
||||
}
|
||||
|
|
|
@ -852,35 +852,7 @@ void add_top_module_sram_ports(ModuleManager& module_manager,
|
|||
break;
|
||||
}
|
||||
case CONFIG_MEM_QL_MEMORY_BANK: {
|
||||
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);
|
||||
|
||||
/* 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);
|
||||
|
||||
add_top_module_ql_memory_bank_sram_ports(module_manager, module_id, circuit_lib, config_protocol, num_config_bits);
|
||||
break;
|
||||
}
|
||||
case CONFIG_MEM_SCAN_CHAIN: {
|
||||
|
@ -1765,7 +1737,6 @@ void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
|
|||
DecoderLibrary& decoder_lib,
|
||||
const ModuleId& parent_module,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const TopModuleNumConfigBits& num_config_bits) {
|
||||
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);
|
||||
break;
|
||||
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;
|
||||
case CONFIG_MEM_FRAME_BASED:
|
||||
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,
|
||||
const ModuleId& parent_module,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const e_circuit_model_design_tech& mem_tech,
|
||||
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,
|
||||
parent_module,
|
||||
circuit_lib,
|
||||
sram_model,
|
||||
config_protocol,
|
||||
num_config_bits);
|
||||
break;
|
||||
|
|
|
@ -66,7 +66,6 @@ void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
|
|||
DecoderLibrary& decoder_lib,
|
||||
const ModuleId& parent_module,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const e_circuit_model_design_tech& mem_tech,
|
||||
const TopModuleNumConfigBits& num_config_bits);
|
||||
|
|
|
@ -31,13 +31,15 @@
|
|||
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
|
||||
* - 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 BL configuration bus for decoders
|
||||
*
|
||||
* 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
|
||||
* top-level BL address lines
|
||||
|
@ -120,12 +122,13 @@ namespace openfpga {
|
|||
* +---------+
|
||||
*
|
||||
**********************************************************************/
|
||||
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 CircuitModelId& sram_model,
|
||||
const TopModuleNumConfigBits& num_config_bits) {
|
||||
static
|
||||
void add_top_module_nets_cmos_ql_memory_bank_bl_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);
|
||||
|
@ -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 */
|
||||
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 */
|
||||
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);
|
||||
|
||||
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 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 */
|
||||
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);
|
||||
}
|
||||
|
||||
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)) {
|
||||
/**************************************************************
|
||||
|
@ -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);
|
||||
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
|
||||
*/
|
||||
|
@ -267,57 +223,15 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma
|
|||
/* 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]);
|
||||
|
||||
/**************************************************************
|
||||
* 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_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,
|
||||
config_region,
|
||||
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> 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
|
||||
|
@ -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
|
||||
*/
|
||||
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);
|
||||
|
||||
/* 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) {
|
||||
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 */
|
||||
/* 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));
|
||||
if (!child_wl_port) {
|
||||
continue;
|
||||
}
|
||||
BasicPort child_wl_port_info = module_manager.module_port(child_module, child_wl_port);
|
||||
|
||||
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];
|
||||
|
||||
/* 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));
|
||||
if (!child_wlr_port) {
|
||||
continue;
|
||||
}
|
||||
BasicPort child_wlr_port_info = module_manager.module_port(child_module, child_wlr_port);
|
||||
|
||||
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
|
||||
* 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_to_region(top_module,
|
||||
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 */
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "vtr_vector.h"
|
||||
#include "vtr_ndmatrix.h"
|
||||
#include "module_manager.h"
|
||||
#include "config_protocol.h"
|
||||
#include "circuit_library.h"
|
||||
#include "decoder_library.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,
|
||||
const ModuleId& top_module,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
const ConfigProtocol& config_protocol,
|
||||
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 */
|
||||
|
||||
#endif
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace openfpga {
|
|||
***************************************************************************************/
|
||||
int write_fabric_key_to_xml_file(const ModuleManager& module_manager,
|
||||
const std::string& fname,
|
||||
const e_config_protocol_type& config_protocol_type,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const bool& verbose) {
|
||||
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 */
|
||||
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;
|
||||
|
||||
fabric_key.reserve_region_keys(fabric_region, curr_region_num_config_child);
|
||||
|
|
|
@ -4,8 +4,9 @@
|
|||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include "vpr_context.h"
|
||||
#include "openfpga_context.h"
|
||||
#include <string.h>
|
||||
#include "module_manager.h"
|
||||
#include "config_protocol.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
|
@ -16,7 +17,7 @@ namespace openfpga {
|
|||
|
||||
int write_fabric_key_to_xml_file(const ModuleManager& module_manager,
|
||||
const std::string& fname,
|
||||
const e_config_protocol_type& config_protocol_type,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const bool& verbose);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -64,7 +64,7 @@ static
|
|||
size_t rec_estimate_device_bitstream_num_bits(const ModuleManager& module_manager,
|
||||
const ModuleId& top_module,
|
||||
const ModuleId& parent_module,
|
||||
const e_config_protocol_type& config_protocol_type) {
|
||||
const ConfigProtocol& config_protocol) {
|
||||
size_t num_bits = 0;
|
||||
|
||||
/* 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) {
|
||||
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 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;
|
||||
|
||||
/* Visit all the children in a recursively way */
|
||||
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];
|
||||
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 {
|
||||
|
@ -102,14 +102,14 @@ size_t rec_estimate_device_bitstream_num_bits(const ModuleManager& module_manage
|
|||
/* Frame-based configuration protocol will have 1 decoder
|
||||
* 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)) {
|
||||
num_configurable_children--;
|
||||
}
|
||||
|
||||
for (size_t ichild = 0; ichild < num_configurable_children; ++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(),
|
||||
top_module,
|
||||
top_module,
|
||||
openfpga_ctx.arch().config_protocol.type());
|
||||
openfpga_ctx.arch().config_protocol);
|
||||
bitstream_manager.reserve_bits(num_bits_to_reserve);
|
||||
VTR_LOGV(verbose, "Reserved %lu configuration bits\n", num_bits_to_reserve);
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
|
||||
#include "decoder_library_utils.h"
|
||||
#include "bitstream_manager_utils.h"
|
||||
#include "memory_utils.h"
|
||||
#include "memory_bank_utils.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& parent_module,
|
||||
const ConfigRegionId& config_region,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& sram_model,
|
||||
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);
|
||||
|
||||
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 */
|
||||
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,
|
||||
module_manager, top_module, child_module,
|
||||
config_region,
|
||||
config_protocol,
|
||||
circuit_lib, sram_model,
|
||||
bl_addr_size, wl_addr_size,
|
||||
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,
|
||||
module_manager, top_module, child_module,
|
||||
config_region,
|
||||
config_protocol,
|
||||
circuit_lib, sram_model,
|
||||
bl_addr_size, wl_addr_size,
|
||||
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)) {
|
||||
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;
|
||||
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 */
|
||||
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 */
|
||||
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 */
|
||||
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 */
|
||||
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
|
||||
* 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,
|
||||
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*/
|
||||
VTR_ASSERT(config_protocol.type() == CONFIG_MEM_QL_MEMORY_BANK);
|
||||
|
||||
/* Find global BL address port size */
|
||||
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);
|
||||
/* For different BL control protocol, the address ports are different
|
||||
* - flatten BLs: the address port should be raw BL ports at top-level module.
|
||||
* 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 */
|
||||
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);
|
||||
/* For different WL control protocol, the address ports are different
|
||||
* - flatten WLs: the address port should be raw WL ports at top-level module.
|
||||
* 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 */
|
||||
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 */
|
||||
std::vector<ModuleId> configurable_children = module_manager.region_configurable_children(top_module, config_region);
|
||||
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 */
|
||||
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
|
||||
* 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,
|
||||
module_manager, top_module, top_module,
|
||||
config_region,
|
||||
config_protocol,
|
||||
circuit_lib, config_protocol.memory_model(),
|
||||
bl_addr_port_info.get_width(),
|
||||
wl_addr_port_info.get_width(),
|
||||
cur_bl_addr_port_info.get_width(),
|
||||
cur_wl_addr_port_info.get_width(),
|
||||
temp_num_bls_cur_tile, bl_start_index_per_tile,
|
||||
temp_num_wls_cur_tile, wl_start_index_per_tile,
|
||||
temp_coord,
|
||||
|
|
|
@ -139,24 +139,35 @@ FabricBitId FabricBitstream::add_bit(const ConfigBitId& config_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 == use_address_);
|
||||
VTR_ASSERT(address_length_ == address.size());
|
||||
if (tolerant_short_address) {
|
||||
VTR_ASSERT(address_length_ >= address.size());
|
||||
} else {
|
||||
VTR_ASSERT(address_length_ == address.size());
|
||||
}
|
||||
bit_addresses_[bit_id] = address;
|
||||
}
|
||||
|
||||
void FabricBitstream::set_bit_bl_address(const FabricBitId& bit_id,
|
||||
const std::vector<char>& address) {
|
||||
set_bit_address(bit_id, address);
|
||||
const std::vector<char>& 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,
|
||||
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 == use_address_);
|
||||
VTR_ASSERT(true == use_wl_address_);
|
||||
VTR_ASSERT(wl_address_length_ == address.size());
|
||||
if (tolerant_short_address) {
|
||||
VTR_ASSERT(wl_address_length_ >= address.size());
|
||||
} else {
|
||||
VTR_ASSERT(wl_address_length_ == address.size());
|
||||
}
|
||||
bit_wl_addresses_[bit_id] = address;
|
||||
}
|
||||
|
||||
|
|
|
@ -135,13 +135,16 @@ class FabricBitstream {
|
|||
FabricBitId add_bit(const ConfigBitId& config_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,
|
||||
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,
|
||||
const std::vector<char>& address);
|
||||
const std::vector<char>& address,
|
||||
const bool& tolerant_short_address = false);
|
||||
|
||||
void set_bit_din(const FabricBitId& bit_id,
|
||||
const char& din);
|
||||
|
|
|
@ -180,6 +180,56 @@ int write_memory_bank_fabric_bitstream_to_text_file(std::fstream& fp,
|
|||
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
|
||||
* to a plain text file
|
||||
|
@ -306,7 +356,28 @@ int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manage
|
|||
bitstream_manager,
|
||||
fabric_bitstream);
|
||||
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:
|
||||
status = write_memory_bank_fabric_bitstream_to_text_file(fp,
|
||||
apply_fast_configuration,
|
||||
|
|
|
@ -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);
|
||||
break;
|
||||
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:
|
||||
print_verilog_top_testbench_memory_bank_port(fp, module_manager, top_module);
|
||||
break;
|
||||
|
@ -808,7 +810,7 @@ void print_verilog_top_testbench_ports(std::fstream& fp,
|
|||
* Note that this will not applicable to configuration chain!!!
|
||||
*******************************************************************/
|
||||
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& bit_value_to_skip,
|
||||
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;
|
||||
|
||||
/* Branch on the type of configuration protocol */
|
||||
switch (sram_orgz_type) {
|
||||
switch (config_protocol.type()) {
|
||||
case CONFIG_MEM_STANDALONE:
|
||||
/* We just need 1 clock cycle to load all the configuration bits
|
||||
* 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.));
|
||||
}
|
||||
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: {
|
||||
/* 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();
|
||||
|
@ -1111,7 +1131,10 @@ void print_verilog_top_testbench_configuration_protocol_stimulus(std::fstream& f
|
|||
case CONFIG_MEM_FRAME_BASED: {
|
||||
ModulePortId en_port_id = module_manager.find_module_port(top_module,
|
||||
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);
|
||||
print_verilog_comment(fp, std::string("---- Generate enable signal waveform -----"));
|
||||
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
|
||||
void print_verilog_full_testbench_bitstream(std::fstream& fp,
|
||||
const std::string& bitstream_file,
|
||||
const e_config_protocol_type& config_protocol_type,
|
||||
const ConfigProtocol& config_protocol,
|
||||
const bool& fast_configuration,
|
||||
const bool& bit_value_to_skip,
|
||||
const ModuleManager& module_manager,
|
||||
|
@ -1693,7 +1716,7 @@ void print_verilog_full_testbench_bitstream(std::fstream& fp,
|
|||
const FabricBitstream& fabric_bitstream) {
|
||||
|
||||
/* Branch on the type of configuration protocol */
|
||||
switch (config_protocol_type) {
|
||||
switch (config_protocol.type()) {
|
||||
case CONFIG_MEM_STANDALONE:
|
||||
print_verilog_full_testbench_vanilla_bitstream(fp,
|
||||
bitstream_file,
|
||||
|
@ -1719,6 +1742,7 @@ void print_verilog_full_testbench_bitstream(std::fstream& fp,
|
|||
break;
|
||||
case CONFIG_MEM_QL_MEMORY_BANK:
|
||||
print_verilog_full_testbench_ql_memory_bank_bitstream(fp, bitstream_file,
|
||||
config_protocol,
|
||||
fast_configuration,
|
||||
bit_value_to_skip,
|
||||
module_manager, top_module,
|
||||
|
@ -1916,7 +1940,7 @@ int print_verilog_full_testbench(const ModuleManager& module_manager,
|
|||
}
|
||||
|
||||
/* 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,
|
||||
bit_value_to_skip,
|
||||
bitstream_manager,
|
||||
|
@ -1998,7 +2022,7 @@ int print_verilog_full_testbench(const ModuleManager& module_manager,
|
|||
/* load bitstream to FPGA fabric in a configuration phase */
|
||||
print_verilog_full_testbench_bitstream(fp,
|
||||
bitstream_file,
|
||||
config_protocol.type(),
|
||||
config_protocol,
|
||||
apply_fast_configuration,
|
||||
bit_value_to_skip,
|
||||
module_manager, top_module,
|
||||
|
|
|
@ -36,13 +36,264 @@
|
|||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
void print_verilog_full_testbench_ql_memory_bank_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) {
|
||||
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 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);
|
||||
|
||||
|
@ -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 -----");
|
||||
}
|
||||
|
||||
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 */
|
||||
|
|
|
@ -26,12 +26,21 @@
|
|||
/* begin 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
|
||||
* where configuration bits are programming in serial (one by one)
|
||||
*/
|
||||
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,
|
||||
|
|
|
@ -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,
|
||||
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;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* 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
|
||||
* Verilog port
|
||||
|
|
|
@ -111,6 +111,10 @@ std::string generate_verilog_port_constant_values(const BasicPort& output_port,
|
|||
const std::vector<size_t>& const_values,
|
||||
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,
|
||||
const BasicPort& output_port,
|
||||
const std::vector<size_t>& const_values);
|
||||
|
|
|
@ -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
|
||||
* satisfy the needs of configuration protocol
|
||||
* - 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,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& config_mem_circuit_model) {
|
||||
bool check_configurable_memory_circuit_model(const ConfigProtocol& config_protocol,
|
||||
const CircuitLibrary& circuit_lib) {
|
||||
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:
|
||||
num_err = check_ccff_circuit_model_ports(circuit_lib,
|
||||
config_mem_circuit_model);
|
||||
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_MEMORY_BANK:
|
||||
case CONFIG_MEM_QL_MEMORY_BANK:
|
||||
case CONFIG_MEM_FRAME_BASED:
|
||||
num_err = check_sram_circuit_model_ports(circuit_lib,
|
||||
config_mem_circuit_model,
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include <vector>
|
||||
#include "circuit_types.h"
|
||||
#include "circuit_library.h"
|
||||
#include "config_protocol.h"
|
||||
|
||||
/********************************************************************
|
||||
* 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);
|
||||
|
||||
bool check_configurable_memory_circuit_model(const e_config_protocol_type& config_protocol_type,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& config_mem_circuit_model);
|
||||
bool check_configurable_memory_circuit_model(const ConfigProtocol& config_protocol,
|
||||
const CircuitLibrary& circuit_lib);
|
||||
|
||||
CircuitPortId find_circuit_model_power_gate_en_port(const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model);
|
||||
|
|
|
@ -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:
|
||||
* This is due to that the length of fabric bitstream could be different in each region.
|
||||
* Template:
|
||||
|
@ -232,6 +232,94 @@ MemoryBankFabricBitstream build_memory_bank_fabric_bitstream_by_address(const Fa
|
|||
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
|
||||
* the rule to skip any configuration bit should consider the whole data input values.
|
||||
|
|
|
@ -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,
|
||||
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 */
|
||||
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);
|
||||
|
|
|
@ -429,13 +429,13 @@ size_t generate_pb_sram_port_size(const e_config_protocol_type sram_orgz_type,
|
|||
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 num_child_to_skip = 0;
|
||||
/* Frame-based configuration protocol will have 1 decoder
|
||||
* 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)) {
|
||||
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
|
||||
* at the top-level
|
||||
*/
|
||||
if (CONFIG_MEM_MEMORY_BANK == config_protocol_type
|
||||
|| CONFIG_MEM_QL_MEMORY_BANK == config_protocol_type) {
|
||||
if (CONFIG_MEM_MEMORY_BANK == config_protocol.type()
|
||||
|| CONFIG_MEM_QL_MEMORY_BANK == config_protocol.type()) {
|
||||
VTR_ASSERT(2 <= curr_region_num_config_child);
|
||||
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;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <vector>
|
||||
#include "openfpga_port.h"
|
||||
#include "circuit_types.h"
|
||||
#include "config_protocol.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)
|
||||
* 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);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -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>
|
|
@ -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>
|
|
@ -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_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/ql_memory_bank_flatten --debug --show_thread_logs
|
||||
|
||||
echo -e "Testing testbenches without self checking features";
|
||||
run-task basic_tests/full_testbench/full_testbench_without_self_checking --debug --show_thread_logs
|
||||
|
|
|
@ -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=
|
|
@ -11,12 +11,6 @@ namespace openfpga {
|
|||
/************************************************************************
|
||||
* Constructors
|
||||
***********************************************************************/
|
||||
/* Copy Constructor */
|
||||
RRChan::RRChan(const RRChan& rr_chan) {
|
||||
this->set(rr_chan);
|
||||
return;
|
||||
}
|
||||
|
||||
/* default constructor */
|
||||
RRChan::RRChan() {
|
||||
type_ = NUM_RR_TYPES;
|
||||
|
|
|
@ -43,7 +43,6 @@ namespace openfpga {
|
|||
*******************************************************************/
|
||||
class RRChan {
|
||||
public: /* Constructors */
|
||||
RRChan(const RRChan&); /* Copy Constructor */
|
||||
RRChan();
|
||||
public: /* Accessors */
|
||||
t_rr_type get_type() const;
|
||||
|
|
|
@ -32,13 +32,6 @@ RRGSB::RRGSB() {
|
|||
opin_node_.clear();
|
||||
}
|
||||
|
||||
/* Copy constructor */
|
||||
RRGSB::RRGSB(const RRGSB& src) {
|
||||
/* Copy coordinate */
|
||||
this->set(src);
|
||||
return;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
* Accessors
|
||||
***********************************************************************/
|
||||
|
|
|
@ -52,7 +52,6 @@ namespace openfpga {
|
|||
*******************************************************************/
|
||||
class RRGSB {
|
||||
public: /* Contructors */
|
||||
RRGSB(const RRGSB&);/* Copy constructor */
|
||||
RRGSB();/* Default constructor */
|
||||
public: /* Accessors */
|
||||
/* Get the number of sides of this SB */
|
||||
|
|
Loading…
Reference in New Issue