Merge pull request #20 from RapidSilicon/qlbank_sr
Support Shift-registers-based QuickLogic's Memory Bank
This commit is contained in:
commit
2903f28d24
|
@ -326,6 +326,102 @@ size_t check_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
||||||
return num_err;
|
return num_err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* A function to check the port map of CCFF circuit model used to control BLs
|
||||||
|
* - Require 1 clock port
|
||||||
|
* - Require 1 input port as data input (to be driven by other CCFF in a chain)
|
||||||
|
* - Require 1 output port as data output (to drive other CCFF in a chain)
|
||||||
|
* - Require 1 BL port as data output / inout (to drive/driven by BLs)
|
||||||
|
***********************************************************************/
|
||||||
|
size_t check_bl_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitModelId& circuit_model) {
|
||||||
|
size_t num_err = 0;
|
||||||
|
|
||||||
|
/* Check the type of circuit model */
|
||||||
|
VTR_ASSERT(CIRCUIT_MODEL_CCFF == circuit_lib.model_type(circuit_model));
|
||||||
|
|
||||||
|
/* Check if we have D, Set and Reset */
|
||||||
|
/* We can have either 1 input which is D or 2 inputs which are D and scan input */
|
||||||
|
size_t num_input_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true).size();
|
||||||
|
if (1 != num_input_ports) {
|
||||||
|
VTR_LOG_ERROR("Configuration flip-flop for BL shift register '%s' must have 1 %s port!\n",
|
||||||
|
circuit_lib.model_name(circuit_model).c_str(),
|
||||||
|
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(CIRCUIT_MODEL_PORT_INPUT)]);
|
||||||
|
num_err++;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
|
||||||
|
CIRCUIT_MODEL_PORT_INPUT,
|
||||||
|
num_input_ports, 1, false);
|
||||||
|
/* Check if we have a clock */
|
||||||
|
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
|
||||||
|
CIRCUIT_MODEL_PORT_CLOCK,
|
||||||
|
1, 1, true);
|
||||||
|
|
||||||
|
|
||||||
|
/* Check if we have 1 output*/
|
||||||
|
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
|
||||||
|
CIRCUIT_MODEL_PORT_OUTPUT,
|
||||||
|
1, 1, false);
|
||||||
|
|
||||||
|
/* Check if we have 1 bl port */
|
||||||
|
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
|
||||||
|
CIRCUIT_MODEL_PORT_BL,
|
||||||
|
1, 1, false);
|
||||||
|
|
||||||
|
return num_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/************************************************************************
|
||||||
|
* A function to check the port map of CCFF circuit model used to control WLs
|
||||||
|
* - Require 1 clock port
|
||||||
|
* - Require 1 input port as data input (to be driven by other CCFF in a chain)
|
||||||
|
* - Require 1 output port as data output (to drive other CCFF in a chain)
|
||||||
|
* - Require 1 WL port as data output (to drive WLs)
|
||||||
|
* - Optionally require 1 WLR port as data output (to drive WLRs)
|
||||||
|
***********************************************************************/
|
||||||
|
size_t check_wl_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitModelId& circuit_model) {
|
||||||
|
size_t num_err = 0;
|
||||||
|
|
||||||
|
/* Check the type of circuit model */
|
||||||
|
VTR_ASSERT(CIRCUIT_MODEL_CCFF == circuit_lib.model_type(circuit_model));
|
||||||
|
|
||||||
|
/* Check if we have D, Set and Reset */
|
||||||
|
/* We can have either 1 input which is D or 2 inputs which are D and scan input */
|
||||||
|
size_t num_input_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true).size();
|
||||||
|
if (1 != num_input_ports) {
|
||||||
|
VTR_LOG_ERROR("Configuration flip-flop for WL shift register '%s' must have 1 %s port!\n",
|
||||||
|
circuit_lib.model_name(circuit_model).c_str(),
|
||||||
|
CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(CIRCUIT_MODEL_PORT_INPUT)]);
|
||||||
|
num_err++;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
|
||||||
|
CIRCUIT_MODEL_PORT_INPUT,
|
||||||
|
num_input_ports, 1, false);
|
||||||
|
/* Check if we have two clock: 1 for write-enable, 1 for shift register */
|
||||||
|
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
|
||||||
|
CIRCUIT_MODEL_PORT_CLOCK,
|
||||||
|
2, 1, true);
|
||||||
|
|
||||||
|
|
||||||
|
/* Check if we have 1 output*/
|
||||||
|
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
|
||||||
|
CIRCUIT_MODEL_PORT_OUTPUT,
|
||||||
|
1, 1, false);
|
||||||
|
|
||||||
|
/* Check if we have 1 wl port */
|
||||||
|
if (0 < circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_WLR, true).size()) {
|
||||||
|
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
|
||||||
|
CIRCUIT_MODEL_PORT_WLR,
|
||||||
|
1, 1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* A function to check the port map of SRAM circuit model
|
* A function to check the port map of SRAM circuit model
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
|
|
@ -39,6 +39,12 @@ size_t check_ff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
||||||
size_t check_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
size_t check_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
||||||
const CircuitModelId& circuit_model);
|
const CircuitModelId& circuit_model);
|
||||||
|
|
||||||
|
size_t check_bl_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitModelId& circuit_model);
|
||||||
|
|
||||||
|
size_t check_wl_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitModelId& circuit_model);
|
||||||
|
|
||||||
size_t check_sram_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
size_t check_sram_circuit_model_ports(const CircuitLibrary& circuit_lib,
|
||||||
const CircuitModelId& circuit_model,
|
const CircuitModelId& circuit_model,
|
||||||
const bool& check_blwl);
|
const bool& check_blwl);
|
||||||
|
|
|
@ -949,7 +949,6 @@ bool CircuitLibrary::port_is_config_enable(const CircuitPortId& circuit_port_id)
|
||||||
return port_is_config_enable_[circuit_port_id];
|
return port_is_config_enable_[circuit_port_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Return a flag if the port is used during programming a FPGA in a circuit model */
|
/* Return a flag if the port is used during programming a FPGA in a circuit model */
|
||||||
bool CircuitLibrary::port_is_prog(const CircuitPortId& circuit_port_id) const {
|
bool CircuitLibrary::port_is_prog(const CircuitPortId& circuit_port_id) const {
|
||||||
/* validate the circuit_port_id */
|
/* validate the circuit_port_id */
|
||||||
|
@ -957,6 +956,13 @@ bool CircuitLibrary::port_is_prog(const CircuitPortId& circuit_port_id) const {
|
||||||
return port_is_prog_[circuit_port_id];
|
return port_is_prog_[circuit_port_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return a flag if the port is used by shift register in a circuit model */
|
||||||
|
bool CircuitLibrary::port_is_shift_register(const CircuitPortId& circuit_port_id) const {
|
||||||
|
/* validate the circuit_port_id */
|
||||||
|
VTR_ASSERT(valid_circuit_port_id(circuit_port_id));
|
||||||
|
return port_is_shift_register_[circuit_port_id];
|
||||||
|
}
|
||||||
|
|
||||||
/* Return which level the output port locates at a LUT multiplexing structure */
|
/* Return which level the output port locates at a LUT multiplexing structure */
|
||||||
size_t CircuitLibrary::port_lut_frac_level(const CircuitPortId& circuit_port_id) const {
|
size_t CircuitLibrary::port_lut_frac_level(const CircuitPortId& circuit_port_id) const {
|
||||||
/* validate the circuit_port_id */
|
/* validate the circuit_port_id */
|
||||||
|
@ -1401,6 +1407,7 @@ CircuitPortId CircuitLibrary::add_model_port(const CircuitModelId& model_id,
|
||||||
port_is_set_.push_back(false);
|
port_is_set_.push_back(false);
|
||||||
port_is_config_enable_.push_back(false);
|
port_is_config_enable_.push_back(false);
|
||||||
port_is_prog_.push_back(false);
|
port_is_prog_.push_back(false);
|
||||||
|
port_is_shift_register_.push_back(false);
|
||||||
port_tri_state_model_names_.emplace_back();
|
port_tri_state_model_names_.emplace_back();
|
||||||
port_tri_state_model_ids_.push_back(CircuitModelId::INVALID());
|
port_tri_state_model_ids_.push_back(CircuitModelId::INVALID());
|
||||||
port_inv_model_names_.emplace_back();
|
port_inv_model_names_.emplace_back();
|
||||||
|
@ -1538,6 +1545,15 @@ void CircuitLibrary::set_port_is_prog(const CircuitPortId& circuit_port_id,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Set the is_prog for a port of a circuit model */
|
||||||
|
void CircuitLibrary::set_port_is_shift_register(const CircuitPortId& circuit_port_id,
|
||||||
|
const bool& is_shift_register) {
|
||||||
|
/* validate the circuit_port_id */
|
||||||
|
VTR_ASSERT(valid_circuit_port_id(circuit_port_id));
|
||||||
|
port_is_shift_register_[circuit_port_id] = is_shift_register;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* Set the model_name for a port of a circuit model */
|
/* Set the model_name for a port of a circuit model */
|
||||||
void CircuitLibrary::set_port_tri_state_model_name(const CircuitPortId& circuit_port_id,
|
void CircuitLibrary::set_port_tri_state_model_name(const CircuitPortId& circuit_port_id,
|
||||||
const std::string& model_name) {
|
const std::string& model_name) {
|
||||||
|
|
|
@ -288,6 +288,7 @@ class CircuitLibrary {
|
||||||
bool port_is_set(const CircuitPortId& circuit_port_id) const;
|
bool port_is_set(const CircuitPortId& circuit_port_id) const;
|
||||||
bool port_is_config_enable(const CircuitPortId& circuit_port_id) const;
|
bool port_is_config_enable(const CircuitPortId& circuit_port_id) const;
|
||||||
bool port_is_prog(const CircuitPortId& circuit_port_id) const;
|
bool port_is_prog(const CircuitPortId& circuit_port_id) const;
|
||||||
|
bool port_is_shift_register(const CircuitPortId& circuit_port_id) const;
|
||||||
size_t port_lut_frac_level(const CircuitPortId& circuit_port_id) const;
|
size_t port_lut_frac_level(const CircuitPortId& circuit_port_id) const;
|
||||||
bool port_is_harden_lut_port(const CircuitPortId& circuit_port_id) const;
|
bool port_is_harden_lut_port(const CircuitPortId& circuit_port_id) const;
|
||||||
std::vector<size_t> port_lut_output_mask(const CircuitPortId& circuit_port_id) const;
|
std::vector<size_t> port_lut_output_mask(const CircuitPortId& circuit_port_id) const;
|
||||||
|
@ -372,6 +373,8 @@ class CircuitLibrary {
|
||||||
const bool& is_config_enable);
|
const bool& is_config_enable);
|
||||||
void set_port_is_prog(const CircuitPortId& circuit_port_id,
|
void set_port_is_prog(const CircuitPortId& circuit_port_id,
|
||||||
const bool& is_prog);
|
const bool& is_prog);
|
||||||
|
void set_port_is_shift_register(const CircuitPortId& circuit_port_id,
|
||||||
|
const bool& is_shift_register);
|
||||||
void set_port_tri_state_model_name(const CircuitPortId& circuit_port_id,
|
void set_port_tri_state_model_name(const CircuitPortId& circuit_port_id,
|
||||||
const std::string& model_name);
|
const std::string& model_name);
|
||||||
void set_port_tri_state_model_id(const CircuitPortId& circuit_port_id,
|
void set_port_tri_state_model_id(const CircuitPortId& circuit_port_id,
|
||||||
|
@ -560,6 +563,7 @@ class CircuitLibrary {
|
||||||
vtr::vector<CircuitPortId, bool> port_is_set_;
|
vtr::vector<CircuitPortId, bool> port_is_set_;
|
||||||
vtr::vector<CircuitPortId, bool> port_is_config_enable_;
|
vtr::vector<CircuitPortId, bool> port_is_config_enable_;
|
||||||
vtr::vector<CircuitPortId, bool> port_is_prog_;
|
vtr::vector<CircuitPortId, bool> port_is_prog_;
|
||||||
|
vtr::vector<CircuitPortId, bool> port_is_shift_register_;
|
||||||
vtr::vector<CircuitPortId, std::string> port_tri_state_model_names_;
|
vtr::vector<CircuitPortId, std::string> port_tri_state_model_names_;
|
||||||
vtr::vector<CircuitPortId, CircuitModelId> port_tri_state_model_ids_;
|
vtr::vector<CircuitPortId, CircuitModelId> port_tri_state_model_ids_;
|
||||||
vtr::vector<CircuitPortId, std::string> port_inv_model_names_;
|
vtr::vector<CircuitPortId, std::string> port_inv_model_names_;
|
||||||
|
|
|
@ -45,6 +45,10 @@ CircuitModelId ConfigProtocol::bl_memory_model() const {
|
||||||
return bl_memory_model_;
|
return bl_memory_model_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t ConfigProtocol::bl_num_banks() const {
|
||||||
|
return bl_num_banks_;
|
||||||
|
}
|
||||||
|
|
||||||
e_blwl_protocol_type ConfigProtocol::wl_protocol_type() const {
|
e_blwl_protocol_type ConfigProtocol::wl_protocol_type() const {
|
||||||
return wl_protocol_type_;
|
return wl_protocol_type_;
|
||||||
}
|
}
|
||||||
|
@ -57,6 +61,10 @@ CircuitModelId ConfigProtocol::wl_memory_model() const {
|
||||||
return wl_memory_model_;
|
return wl_memory_model_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t ConfigProtocol::wl_num_banks() const {
|
||||||
|
return wl_num_banks_;
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* Public Mutators
|
* Public Mutators
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
@ -100,6 +108,15 @@ void ConfigProtocol::set_bl_memory_model(const CircuitModelId& memory_model) {
|
||||||
bl_memory_model_ = memory_model;
|
bl_memory_model_ = memory_model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConfigProtocol::set_bl_num_banks(const size_t& num_banks) {
|
||||||
|
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_num_banks_ = num_banks;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void ConfigProtocol::set_wl_protocol_type(const e_blwl_protocol_type& type) {
|
void ConfigProtocol::set_wl_protocol_type(const e_blwl_protocol_type& type) {
|
||||||
if (CONFIG_MEM_QL_MEMORY_BANK != 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_]);
|
VTR_LOG_ERROR("WL protocol type is only applicable for configuration protocol '%d'", CONFIG_PROTOCOL_TYPE_STRING[type_]);
|
||||||
|
@ -123,3 +140,12 @@ void ConfigProtocol::set_wl_memory_model(const CircuitModelId& memory_model) {
|
||||||
}
|
}
|
||||||
wl_memory_model_ = memory_model;
|
wl_memory_model_ = memory_model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConfigProtocol::set_wl_num_banks(const size_t& num_banks) {
|
||||||
|
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_num_banks_ = num_banks;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,9 +29,11 @@ class ConfigProtocol {
|
||||||
e_blwl_protocol_type bl_protocol_type() const;
|
e_blwl_protocol_type bl_protocol_type() const;
|
||||||
std::string bl_memory_model_name() const;
|
std::string bl_memory_model_name() const;
|
||||||
CircuitModelId bl_memory_model() const;
|
CircuitModelId bl_memory_model() const;
|
||||||
|
size_t bl_num_banks() const;
|
||||||
e_blwl_protocol_type wl_protocol_type() const;
|
e_blwl_protocol_type wl_protocol_type() const;
|
||||||
std::string wl_memory_model_name() const;
|
std::string wl_memory_model_name() const;
|
||||||
CircuitModelId wl_memory_model() const;
|
CircuitModelId wl_memory_model() const;
|
||||||
|
size_t wl_num_banks() const;
|
||||||
public: /* Public Mutators */
|
public: /* Public Mutators */
|
||||||
void set_type(const e_config_protocol_type& type);
|
void set_type(const e_config_protocol_type& type);
|
||||||
void set_memory_model_name(const std::string& memory_model_name);
|
void set_memory_model_name(const std::string& memory_model_name);
|
||||||
|
@ -41,9 +43,11 @@ class ConfigProtocol {
|
||||||
void set_bl_protocol_type(const e_blwl_protocol_type& type);
|
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_name(const std::string& memory_model_name);
|
||||||
void set_bl_memory_model(const CircuitModelId& memory_model);
|
void set_bl_memory_model(const CircuitModelId& memory_model);
|
||||||
|
void set_bl_num_banks(const size_t& num_banks);
|
||||||
void set_wl_protocol_type(const e_blwl_protocol_type& type);
|
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_name(const std::string& memory_model_name);
|
||||||
void set_wl_memory_model(const CircuitModelId& memory_model);
|
void set_wl_memory_model(const CircuitModelId& memory_model);
|
||||||
|
void set_wl_num_banks(const size_t& num_banks);
|
||||||
private: /* Internal data */
|
private: /* Internal data */
|
||||||
/* The type of configuration protocol.
|
/* The type of configuration protocol.
|
||||||
* In other words, it is about how to organize and access each configurable memory
|
* In other words, it is about how to organize and access each configurable memory
|
||||||
|
@ -62,13 +66,17 @@ class ConfigProtocol {
|
||||||
* - bl/wl_memory_model: defines the circuit model to be used when building shift register chains for BL/WL configuration.
|
* - 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
|
* It must be a valid CCFF circuit model. This is only applicable when shift-register protocol is selected
|
||||||
* for BL or WL.
|
* for BL or WL.
|
||||||
|
* - bl/wl_num_banks: defines the number of independent shift register chains (with separated head and tail ports)
|
||||||
|
* for a given BL protocol per configuration region
|
||||||
*/
|
*/
|
||||||
e_blwl_protocol_type bl_protocol_type_ = BLWL_PROTOCOL_DECODER;
|
e_blwl_protocol_type bl_protocol_type_ = BLWL_PROTOCOL_DECODER;
|
||||||
std::string bl_memory_model_name_;
|
std::string bl_memory_model_name_;
|
||||||
CircuitModelId bl_memory_model_;
|
CircuitModelId bl_memory_model_;
|
||||||
|
size_t bl_num_banks_;
|
||||||
e_blwl_protocol_type wl_protocol_type_ = BLWL_PROTOCOL_DECODER;
|
e_blwl_protocol_type wl_protocol_type_ = BLWL_PROTOCOL_DECODER;
|
||||||
std::string wl_memory_model_name_;
|
std::string wl_memory_model_name_;
|
||||||
CircuitModelId wl_memory_model_;
|
CircuitModelId wl_memory_model_;
|
||||||
|
size_t wl_num_banks_;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -484,6 +484,9 @@ void read_xml_circuit_port(pugi::xml_node& xml_port,
|
||||||
/* Identify if the port is in programming purpose, by default it is NOT */
|
/* Identify if the port is in programming purpose, by default it is NOT */
|
||||||
circuit_lib.set_port_is_prog(port, get_attribute(xml_port, "is_prog", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false));
|
circuit_lib.set_port_is_prog(port, get_attribute(xml_port, "is_prog", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false));
|
||||||
|
|
||||||
|
/* Identify if the port is in shift register purpose, by default it is NOT */
|
||||||
|
circuit_lib.set_port_is_shift_register(port, get_attribute(xml_port, "is_shift_register", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false));
|
||||||
|
|
||||||
/* Identify if the port is to enable programming for FPGAs, by default it is NOT */
|
/* Identify if the port is to enable programming for FPGAs, by default it is NOT */
|
||||||
circuit_lib.set_port_is_config_enable(port, get_attribute(xml_port, "is_config_enable", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false));
|
circuit_lib.set_port_is_config_enable(port, get_attribute(xml_port, "is_config_enable", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false));
|
||||||
|
|
||||||
|
|
|
@ -68,9 +68,13 @@ void read_xml_bl_protocol(pugi::xml_node& xml_bl_protocol,
|
||||||
|
|
||||||
config_protocol.set_bl_protocol_type(blwl_protocol_type);
|
config_protocol.set_bl_protocol_type(blwl_protocol_type);
|
||||||
|
|
||||||
/* Find the memory model, only applicable to shift-registor protocol */
|
/* only applicable to shift-registor protocol
|
||||||
|
* - Find the memory model to build shift register chains
|
||||||
|
* - Find the number of shift register chains for each protocol
|
||||||
|
*/
|
||||||
if (BLWL_PROTOCOL_SHIFT_REGISTER == blwl_protocol_type) {
|
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());
|
config_protocol.set_bl_memory_model_name(get_attribute(xml_bl_protocol, "circuit_model_name", loc_data).as_string());
|
||||||
|
config_protocol.set_bl_num_banks(get_attribute(xml_bl_protocol, "num_banks", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,9 +98,13 @@ void read_xml_wl_protocol(pugi::xml_node& xml_wl_protocol,
|
||||||
|
|
||||||
config_protocol.set_wl_protocol_type(blwl_protocol_type);
|
config_protocol.set_wl_protocol_type(blwl_protocol_type);
|
||||||
|
|
||||||
/* Find the memory model, only applicable to shift-registor protocol */
|
/* only applicable to shift-registor protocol
|
||||||
|
* - Find the memory model to build shift register chains
|
||||||
|
* - Find the number of shift register chains for each protocol
|
||||||
|
*/
|
||||||
if (BLWL_PROTOCOL_SHIFT_REGISTER == blwl_protocol_type) {
|
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());
|
config_protocol.set_wl_memory_model_name(get_attribute(xml_wl_protocol, "circuit_model_name", loc_data).as_string());
|
||||||
|
config_protocol.set_wl_num_banks(get_attribute(xml_wl_protocol, "num_banks", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ e_sim_accuracy_type string_to_sim_accuracy_type(const std::string& type_string)
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Parse XML codes of a <clock> line to an object of simulation setting
|
* Parse XML codes of a <clock> line under <operating> to an object of simulation setting
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
static
|
static
|
||||||
void read_xml_operating_clock_override_setting(pugi::xml_node& xml_clock_override_setting,
|
void read_xml_operating_clock_override_setting(pugi::xml_node& xml_clock_override_setting,
|
||||||
|
@ -62,6 +62,40 @@ void read_xml_operating_clock_override_setting(pugi::xml_node& xml_clock_overrid
|
||||||
sim_setting.set_clock_frequency(clock_id, get_attribute(xml_clock_override_setting, "frequency", loc_data).as_float(0.));
|
sim_setting.set_clock_frequency(clock_id, get_attribute(xml_clock_override_setting, "frequency", loc_data).as_float(0.));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Parse XML codes of a <clock> line under <programming> to an object of simulation setting
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
void read_xml_programming_clock_override_setting(pugi::xml_node& xml_clock_override_setting,
|
||||||
|
const pugiutil::loc_data& loc_data,
|
||||||
|
openfpga::SimulationSetting& sim_setting) {
|
||||||
|
std::string clock_name = get_attribute(xml_clock_override_setting, "name", loc_data).as_string();
|
||||||
|
|
||||||
|
/* Create a new clock override object in the sim_setting object with the given name */
|
||||||
|
SimulationClockId clock_id = sim_setting.create_clock(clock_name);
|
||||||
|
|
||||||
|
/* Report if the clock creation failed, this is due to a conflicts in naming*/
|
||||||
|
if (false == sim_setting.valid_clock_id(clock_id)) {
|
||||||
|
archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_clock_override_setting),
|
||||||
|
"Fail to create simulation clock '%s', it may share the same name as other simulation clock definition!\n",
|
||||||
|
clock_name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parse port information */
|
||||||
|
openfpga::PortParser clock_port_parser(get_attribute(xml_clock_override_setting, "port", loc_data).as_string());
|
||||||
|
sim_setting.set_clock_port(clock_id, clock_port_parser.port());
|
||||||
|
|
||||||
|
/* Parse frequency information */
|
||||||
|
std::string clock_freq_str = get_attribute(xml_clock_override_setting, "frequency", loc_data).as_string();
|
||||||
|
if (std::string("auto") != clock_freq_str) {
|
||||||
|
sim_setting.set_clock_frequency(clock_id, get_attribute(xml_clock_override_setting, "frequency", loc_data).as_float(0.));
|
||||||
|
}
|
||||||
|
|
||||||
|
sim_setting.set_clock_is_programming(clock_id, true);
|
||||||
|
|
||||||
|
sim_setting.set_clock_is_shift_register(clock_id, get_attribute(xml_clock_override_setting, "is_shift_register", loc_data).as_bool(false));
|
||||||
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Parse XML codes of a <clock_setting> to an object of simulation setting
|
* Parse XML codes of a <clock_setting> to an object of simulation setting
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
|
@ -102,6 +136,15 @@ void read_xml_clock_setting(pugi::xml_node& xml_clock_setting,
|
||||||
pugi::xml_node xml_programming_clock_setting = get_single_child(xml_clock_setting, "programming", loc_data);
|
pugi::xml_node xml_programming_clock_setting = get_single_child(xml_clock_setting, "programming", loc_data);
|
||||||
|
|
||||||
sim_setting.set_programming_clock_frequency(get_attribute(xml_programming_clock_setting, "frequency", loc_data).as_float(0.));
|
sim_setting.set_programming_clock_frequency(get_attribute(xml_programming_clock_setting, "frequency", loc_data).as_float(0.));
|
||||||
|
|
||||||
|
/* Iterate over multiple operating clock settings and parse one by one */
|
||||||
|
for (pugi::xml_node xml_clock : xml_programming_clock_setting.children()) {
|
||||||
|
/* Error out if the XML child has an invalid name! */
|
||||||
|
if (xml_clock.name() != std::string("clock")) {
|
||||||
|
bad_tag(xml_clock, loc_data, xml_programming_clock_setting, {"clock"});
|
||||||
|
}
|
||||||
|
read_xml_programming_clock_override_setting(xml_clock, loc_data, sim_setting);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
|
|
|
@ -16,6 +16,36 @@ SimulationSetting::simulation_clock_range SimulationSetting::clocks() const {
|
||||||
return vtr::make_range(clock_ids_.begin(), clock_ids_.end());
|
return vtr::make_range(clock_ids_.begin(), clock_ids_.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::vector<SimulationClockId> SimulationSetting::operating_clocks() const {
|
||||||
|
std::vector<SimulationClockId> op_clks;
|
||||||
|
for (const SimulationClockId& clk : clocks()) {
|
||||||
|
if (!clock_is_programming(clk)) {
|
||||||
|
op_clks.push_back(clk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return op_clks;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<SimulationClockId> SimulationSetting::programming_clocks() const {
|
||||||
|
std::vector<SimulationClockId> prog_clks;
|
||||||
|
for (const SimulationClockId& clk : clocks()) {
|
||||||
|
if (clock_is_programming(clk)) {
|
||||||
|
prog_clks.push_back(clk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return prog_clks;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<SimulationClockId> SimulationSetting::programming_shift_register_clocks() const {
|
||||||
|
std::vector<SimulationClockId> prog_clks;
|
||||||
|
for (const SimulationClockId& clk : clocks()) {
|
||||||
|
if (clock_is_programming(clk) && clock_is_shift_register(clk)) {
|
||||||
|
prog_clks.push_back(clk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return prog_clks;
|
||||||
|
}
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* Constructors
|
* Constructors
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
@ -53,6 +83,16 @@ float SimulationSetting::clock_frequency(const SimulationClockId& clock_id) cons
|
||||||
return clock_frequencies_[clock_id];
|
return clock_frequencies_[clock_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SimulationSetting::clock_is_programming(const SimulationClockId& clock_id) const {
|
||||||
|
VTR_ASSERT(valid_clock_id(clock_id));
|
||||||
|
return clock_is_programming_[clock_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SimulationSetting::clock_is_shift_register(const SimulationClockId& clock_id) const {
|
||||||
|
VTR_ASSERT(valid_clock_id(clock_id));
|
||||||
|
return clock_is_shift_register_[clock_id];
|
||||||
|
}
|
||||||
|
|
||||||
bool SimulationSetting::auto_select_num_clock_cycles() const {
|
bool SimulationSetting::auto_select_num_clock_cycles() const {
|
||||||
return 0 == num_clock_cycles_;
|
return 0 == num_clock_cycles_;
|
||||||
}
|
}
|
||||||
|
@ -157,6 +197,8 @@ SimulationClockId SimulationSetting::create_clock(const std::string& name) {
|
||||||
clock_names_.push_back(name);
|
clock_names_.push_back(name);
|
||||||
clock_ports_.emplace_back();
|
clock_ports_.emplace_back();
|
||||||
clock_frequencies_.push_back(0.);
|
clock_frequencies_.push_back(0.);
|
||||||
|
clock_is_programming_.push_back(false);
|
||||||
|
clock_is_shift_register_.push_back(false);
|
||||||
|
|
||||||
/* Register in the name-to-id map */
|
/* Register in the name-to-id map */
|
||||||
clock_name2ids_[name] = clock_id;
|
clock_name2ids_[name] = clock_id;
|
||||||
|
@ -176,6 +218,18 @@ void SimulationSetting::set_clock_frequency(const SimulationClockId& clock_id,
|
||||||
clock_frequencies_[clock_id] = frequency;
|
clock_frequencies_[clock_id] = frequency;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SimulationSetting::set_clock_is_programming(const SimulationClockId& clock_id,
|
||||||
|
const float& is_prog) {
|
||||||
|
VTR_ASSERT(valid_clock_id(clock_id));
|
||||||
|
clock_is_programming_[clock_id] = is_prog;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SimulationSetting::set_clock_is_shift_register(const SimulationClockId& clock_id,
|
||||||
|
const float& is_sr) {
|
||||||
|
VTR_ASSERT(valid_clock_id(clock_id));
|
||||||
|
clock_is_shift_register_[clock_id] = is_sr;
|
||||||
|
}
|
||||||
|
|
||||||
void SimulationSetting::set_num_clock_cycles(const size_t& num_clk_cycles) {
|
void SimulationSetting::set_num_clock_cycles(const size_t& num_clk_cycles) {
|
||||||
num_clock_cycles_ = num_clk_cycles;
|
num_clock_cycles_ = num_clk_cycles;
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,9 @@ class SimulationSetting {
|
||||||
SimulationSetting();
|
SimulationSetting();
|
||||||
public: /* Accessors: aggregates */
|
public: /* Accessors: aggregates */
|
||||||
simulation_clock_range clocks() const;
|
simulation_clock_range clocks() const;
|
||||||
|
std::vector<SimulationClockId> operating_clocks() const;
|
||||||
|
std::vector<SimulationClockId> programming_clocks() const;
|
||||||
|
std::vector<SimulationClockId> programming_shift_register_clocks() const;
|
||||||
public: /* Public Accessors */
|
public: /* Public Accessors */
|
||||||
float default_operating_clock_frequency() const;
|
float default_operating_clock_frequency() const;
|
||||||
float programming_clock_frequency() const;
|
float programming_clock_frequency() const;
|
||||||
|
@ -69,6 +72,8 @@ class SimulationSetting {
|
||||||
std::string clock_name(const SimulationClockId& clock_id) const;
|
std::string clock_name(const SimulationClockId& clock_id) const;
|
||||||
BasicPort clock_port(const SimulationClockId& clock_id) const;
|
BasicPort clock_port(const SimulationClockId& clock_id) const;
|
||||||
float clock_frequency(const SimulationClockId& clock_id) const;
|
float clock_frequency(const SimulationClockId& clock_id) const;
|
||||||
|
bool clock_is_programming(const SimulationClockId& clock_id) const;
|
||||||
|
bool clock_is_shift_register(const SimulationClockId& clock_id) const;
|
||||||
bool auto_select_num_clock_cycles() const;
|
bool auto_select_num_clock_cycles() const;
|
||||||
size_t num_clock_cycles() const;
|
size_t num_clock_cycles() const;
|
||||||
float operating_clock_frequency_slack() const;
|
float operating_clock_frequency_slack() const;
|
||||||
|
@ -102,6 +107,10 @@ class SimulationSetting {
|
||||||
const BasicPort& port);
|
const BasicPort& port);
|
||||||
void set_clock_frequency(const SimulationClockId& clock_id,
|
void set_clock_frequency(const SimulationClockId& clock_id,
|
||||||
const float& frequency);
|
const float& frequency);
|
||||||
|
void set_clock_is_programming(const SimulationClockId& clock_id,
|
||||||
|
const float& is_prog);
|
||||||
|
void set_clock_is_shift_register(const SimulationClockId& clock_id,
|
||||||
|
const float& is_sr);
|
||||||
void set_num_clock_cycles(const size_t& num_clk_cycles);
|
void set_num_clock_cycles(const size_t& num_clk_cycles);
|
||||||
void set_operating_clock_frequency_slack(const float& op_clk_freq_slack);
|
void set_operating_clock_frequency_slack(const float& op_clk_freq_slack);
|
||||||
void set_simulation_temperature(const float& sim_temp);
|
void set_simulation_temperature(const float& sim_temp);
|
||||||
|
@ -150,6 +159,8 @@ class SimulationSetting {
|
||||||
vtr::vector<SimulationClockId, std::string> clock_names_;
|
vtr::vector<SimulationClockId, std::string> clock_names_;
|
||||||
vtr::vector<SimulationClockId, BasicPort> clock_ports_;
|
vtr::vector<SimulationClockId, BasicPort> clock_ports_;
|
||||||
vtr::vector<SimulationClockId, float> clock_frequencies_;
|
vtr::vector<SimulationClockId, float> clock_frequencies_;
|
||||||
|
vtr::vector<SimulationClockId, bool> clock_is_programming_;
|
||||||
|
vtr::vector<SimulationClockId, bool> clock_is_shift_register_;
|
||||||
|
|
||||||
/* Fast name-to-id lookup */
|
/* Fast name-to-id lookup */
|
||||||
std::map<std::string, SimulationClockId> clock_name2ids_;
|
std::map<std::string, SimulationClockId> clock_name2ids_;
|
||||||
|
|
|
@ -220,6 +220,10 @@ void write_xml_circuit_port(std::fstream& fp,
|
||||||
write_xml_attribute(fp, "is_prog", "true");
|
write_xml_attribute(fp, "is_prog", "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (true == circuit_lib.port_is_shift_register(port)) {
|
||||||
|
write_xml_attribute(fp, "is_shift_register", "true");
|
||||||
|
}
|
||||||
|
|
||||||
if (true == circuit_lib.port_is_config_enable(port)) {
|
if (true == circuit_lib.port_is_config_enable(port)) {
|
||||||
write_xml_attribute(fp, "is_config_enable", "true");
|
write_xml_attribute(fp, "is_config_enable", "true");
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,24 @@ void write_xml_config_organization(std::fstream& fp,
|
||||||
openfpga::check_file_stream(fname, fp);
|
openfpga::check_file_stream(fname, fp);
|
||||||
|
|
||||||
fp << "\t\t" << "<organization";
|
fp << "\t\t" << "<organization";
|
||||||
|
|
||||||
write_xml_attribute(fp, "type", CONFIG_PROTOCOL_TYPE_STRING[config_protocol.type()]);
|
write_xml_attribute(fp, "type", CONFIG_PROTOCOL_TYPE_STRING[config_protocol.type()]);
|
||||||
write_xml_attribute(fp, "circuit_model_name", circuit_lib.model_name(config_protocol.memory_model()).c_str());
|
write_xml_attribute(fp, "circuit_model_name", circuit_lib.model_name(config_protocol.memory_model()).c_str());
|
||||||
|
|
||||||
fp << "/>" << "\n";
|
fp << "/>" << "\n";
|
||||||
|
|
||||||
|
/* Output BL/WL protocols */
|
||||||
|
fp << "\t\t\t" << "<bl";
|
||||||
|
write_xml_attribute(fp, "protocol", BLWL_PROTOCOL_TYPE_STRING[config_protocol.bl_protocol_type()]);
|
||||||
|
write_xml_attribute(fp, "circuit_model_name", circuit_lib.model_name(config_protocol.bl_memory_model()).c_str());
|
||||||
|
write_xml_attribute(fp, "num_banks", config_protocol.bl_num_banks());
|
||||||
|
fp << "/>" << "\n";
|
||||||
|
|
||||||
|
fp << "\t\t\t" << "<wl";
|
||||||
|
write_xml_attribute(fp, "protocol", BLWL_PROTOCOL_TYPE_STRING[config_protocol.wl_protocol_type()]);
|
||||||
|
write_xml_attribute(fp, "circuit_model_name", circuit_lib.model_name(config_protocol.wl_memory_model()).c_str());
|
||||||
|
write_xml_attribute(fp, "num_banks", config_protocol.wl_num_banks());
|
||||||
|
fp << "/>" << "\n";
|
||||||
|
|
||||||
|
fp << "\t" << "</organization>" << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
|
|
|
@ -41,7 +41,7 @@ void write_xml_clock_setting(std::fstream& fp,
|
||||||
fp << ">" << "\n";
|
fp << ">" << "\n";
|
||||||
|
|
||||||
/* Output clock information one by one */
|
/* Output clock information one by one */
|
||||||
for (const SimulationClockId& clock_id : sim_setting.clocks()) {
|
for (const SimulationClockId& clock_id : sim_setting.operating_clocks()) {
|
||||||
fp << "\t\t\t" << "<clock";
|
fp << "\t\t\t" << "<clock";
|
||||||
write_xml_attribute(fp, "name", sim_setting.clock_name(clock_id).c_str());
|
write_xml_attribute(fp, "name", sim_setting.clock_name(clock_id).c_str());
|
||||||
write_xml_attribute(fp, "port", generate_xml_port_name(sim_setting.clock_port(clock_id)).c_str());
|
write_xml_attribute(fp, "port", generate_xml_port_name(sim_setting.clock_port(clock_id)).c_str());
|
||||||
|
@ -52,9 +52,22 @@ void write_xml_clock_setting(std::fstream& fp,
|
||||||
fp << "\t\t" << "</operating";
|
fp << "\t\t" << "</operating";
|
||||||
fp << ">" << "\n";
|
fp << ">" << "\n";
|
||||||
|
|
||||||
fp << "\t\t" << "<operating";
|
fp << "\t\t" << "<programming";
|
||||||
write_xml_attribute(fp, "frequency", sim_setting.programming_clock_frequency());
|
write_xml_attribute(fp, "frequency", sim_setting.programming_clock_frequency());
|
||||||
fp << "/>" << "\n";
|
fp << ">" << "\n";
|
||||||
|
|
||||||
|
/* Output clock information one by one */
|
||||||
|
for (const SimulationClockId& clock_id : sim_setting.programming_clocks()) {
|
||||||
|
fp << "\t\t\t" << "<clock";
|
||||||
|
write_xml_attribute(fp, "name", sim_setting.clock_name(clock_id).c_str());
|
||||||
|
write_xml_attribute(fp, "port", generate_xml_port_name(sim_setting.clock_port(clock_id)).c_str());
|
||||||
|
write_xml_attribute(fp, "frequency", std::to_string(sim_setting.clock_frequency(clock_id)).c_str());
|
||||||
|
write_xml_attribute(fp, "is_shift_register", std::to_string(sim_setting.clock_is_shift_register(clock_id)).c_str());
|
||||||
|
fp << ">" << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
fp << "\t\t" << "</programming";
|
||||||
|
fp << ">" << "\n";
|
||||||
|
|
||||||
fp << "\t" << "</clock_setting>" << "\n";
|
fp << "\t" << "</clock_setting>" << "\n";
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,18 @@ namespace openfpga {
|
||||||
/* Top-level module name */
|
/* Top-level module name */
|
||||||
constexpr char* FPGA_TOP_MODULE_NAME = "fpga_top";
|
constexpr char* FPGA_TOP_MODULE_NAME = "fpga_top";
|
||||||
|
|
||||||
|
/* Configuration chain naming constant strings */
|
||||||
constexpr char* CONFIGURABLE_MEMORY_CHAIN_IN_NAME = "ccff_head";
|
constexpr char* CONFIGURABLE_MEMORY_CHAIN_IN_NAME = "ccff_head";
|
||||||
constexpr char* CONFIGURABLE_MEMORY_CHAIN_OUT_NAME = "ccff_tail";
|
constexpr char* CONFIGURABLE_MEMORY_CHAIN_OUT_NAME = "ccff_tail";
|
||||||
constexpr char* CONFIGURABLE_MEMORY_DATA_OUT_NAME = "mem_out";
|
constexpr char* CONFIGURABLE_MEMORY_DATA_OUT_NAME = "mem_out";
|
||||||
constexpr char* CONFIGURABLE_MEMORY_INVERTED_DATA_OUT_NAME = "mem_outb";
|
constexpr char* CONFIGURABLE_MEMORY_INVERTED_DATA_OUT_NAME = "mem_outb";
|
||||||
|
constexpr char* BL_SHIFT_REGISTER_CHAIN_HEAD_NAME = "bl_sr_head";
|
||||||
|
constexpr char* BL_SHIFT_REGISTER_CHAIN_TAIL_NAME = "bl_sr_tail";
|
||||||
|
constexpr char* BL_SHIFT_REGISTER_CHAIN_BL_OUT_NAME = "bl_sr_bl_out";
|
||||||
|
constexpr char* WL_SHIFT_REGISTER_CHAIN_HEAD_NAME = "wl_sr_head";
|
||||||
|
constexpr char* WL_SHIFT_REGISTER_CHAIN_TAIL_NAME = "wl_sr_tail";
|
||||||
|
constexpr char* WL_SHIFT_REGISTER_CHAIN_WL_OUT_NAME = "wl_sr_wl_out";
|
||||||
|
constexpr char* WL_SHIFT_REGISTER_CHAIN_WLR_OUT_NAME = "wl_sr_wlr_out";
|
||||||
|
|
||||||
/* IO PORT */
|
/* IO PORT */
|
||||||
/* Prefix of global input, output and inout ports of FPGA fabric */
|
/* Prefix of global input, output and inout ports of FPGA fabric */
|
||||||
|
|
|
@ -103,6 +103,7 @@ int build_fabric(OpenfpgaContext& openfpga_ctx,
|
||||||
|
|
||||||
curr_status = build_device_module_graph(openfpga_ctx.mutable_module_graph(),
|
curr_status = build_device_module_graph(openfpga_ctx.mutable_module_graph(),
|
||||||
openfpga_ctx.mutable_decoder_lib(),
|
openfpga_ctx.mutable_decoder_lib(),
|
||||||
|
openfpga_ctx.mutable_blwl_shift_register_banks(),
|
||||||
const_cast<const OpenfpgaContext&>(openfpga_ctx),
|
const_cast<const OpenfpgaContext&>(openfpga_ctx),
|
||||||
g_vpr_ctx.device(),
|
g_vpr_ctx.device(),
|
||||||
cmd_context.option_enable(cmd, opt_frame_view),
|
cmd_context.option_enable(cmd, opt_frame_view),
|
||||||
|
@ -123,6 +124,7 @@ int build_fabric(OpenfpgaContext& openfpga_ctx,
|
||||||
|
|
||||||
/* Build fabric global port information */
|
/* Build fabric global port information */
|
||||||
openfpga_ctx.mutable_fabric_global_port_info() = build_fabric_global_port_info(openfpga_ctx.module_graph(),
|
openfpga_ctx.mutable_fabric_global_port_info() = build_fabric_global_port_info(openfpga_ctx.module_graph(),
|
||||||
|
openfpga_ctx.arch().config_protocol,
|
||||||
openfpga_ctx.arch().tile_annotations,
|
openfpga_ctx.arch().tile_annotations,
|
||||||
openfpga_ctx.arch().circuit_lib);
|
openfpga_ctx.arch().circuit_lib);
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "device_rr_gsb.h"
|
#include "device_rr_gsb.h"
|
||||||
#include "io_location_map.h"
|
#include "io_location_map.h"
|
||||||
#include "fabric_global_port_info.h"
|
#include "fabric_global_port_info.h"
|
||||||
|
#include "memory_bank_shift_register_banks.h"
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* This file includes the declaration of the date structure
|
* This file includes the declaration of the date structure
|
||||||
|
@ -65,6 +66,7 @@ class OpenfpgaContext : public Context {
|
||||||
const openfpga::DeviceRRGSB& device_rr_gsb() const { return device_rr_gsb_; }
|
const openfpga::DeviceRRGSB& device_rr_gsb() const { return device_rr_gsb_; }
|
||||||
const openfpga::MuxLibrary& mux_lib() const { return mux_lib_; }
|
const openfpga::MuxLibrary& mux_lib() const { return mux_lib_; }
|
||||||
const openfpga::DecoderLibrary& decoder_lib() const { return decoder_lib_; }
|
const openfpga::DecoderLibrary& decoder_lib() const { return decoder_lib_; }
|
||||||
|
const std::array<openfpga::MemoryBankShiftRegisterBanks, 2>& blwl_shift_register_banks() { return blwl_sr_banks_; }
|
||||||
const openfpga::TileDirect& tile_direct() const { return tile_direct_; }
|
const openfpga::TileDirect& tile_direct() const { return tile_direct_; }
|
||||||
const openfpga::ModuleManager& module_graph() const { return module_graph_; }
|
const openfpga::ModuleManager& module_graph() const { return module_graph_; }
|
||||||
const openfpga::FlowManager& flow_manager() const { return flow_manager_; }
|
const openfpga::FlowManager& flow_manager() const { return flow_manager_; }
|
||||||
|
@ -87,6 +89,7 @@ class OpenfpgaContext : public Context {
|
||||||
openfpga::DeviceRRGSB& mutable_device_rr_gsb() { return device_rr_gsb_; }
|
openfpga::DeviceRRGSB& mutable_device_rr_gsb() { return device_rr_gsb_; }
|
||||||
openfpga::MuxLibrary& mutable_mux_lib() { return mux_lib_; }
|
openfpga::MuxLibrary& mutable_mux_lib() { return mux_lib_; }
|
||||||
openfpga::DecoderLibrary& mutable_decoder_lib() { return decoder_lib_; }
|
openfpga::DecoderLibrary& mutable_decoder_lib() { return decoder_lib_; }
|
||||||
|
std::array<openfpga::MemoryBankShiftRegisterBanks, 2>& mutable_blwl_shift_register_banks() { return blwl_sr_banks_; }
|
||||||
openfpga::TileDirect& mutable_tile_direct() { return tile_direct_; }
|
openfpga::TileDirect& mutable_tile_direct() { return tile_direct_; }
|
||||||
openfpga::ModuleManager& mutable_module_graph() { return module_graph_; }
|
openfpga::ModuleManager& mutable_module_graph() { return module_graph_; }
|
||||||
openfpga::FlowManager& mutable_flow_manager() { return flow_manager_; }
|
openfpga::FlowManager& mutable_flow_manager() { return flow_manager_; }
|
||||||
|
@ -132,6 +135,11 @@ class OpenfpgaContext : public Context {
|
||||||
/* Inner/inter-column/row tile direct connections */
|
/* Inner/inter-column/row tile direct connections */
|
||||||
openfpga::TileDirect tile_direct_;
|
openfpga::TileDirect tile_direct_;
|
||||||
|
|
||||||
|
/* Library of shift register banks that control BLs and WLs
|
||||||
|
* @note Only used when memory bank is used as configuration protocol
|
||||||
|
*/
|
||||||
|
std::array<openfpga::MemoryBankShiftRegisterBanks, 2> blwl_sr_banks_;
|
||||||
|
|
||||||
/* Fabric module graph */
|
/* Fabric module graph */
|
||||||
openfpga::ModuleManager module_graph_;
|
openfpga::ModuleManager module_graph_;
|
||||||
openfpga::IoLocationMap io_location_map_;
|
openfpga::IoLocationMap io_location_map_;
|
||||||
|
|
|
@ -822,6 +822,23 @@ std::string generate_regional_blwl_port_name(const std::string& blwl_port_prefix
|
||||||
return blwl_port_prefix + std::string("_config_region_") + std::to_string(size_t(region_id));
|
return blwl_port_prefix + std::string("_config_region_") + std::to_string(size_t(region_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* Generate the module name for a shift register chain which configures BLs
|
||||||
|
*********************************************************************/
|
||||||
|
std::string generate_bl_shift_register_module_name(const std::string& memory_model_name,
|
||||||
|
const size_t& shift_register_size) {
|
||||||
|
return std::string("bl_shift_register_") + memory_model_name + std::string("_size") + std::to_string(shift_register_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* Generate the module name for a shift register chain which configures WLs
|
||||||
|
*********************************************************************/
|
||||||
|
std::string generate_wl_shift_register_module_name(const std::string& memory_model_name,
|
||||||
|
const size_t& shift_register_size) {
|
||||||
|
return std::string("wl_shift_register_") + memory_model_name + std::string("_size") + std::to_string(shift_register_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
* Generate the port name for the input bus of a routing multiplexer
|
* Generate the port name for the input bus of a routing multiplexer
|
||||||
* This is very useful in Verilog code generation where the inputs of
|
* This is very useful in Verilog code generation where the inputs of
|
||||||
|
|
|
@ -187,6 +187,12 @@ std::string generate_sram_local_port_name(const CircuitLibrary& circuit_lib,
|
||||||
std::string generate_regional_blwl_port_name(const std::string& blwl_port_prefix,
|
std::string generate_regional_blwl_port_name(const std::string& blwl_port_prefix,
|
||||||
const ConfigRegionId& region_id);
|
const ConfigRegionId& region_id);
|
||||||
|
|
||||||
|
std::string generate_bl_shift_register_module_name(const std::string& memory_model_name,
|
||||||
|
const size_t& shift_register_size);
|
||||||
|
|
||||||
|
std::string generate_wl_shift_register_module_name(const std::string& memory_model_name,
|
||||||
|
const size_t& shift_register_size);
|
||||||
|
|
||||||
std::string generate_mux_input_bus_port_name(const CircuitLibrary& circuit_lib,
|
std::string generate_mux_input_bus_port_name(const CircuitLibrary& circuit_lib,
|
||||||
const CircuitModelId& mux_model,
|
const CircuitModelId& mux_model,
|
||||||
const size_t& mux_size,
|
const size_t& mux_size,
|
||||||
|
|
|
@ -52,6 +52,7 @@ int write_fabric_verilog(OpenfpgaContext& openfpga_ctx,
|
||||||
|
|
||||||
fpga_fabric_verilog(openfpga_ctx.mutable_module_graph(),
|
fpga_fabric_verilog(openfpga_ctx.mutable_module_graph(),
|
||||||
openfpga_ctx.mutable_verilog_netlists(),
|
openfpga_ctx.mutable_verilog_netlists(),
|
||||||
|
openfpga_ctx.blwl_shift_register_banks(),
|
||||||
openfpga_ctx.arch().circuit_lib,
|
openfpga_ctx.arch().circuit_lib,
|
||||||
openfpga_ctx.mux_lib(),
|
openfpga_ctx.mux_lib(),
|
||||||
openfpga_ctx.decoder_lib(),
|
openfpga_ctx.decoder_lib(),
|
||||||
|
|
|
@ -31,6 +31,7 @@ namespace openfpga {
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
int build_device_module_graph(ModuleManager& module_manager,
|
int build_device_module_graph(ModuleManager& module_manager,
|
||||||
DecoderLibrary& decoder_lib,
|
DecoderLibrary& decoder_lib,
|
||||||
|
std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
|
||||||
const OpenfpgaContext& openfpga_ctx,
|
const OpenfpgaContext& openfpga_ctx,
|
||||||
const DeviceContext& vpr_device_ctx,
|
const DeviceContext& vpr_device_ctx,
|
||||||
const bool& frame_view,
|
const bool& frame_view,
|
||||||
|
@ -112,6 +113,7 @@ int build_device_module_graph(ModuleManager& module_manager,
|
||||||
/* Build FPGA fabric top-level module */
|
/* Build FPGA fabric top-level module */
|
||||||
status = build_top_module(module_manager,
|
status = build_top_module(module_manager,
|
||||||
decoder_lib,
|
decoder_lib,
|
||||||
|
blwl_sr_banks,
|
||||||
openfpga_ctx.arch().circuit_lib,
|
openfpga_ctx.arch().circuit_lib,
|
||||||
openfpga_ctx.vpr_device_annotation(),
|
openfpga_ctx.vpr_device_annotation(),
|
||||||
vpr_device_ctx.grid,
|
vpr_device_ctx.grid,
|
||||||
|
|
|
@ -17,6 +17,7 @@ namespace openfpga {
|
||||||
|
|
||||||
int build_device_module_graph(ModuleManager& module_manager,
|
int build_device_module_graph(ModuleManager& module_manager,
|
||||||
DecoderLibrary& decoder_lib,
|
DecoderLibrary& decoder_lib,
|
||||||
|
std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
|
||||||
const OpenfpgaContext& openfpga_ctx,
|
const OpenfpgaContext& openfpga_ctx,
|
||||||
const DeviceContext& vpr_device_ctx,
|
const DeviceContext& vpr_device_ctx,
|
||||||
const bool& frame_view,
|
const bool& frame_view,
|
||||||
|
|
|
@ -24,6 +24,7 @@ namespace openfpga {
|
||||||
* and cache their port/pin index in the top-level module
|
* and cache their port/pin index in the top-level module
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
FabricGlobalPortInfo build_fabric_global_port_info(const ModuleManager& module_manager,
|
FabricGlobalPortInfo build_fabric_global_port_info(const ModuleManager& module_manager,
|
||||||
|
const ConfigProtocol& config_protocol,
|
||||||
const TileAnnotation& tile_annotation,
|
const TileAnnotation& tile_annotation,
|
||||||
const CircuitLibrary& circuit_lib) {
|
const CircuitLibrary& circuit_lib) {
|
||||||
vtr::ScopedStartFinishTimer timer("Create global port info for top module");
|
vtr::ScopedStartFinishTimer timer("Create global port info for top module");
|
||||||
|
@ -53,8 +54,18 @@ FabricGlobalPortInfo build_fabric_global_port_info(const ModuleManager& module_m
|
||||||
fabric_global_port_info.set_global_port_is_reset(fabric_port, circuit_lib.port_is_reset(global_port));
|
fabric_global_port_info.set_global_port_is_reset(fabric_port, circuit_lib.port_is_reset(global_port));
|
||||||
fabric_global_port_info.set_global_port_is_set(fabric_port, circuit_lib.port_is_set(global_port));
|
fabric_global_port_info.set_global_port_is_set(fabric_port, circuit_lib.port_is_set(global_port));
|
||||||
fabric_global_port_info.set_global_port_is_prog(fabric_port, circuit_lib.port_is_prog(global_port));
|
fabric_global_port_info.set_global_port_is_prog(fabric_port, circuit_lib.port_is_prog(global_port));
|
||||||
|
fabric_global_port_info.set_global_port_is_shift_register(fabric_port, circuit_lib.port_is_shift_register(global_port));
|
||||||
fabric_global_port_info.set_global_port_is_config_enable(fabric_port, circuit_lib.port_is_config_enable(global_port));
|
fabric_global_port_info.set_global_port_is_config_enable(fabric_port, circuit_lib.port_is_config_enable(global_port));
|
||||||
fabric_global_port_info.set_global_port_default_value(fabric_port, circuit_lib.port_default_value(global_port));
|
fabric_global_port_info.set_global_port_default_value(fabric_port, circuit_lib.port_default_value(global_port));
|
||||||
|
|
||||||
|
/* Special for BL/WL shift register models: we should identify which clock belongs to BL and which clock belongs to WL */
|
||||||
|
if (config_protocol.bl_memory_model() == circuit_lib.port_parent_model(global_port)) {
|
||||||
|
fabric_global_port_info.set_global_port_is_bl(fabric_port, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config_protocol.wl_memory_model() == circuit_lib.port_parent_model(global_port)) {
|
||||||
|
fabric_global_port_info.set_global_port_is_wl(fabric_port, true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add the global ports from tile annotation */
|
/* Add the global ports from tile annotation */
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
namespace openfpga {
|
namespace openfpga {
|
||||||
|
|
||||||
FabricGlobalPortInfo build_fabric_global_port_info(const ModuleManager& module_manager,
|
FabricGlobalPortInfo build_fabric_global_port_info(const ModuleManager& module_manager,
|
||||||
|
const ConfigProtocol& config_protocol,
|
||||||
const TileAnnotation& tile_annotation,
|
const TileAnnotation& tile_annotation,
|
||||||
const CircuitLibrary& circuit_lib);
|
const CircuitLibrary& circuit_lib);
|
||||||
|
|
||||||
|
|
|
@ -78,7 +78,6 @@ void add_module_input_nets_to_mem_modules(ModuleManager& module_manager,
|
||||||
* pin of output port of the memory module, where W is the size of port
|
* pin of output port of the memory module, where W is the size of port
|
||||||
* 3. It assumes fixed port name for output ports
|
* 3. It assumes fixed port name for output ports
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
static
|
|
||||||
std::vector<ModuleNetId> add_module_output_nets_to_chain_mem_modules(ModuleManager& module_manager,
|
std::vector<ModuleNetId> add_module_output_nets_to_chain_mem_modules(ModuleManager& module_manager,
|
||||||
const ModuleId& mem_module,
|
const ModuleId& mem_module,
|
||||||
const std::string& mem_module_output_name,
|
const std::string& mem_module_output_name,
|
||||||
|
|
|
@ -16,6 +16,15 @@
|
||||||
/* begin namespace openfpga */
|
/* begin namespace openfpga */
|
||||||
namespace openfpga {
|
namespace openfpga {
|
||||||
|
|
||||||
|
std::vector<ModuleNetId> add_module_output_nets_to_chain_mem_modules(ModuleManager& module_manager,
|
||||||
|
const ModuleId& mem_module,
|
||||||
|
const std::string& mem_module_output_name,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitPortId& circuit_port,
|
||||||
|
const ModuleId& child_module,
|
||||||
|
const size_t& child_index,
|
||||||
|
const size_t& child_instance);
|
||||||
|
|
||||||
void build_memory_modules(ModuleManager& module_manager,
|
void build_memory_modules(ModuleManager& module_manager,
|
||||||
DecoderLibrary& arch_decoder_lib,
|
DecoderLibrary& arch_decoder_lib,
|
||||||
const MuxLibrary& mux_lib,
|
const MuxLibrary& mux_lib,
|
||||||
|
|
|
@ -283,6 +283,7 @@ vtr::Matrix<size_t> add_top_module_connection_block_instances(ModuleManager& mod
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
int build_top_module(ModuleManager& module_manager,
|
int build_top_module(ModuleManager& module_manager,
|
||||||
DecoderLibrary& decoder_lib,
|
DecoderLibrary& decoder_lib,
|
||||||
|
std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
const VprDeviceAnnotation& vpr_device_annotation,
|
const VprDeviceAnnotation& vpr_device_annotation,
|
||||||
const DeviceGrid& grids,
|
const DeviceGrid& grids,
|
||||||
|
@ -341,12 +342,6 @@ int build_top_module(ModuleManager& module_manager,
|
||||||
tile_direct, arch_direct);
|
tile_direct, arch_direct);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add global ports to the pb_module:
|
|
||||||
* This is a much easier job after adding sub modules (instances),
|
|
||||||
* we just need to find all the global ports from the child modules and build a list of it
|
|
||||||
*/
|
|
||||||
add_module_global_ports_from_child_modules(module_manager, top_module);
|
|
||||||
|
|
||||||
/* Add global ports from grid ports that are defined as global in tile annotation */
|
/* Add global ports from grid ports that are defined as global in tile annotation */
|
||||||
status = add_top_module_global_ports_from_grid_modules(module_manager, top_module, tile_annotation, vpr_device_annotation, grids, grid_instance_ids);
|
status = add_top_module_global_ports_from_grid_modules(module_manager, top_module, tile_annotation, vpr_device_annotation, grids, grid_instance_ids);
|
||||||
if (CMD_EXEC_FATAL_ERROR == status) {
|
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||||
|
@ -420,13 +415,20 @@ int build_top_module(ModuleManager& module_manager,
|
||||||
* This is a one-shot addition that covers all the memory modules in this pb module!
|
* This is a one-shot addition that covers all the memory modules in this pb module!
|
||||||
*/
|
*/
|
||||||
if (0 < module_manager.configurable_children(top_module).size()) {
|
if (0 < module_manager.configurable_children(top_module).size()) {
|
||||||
add_top_module_nets_memory_config_bus(module_manager, decoder_lib,
|
add_top_module_nets_memory_config_bus(module_manager, decoder_lib, blwl_sr_banks,
|
||||||
top_module,
|
top_module,
|
||||||
circuit_lib,
|
circuit_lib,
|
||||||
config_protocol, circuit_lib.design_tech_type(sram_model),
|
config_protocol, circuit_lib.design_tech_type(sram_model),
|
||||||
top_module_num_config_bits);
|
top_module_num_config_bits);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add global ports to the top module:
|
||||||
|
* This is a much easier job after adding sub modules (instances),
|
||||||
|
* we just need to find all the global ports from the child modules and build a list of it
|
||||||
|
* @note This function is called after the add_top_module_nets_memory_config_bus() because it may add some sub modules
|
||||||
|
*/
|
||||||
|
add_module_global_ports_from_child_modules(module_manager, top_module);
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#include "config_protocol.h"
|
#include "config_protocol.h"
|
||||||
#include "module_manager.h"
|
#include "module_manager.h"
|
||||||
#include "fabric_key.h"
|
#include "fabric_key.h"
|
||||||
|
#include "memory_bank_shift_register_banks.h"
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Function declaration
|
* Function declaration
|
||||||
|
@ -29,6 +30,7 @@ namespace openfpga {
|
||||||
|
|
||||||
int build_top_module(ModuleManager& module_manager,
|
int build_top_module(ModuleManager& module_manager,
|
||||||
DecoderLibrary& decoder_lib,
|
DecoderLibrary& decoder_lib,
|
||||||
|
std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
const VprDeviceAnnotation& vpr_device_annotation,
|
const VprDeviceAnnotation& vpr_device_annotation,
|
||||||
const DeviceGrid& grids,
|
const DeviceGrid& grids,
|
||||||
|
|
|
@ -1735,6 +1735,7 @@ void add_top_module_nets_cmos_memory_frame_config_bus(ModuleManager& module_mana
|
||||||
static
|
static
|
||||||
void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
|
void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
|
||||||
DecoderLibrary& decoder_lib,
|
DecoderLibrary& decoder_lib,
|
||||||
|
std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
|
||||||
const ModuleId& parent_module,
|
const ModuleId& parent_module,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
const ConfigProtocol& config_protocol,
|
const ConfigProtocol& config_protocol,
|
||||||
|
@ -1754,7 +1755,8 @@ void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
|
||||||
add_top_module_nets_cmos_memory_bank_config_bus(module_manager, decoder_lib, parent_module, num_config_bits);
|
add_top_module_nets_cmos_memory_bank_config_bus(module_manager, decoder_lib, parent_module, num_config_bits);
|
||||||
break;
|
break;
|
||||||
case CONFIG_MEM_QL_MEMORY_BANK:
|
case CONFIG_MEM_QL_MEMORY_BANK:
|
||||||
add_top_module_nets_cmos_ql_memory_bank_config_bus(module_manager, decoder_lib, parent_module, circuit_lib, config_protocol, num_config_bits);
|
add_top_module_nets_cmos_ql_memory_bank_config_bus(module_manager, decoder_lib, blwl_sr_banks,
|
||||||
|
parent_module, circuit_lib, config_protocol, num_config_bits);
|
||||||
break;
|
break;
|
||||||
case CONFIG_MEM_FRAME_BASED:
|
case CONFIG_MEM_FRAME_BASED:
|
||||||
add_top_module_nets_cmos_memory_frame_config_bus(module_manager, decoder_lib, parent_module, num_config_bits);
|
add_top_module_nets_cmos_memory_frame_config_bus(module_manager, decoder_lib, parent_module, num_config_bits);
|
||||||
|
@ -1800,6 +1802,7 @@ void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
|
void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
|
||||||
DecoderLibrary& decoder_lib,
|
DecoderLibrary& decoder_lib,
|
||||||
|
std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
|
||||||
const ModuleId& parent_module,
|
const ModuleId& parent_module,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
const ConfigProtocol& config_protocol,
|
const ConfigProtocol& config_protocol,
|
||||||
|
@ -1811,6 +1814,7 @@ void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
|
||||||
switch (mem_tech) {
|
switch (mem_tech) {
|
||||||
case CIRCUIT_MODEL_DESIGN_CMOS:
|
case CIRCUIT_MODEL_DESIGN_CMOS:
|
||||||
add_top_module_nets_cmos_memory_config_bus(module_manager, decoder_lib,
|
add_top_module_nets_cmos_memory_config_bus(module_manager, decoder_lib,
|
||||||
|
blwl_sr_banks,
|
||||||
parent_module,
|
parent_module,
|
||||||
circuit_lib,
|
circuit_lib,
|
||||||
config_protocol,
|
config_protocol,
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "device_rr_gsb.h"
|
#include "device_rr_gsb.h"
|
||||||
#include "fabric_key.h"
|
#include "fabric_key.h"
|
||||||
#include "config_protocol.h"
|
#include "config_protocol.h"
|
||||||
|
#include "memory_bank_shift_register_banks.h"
|
||||||
#include "build_top_module_memory_utils.h"
|
#include "build_top_module_memory_utils.h"
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
|
@ -64,6 +65,7 @@ void add_top_module_sram_ports(ModuleManager& module_manager,
|
||||||
|
|
||||||
void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
|
void add_top_module_nets_memory_config_bus(ModuleManager& module_manager,
|
||||||
DecoderLibrary& decoder_lib,
|
DecoderLibrary& decoder_lib,
|
||||||
|
std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
|
||||||
const ModuleId& parent_module,
|
const ModuleId& parent_module,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
const ConfigProtocol& config_protocol,
|
const ConfigProtocol& config_protocol,
|
||||||
|
|
|
@ -24,12 +24,331 @@
|
||||||
#include "decoder_library_utils.h"
|
#include "decoder_library_utils.h"
|
||||||
#include "module_manager_utils.h"
|
#include "module_manager_utils.h"
|
||||||
#include "memory_bank_utils.h"
|
#include "memory_bank_utils.h"
|
||||||
|
#include "build_memory_modules.h"
|
||||||
#include "build_decoder_modules.h"
|
#include "build_decoder_modules.h"
|
||||||
|
#include "memory_bank_shift_register_banks.h"
|
||||||
#include "build_top_module_memory_bank.h"
|
#include "build_top_module_memory_bank.h"
|
||||||
|
|
||||||
/* begin namespace openfpga */
|
/* begin namespace openfpga */
|
||||||
namespace openfpga {
|
namespace openfpga {
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Connect all the memory modules under the parent module in a chain
|
||||||
|
*
|
||||||
|
* +--------+ +--------+ +--------+
|
||||||
|
* ccff_head --->| Memory |--->| Memory |--->... --->| Memory |----> ccff_tail
|
||||||
|
* | Module | | Module | | Module |
|
||||||
|
* | [0] | | [1] | | [N-1] |
|
||||||
|
* +--------+ +--------+ +--------+
|
||||||
|
* For the 1st memory module:
|
||||||
|
* net source is the configuration chain head of the primitive module
|
||||||
|
* net sink is the configuration chain head of the next memory module
|
||||||
|
*
|
||||||
|
* For the rest of memory modules:
|
||||||
|
* net source is the configuration chain tail of the previous memory module
|
||||||
|
* net sink is the configuration chain head of the next memory module
|
||||||
|
*
|
||||||
|
* Note that:
|
||||||
|
* This function is designed for memory modules ONLY!
|
||||||
|
* Do not use it to replace the
|
||||||
|
* add_module_nets_cmos_memory_chain_config_bus() !!!
|
||||||
|
*********************************************************************/
|
||||||
|
static
|
||||||
|
void add_module_nets_to_ql_memory_bank_shift_register_module(ModuleManager& module_manager,
|
||||||
|
const ModuleId& parent_module,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitPortId& model_input_port,
|
||||||
|
const CircuitPortId& model_output_port,
|
||||||
|
const std::string& chain_head_port_name,
|
||||||
|
const std::string& chain_tail_port_name) {
|
||||||
|
for (size_t mem_index = 0; mem_index < module_manager.configurable_children(parent_module).size(); ++mem_index) {
|
||||||
|
ModuleId net_src_module_id;
|
||||||
|
size_t net_src_instance_id;
|
||||||
|
ModulePortId net_src_port_id;
|
||||||
|
|
||||||
|
ModuleId net_sink_module_id;
|
||||||
|
size_t net_sink_instance_id;
|
||||||
|
ModulePortId net_sink_port_id;
|
||||||
|
|
||||||
|
if (0 == mem_index) {
|
||||||
|
/* Find the port name of configuration chain head */
|
||||||
|
std::string src_port_name = chain_head_port_name;
|
||||||
|
net_src_module_id = parent_module;
|
||||||
|
net_src_instance_id = 0;
|
||||||
|
net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name);
|
||||||
|
|
||||||
|
/* Find the port name of next memory module */
|
||||||
|
std::string sink_port_name = circuit_lib.port_prefix(model_input_port);
|
||||||
|
net_sink_module_id = module_manager.configurable_children(parent_module)[mem_index];
|
||||||
|
net_sink_instance_id = module_manager.configurable_child_instances(parent_module)[mem_index];
|
||||||
|
net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name);
|
||||||
|
} else {
|
||||||
|
/* Find the port name of previous memory module */
|
||||||
|
std::string src_port_name = circuit_lib.port_prefix(model_output_port);
|
||||||
|
net_src_module_id = module_manager.configurable_children(parent_module)[mem_index - 1];
|
||||||
|
net_src_instance_id = module_manager.configurable_child_instances(parent_module)[mem_index - 1];
|
||||||
|
net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name);
|
||||||
|
|
||||||
|
/* Find the port name of next memory module */
|
||||||
|
std::string sink_port_name = circuit_lib.port_prefix(model_input_port);
|
||||||
|
net_sink_module_id = module_manager.configurable_children(parent_module)[mem_index];
|
||||||
|
net_sink_instance_id = module_manager.configurable_child_instances(parent_module)[mem_index];
|
||||||
|
net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the pin id for source port */
|
||||||
|
BasicPort net_src_port = module_manager.module_port(net_src_module_id, net_src_port_id);
|
||||||
|
/* Get the pin id for sink port */
|
||||||
|
BasicPort net_sink_port = module_manager.module_port(net_sink_module_id, net_sink_port_id);
|
||||||
|
/* Port sizes of source and sink should match */
|
||||||
|
VTR_ASSERT(net_src_port.get_width() == net_sink_port.get_width());
|
||||||
|
|
||||||
|
/* Create a net for each pin */
|
||||||
|
for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) {
|
||||||
|
/* Create a net and add source and sink to it */
|
||||||
|
ModuleNetId net = create_module_source_pin_net(module_manager, parent_module, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]);
|
||||||
|
/* Add net sink */
|
||||||
|
module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* For the last memory module:
|
||||||
|
* net source is the configuration chain tail of the previous memory module
|
||||||
|
* net sink is the configuration chain tail of the primitive module
|
||||||
|
*/
|
||||||
|
/* Find the port name of previous memory module */
|
||||||
|
std::string src_port_name = circuit_lib.port_prefix(model_output_port);
|
||||||
|
ModuleId net_src_module_id = module_manager.configurable_children(parent_module).back();
|
||||||
|
size_t net_src_instance_id = module_manager.configurable_child_instances(parent_module).back();
|
||||||
|
ModulePortId net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name);
|
||||||
|
|
||||||
|
/* Find the port name of next memory module */
|
||||||
|
std::string sink_port_name = chain_tail_port_name;
|
||||||
|
ModuleId net_sink_module_id = parent_module;
|
||||||
|
size_t net_sink_instance_id = 0;
|
||||||
|
ModulePortId net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name);
|
||||||
|
|
||||||
|
/* Get the pin id for source port */
|
||||||
|
BasicPort net_src_port = module_manager.module_port(net_src_module_id, net_src_port_id);
|
||||||
|
/* Get the pin id for sink port */
|
||||||
|
BasicPort net_sink_port = module_manager.module_port(net_sink_module_id, net_sink_port_id);
|
||||||
|
/* Port sizes of source and sink should match */
|
||||||
|
VTR_ASSERT(net_src_port.get_width() == net_sink_port.get_width());
|
||||||
|
|
||||||
|
/* Create a net for each pin */
|
||||||
|
for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) {
|
||||||
|
/* Create a net and add source and sink to it */
|
||||||
|
ModuleNetId net = create_module_source_pin_net(module_manager, parent_module, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]);
|
||||||
|
/* Add net sink */
|
||||||
|
module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* BL shift register chain module organization
|
||||||
|
*
|
||||||
|
* +-------+ +-------+ +-------+
|
||||||
|
* chain --->| CCFF |--->| CCFF |--->... --->| CCFF |---->chain
|
||||||
|
* input&clock | [0] | | [1] | | [N-1] | output
|
||||||
|
* +-------+ +-------+ +-------+
|
||||||
|
* | | ... | config-memory output
|
||||||
|
* v v v
|
||||||
|
* +-----------------------------------------+
|
||||||
|
* | BLs of configurable modules |
|
||||||
|
*
|
||||||
|
********************************************************************/
|
||||||
|
static
|
||||||
|
ModuleId build_bl_shift_register_chain_module(ModuleManager& module_manager,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const std::string& module_name,
|
||||||
|
const CircuitModelId& sram_model,
|
||||||
|
const size_t& num_mems) {
|
||||||
|
|
||||||
|
/* Get the input ports from the SRAM */
|
||||||
|
std::vector<CircuitPortId> sram_input_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_INPUT, true);
|
||||||
|
VTR_ASSERT(1 == sram_input_ports.size());
|
||||||
|
|
||||||
|
/* Get the output ports from the SRAM */
|
||||||
|
std::vector<CircuitPortId> sram_output_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_OUTPUT, true);
|
||||||
|
VTR_ASSERT(1 == sram_output_ports.size());
|
||||||
|
|
||||||
|
/* Get the BL ports from the SRAM */
|
||||||
|
std::vector<CircuitPortId> sram_bl_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_BL, true);
|
||||||
|
VTR_ASSERT(1 == sram_bl_ports.size());
|
||||||
|
|
||||||
|
/* Create a module and add to the module manager */
|
||||||
|
ModuleId mem_module = module_manager.add_module(module_name);
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_id(mem_module));
|
||||||
|
|
||||||
|
/* Label module usage */
|
||||||
|
module_manager.set_module_usage(mem_module, ModuleManager::MODULE_CONFIG);
|
||||||
|
|
||||||
|
/* Add an input port, which is the head of configuration chain in the module */
|
||||||
|
/* TODO: restriction!!!
|
||||||
|
* consider only the first input of the CCFF model as the D port,
|
||||||
|
* which will be connected to the head of the chain
|
||||||
|
*/
|
||||||
|
BasicPort chain_head_port(BL_SHIFT_REGISTER_CHAIN_HEAD_NAME,
|
||||||
|
circuit_lib.port_size(sram_input_ports[0]));
|
||||||
|
module_manager.add_port(mem_module, chain_head_port, ModuleManager::MODULE_INPUT_PORT);
|
||||||
|
|
||||||
|
/* Add an output port, which is the tail of configuration chain in the module */
|
||||||
|
/* TODO: restriction!!!
|
||||||
|
* consider only the first output of the CCFF model as the Q port,
|
||||||
|
* which will be connected to the tail of the chain
|
||||||
|
*/
|
||||||
|
BasicPort chain_tail_port(BL_SHIFT_REGISTER_CHAIN_TAIL_NAME,
|
||||||
|
circuit_lib.port_size(sram_output_ports[0]));
|
||||||
|
module_manager.add_port(mem_module, chain_tail_port, ModuleManager::MODULE_OUTPUT_PORT);
|
||||||
|
|
||||||
|
/* Add the output ports to output BL signals */
|
||||||
|
BasicPort chain_bl_port(BL_SHIFT_REGISTER_CHAIN_BL_OUT_NAME,
|
||||||
|
num_mems);
|
||||||
|
module_manager.add_port(mem_module, chain_bl_port, ModuleManager::MODULE_OUTPUT_PORT);
|
||||||
|
|
||||||
|
/* Find the sram module in the module manager */
|
||||||
|
ModuleId sram_mem_module = module_manager.find_module(circuit_lib.model_name(sram_model));
|
||||||
|
|
||||||
|
/* Instanciate each submodule */
|
||||||
|
for (size_t i = 0; i < num_mems; ++i) {
|
||||||
|
size_t sram_mem_instance = module_manager.num_instance(mem_module, sram_mem_module);
|
||||||
|
module_manager.add_child_module(mem_module, sram_mem_module);
|
||||||
|
module_manager.add_configurable_child(mem_module, sram_mem_module, sram_mem_instance);
|
||||||
|
|
||||||
|
/* Build module nets to wire bl outputs of sram modules to BL outputs of memory module */
|
||||||
|
for (const auto& child_module_output_port : sram_bl_ports) {
|
||||||
|
std::string chain_output_port_name = std::string(BL_SHIFT_REGISTER_CHAIN_BL_OUT_NAME);
|
||||||
|
add_module_output_nets_to_chain_mem_modules(module_manager, mem_module,
|
||||||
|
chain_output_port_name, circuit_lib,
|
||||||
|
child_module_output_port,
|
||||||
|
sram_mem_module, i, sram_mem_instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build module nets to wire the configuration chain */
|
||||||
|
add_module_nets_to_ql_memory_bank_shift_register_module(module_manager, mem_module,
|
||||||
|
circuit_lib, sram_input_ports[0], sram_output_ports[0],
|
||||||
|
std::string(BL_SHIFT_REGISTER_CHAIN_HEAD_NAME),
|
||||||
|
std::string(BL_SHIFT_REGISTER_CHAIN_TAIL_NAME));
|
||||||
|
|
||||||
|
/* Add global ports to the pb_module:
|
||||||
|
* This is a much easier job after adding sub modules (instances),
|
||||||
|
* we just need to find all the global ports from the child modules and build a list of it
|
||||||
|
*/
|
||||||
|
add_module_global_ports_from_child_modules(module_manager, mem_module);
|
||||||
|
|
||||||
|
return mem_module;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* WL shift register chain module organization
|
||||||
|
*
|
||||||
|
* +-------+ +-------+ +-------+
|
||||||
|
* chain --->| CCFF |--->| CCFF |--->... --->| CCFF |---->chain
|
||||||
|
* input&clock | [0] | | [1] | | [N-1] | output
|
||||||
|
* +-------+ +-------+ +-------+
|
||||||
|
* | | ... | config-memory output
|
||||||
|
* v v v
|
||||||
|
* +-----------------------------------------+
|
||||||
|
* | WL/WLRs of configurable modules |
|
||||||
|
*
|
||||||
|
********************************************************************/
|
||||||
|
static
|
||||||
|
ModuleId build_wl_shift_register_chain_module(ModuleManager& module_manager,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const std::string& module_name,
|
||||||
|
const CircuitModelId& sram_model,
|
||||||
|
const size_t& num_mems) {
|
||||||
|
|
||||||
|
/* Get the input ports from the SRAM */
|
||||||
|
std::vector<CircuitPortId> sram_input_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_INPUT, true);
|
||||||
|
VTR_ASSERT(1 == sram_input_ports.size());
|
||||||
|
|
||||||
|
/* Get the output ports from the SRAM */
|
||||||
|
std::vector<CircuitPortId> sram_output_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_OUTPUT, true);
|
||||||
|
VTR_ASSERT(1 == sram_output_ports.size());
|
||||||
|
|
||||||
|
/* Get the WL ports from the SRAM */
|
||||||
|
std::vector<CircuitPortId> sram_wl_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_WL, true);
|
||||||
|
VTR_ASSERT(1 == sram_wl_ports.size());
|
||||||
|
|
||||||
|
/* Get the optional WLR ports from the SRAM */
|
||||||
|
std::vector<CircuitPortId> sram_wlr_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_WLR, true);
|
||||||
|
VTR_ASSERT(0 == sram_wlr_ports.size() || 1 == sram_wlr_ports.size());
|
||||||
|
|
||||||
|
/* Create a module and add to the module manager */
|
||||||
|
ModuleId mem_module = module_manager.add_module(module_name);
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_id(mem_module));
|
||||||
|
|
||||||
|
/* Label module usage */
|
||||||
|
module_manager.set_module_usage(mem_module, ModuleManager::MODULE_CONFIG);
|
||||||
|
|
||||||
|
/* Add an input port, which is the head of configuration chain in the module */
|
||||||
|
/* TODO: restriction!!!
|
||||||
|
* consider only the first input of the CCFF model as the D port,
|
||||||
|
* which will be connected to the head of the chain
|
||||||
|
*/
|
||||||
|
BasicPort chain_head_port(WL_SHIFT_REGISTER_CHAIN_HEAD_NAME,
|
||||||
|
circuit_lib.port_size(sram_input_ports[0]));
|
||||||
|
module_manager.add_port(mem_module, chain_head_port, ModuleManager::MODULE_INPUT_PORT);
|
||||||
|
|
||||||
|
/* Add an output port, which is the tail of configuration chain in the module */
|
||||||
|
/* TODO: restriction!!!
|
||||||
|
* consider only the first output of the CCFF model as the Q port,
|
||||||
|
* which will be connected to the tail of the chain
|
||||||
|
*/
|
||||||
|
BasicPort chain_tail_port(WL_SHIFT_REGISTER_CHAIN_TAIL_NAME,
|
||||||
|
circuit_lib.port_size(sram_output_ports[0]));
|
||||||
|
module_manager.add_port(mem_module, chain_tail_port, ModuleManager::MODULE_OUTPUT_PORT);
|
||||||
|
|
||||||
|
/* Add the output ports to output BL signals */
|
||||||
|
BasicPort chain_wl_port(WL_SHIFT_REGISTER_CHAIN_WL_OUT_NAME,
|
||||||
|
num_mems);
|
||||||
|
module_manager.add_port(mem_module, chain_wl_port, ModuleManager::MODULE_OUTPUT_PORT);
|
||||||
|
|
||||||
|
/* Find the sram module in the module manager */
|
||||||
|
ModuleId sram_mem_module = module_manager.find_module(circuit_lib.model_name(sram_model));
|
||||||
|
|
||||||
|
/* Instanciate each submodule */
|
||||||
|
for (size_t i = 0; i < num_mems; ++i) {
|
||||||
|
size_t sram_mem_instance = module_manager.num_instance(mem_module, sram_mem_module);
|
||||||
|
module_manager.add_child_module(mem_module, sram_mem_module);
|
||||||
|
module_manager.add_configurable_child(mem_module, sram_mem_module, sram_mem_instance);
|
||||||
|
|
||||||
|
/* Build module nets to wire wl outputs of sram modules to WL outputs of memory module */
|
||||||
|
for (const auto& child_module_output_port : sram_wl_ports) {
|
||||||
|
std::string chain_output_port_name = std::string(WL_SHIFT_REGISTER_CHAIN_WL_OUT_NAME);
|
||||||
|
add_module_output_nets_to_chain_mem_modules(module_manager, mem_module,
|
||||||
|
chain_output_port_name, circuit_lib,
|
||||||
|
child_module_output_port,
|
||||||
|
sram_mem_module, i, sram_mem_instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build module nets to wire wlr outputs of sram modules to WLR outputs of memory module */
|
||||||
|
for (const auto& child_module_output_port : sram_wlr_ports) {
|
||||||
|
std::string chain_output_port_name = std::string(WL_SHIFT_REGISTER_CHAIN_WLR_OUT_NAME);
|
||||||
|
add_module_output_nets_to_chain_mem_modules(module_manager, mem_module,
|
||||||
|
chain_output_port_name, circuit_lib,
|
||||||
|
child_module_output_port,
|
||||||
|
sram_mem_module, i, sram_mem_instance);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build module nets to wire the configuration chain */
|
||||||
|
add_module_nets_to_ql_memory_bank_shift_register_module(module_manager, mem_module,
|
||||||
|
circuit_lib, sram_input_ports[0], sram_output_ports[0],
|
||||||
|
std::string(WL_SHIFT_REGISTER_CHAIN_HEAD_NAME),
|
||||||
|
std::string(WL_SHIFT_REGISTER_CHAIN_TAIL_NAME));
|
||||||
|
|
||||||
|
/* Add global ports to the pb_module:
|
||||||
|
* This is a much easier job after adding sub modules (instances),
|
||||||
|
* we just need to find all the global ports from the child modules and build a list of it
|
||||||
|
*/
|
||||||
|
add_module_global_ports_from_child_modules(module_manager, mem_module);
|
||||||
|
|
||||||
|
return mem_module;
|
||||||
|
}
|
||||||
|
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
* This function to add nets for quicklogic memory banks
|
* This function to add nets for quicklogic memory banks
|
||||||
* Each configuration region has independent memory bank circuitry
|
* Each configuration region has independent memory bank circuitry
|
||||||
|
@ -745,6 +1064,396 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_flatten_config_bus(ModuleManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* This function to add nets for QuickLogic memory bank
|
||||||
|
* We build the net connects between the head ports of shift register banks
|
||||||
|
* and the head ports of top-level module
|
||||||
|
* @note This function is applicable to both BL and WL shift registers
|
||||||
|
**********************************************************************/
|
||||||
|
static
|
||||||
|
void add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_heads(ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const MemoryBankShiftRegisterBanks& sr_banks,
|
||||||
|
const std::string& head_port_name) {
|
||||||
|
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||||
|
ModulePortId blsr_head_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(head_port_name, config_region));
|
||||||
|
BasicPort blsr_head_port_info = module_manager.module_port(top_module, blsr_head_port);
|
||||||
|
|
||||||
|
for (size_t iinst = 0; iinst < sr_banks.shift_register_bank_modules(config_region).size(); ++iinst) {
|
||||||
|
ModuleId sr_bank_module = sr_banks.shift_register_bank_modules(config_region)[iinst];
|
||||||
|
size_t sr_bank_instance = sr_banks.shift_register_bank_instances(config_region)[iinst];
|
||||||
|
VTR_ASSERT(sr_bank_module);
|
||||||
|
|
||||||
|
ModulePortId sr_module_head_port = module_manager.find_module_port(sr_bank_module, head_port_name);
|
||||||
|
BasicPort sr_module_head_port_info = module_manager.module_port(sr_bank_module, sr_module_head_port);
|
||||||
|
VTR_ASSERT(sr_module_head_port_info.get_width() == blsr_head_port_info.get_width());
|
||||||
|
for (size_t ipin = 0; ipin < sr_module_head_port_info.pins().size(); ++ipin) {
|
||||||
|
/* Create net */
|
||||||
|
ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
|
||||||
|
top_module, 0,
|
||||||
|
blsr_head_port,
|
||||||
|
blsr_head_port_info.pins()[ipin]);
|
||||||
|
VTR_ASSERT(ModuleNetId::INVALID() != net);
|
||||||
|
|
||||||
|
/* Add net sink */
|
||||||
|
module_manager.add_module_net_sink(top_module, net,
|
||||||
|
sr_bank_module, sr_bank_instance, sr_module_head_port, sr_module_head_port_info.pins()[ipin]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* This function to add nets for QuickLogic memory bank
|
||||||
|
* We build the net connects between the head ports of shift register banks
|
||||||
|
* and the head ports of top-level module
|
||||||
|
* @note This function is applicable to both BL and WL shift registers
|
||||||
|
**********************************************************************/
|
||||||
|
static
|
||||||
|
void add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_tails(ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const MemoryBankShiftRegisterBanks& sr_banks,
|
||||||
|
const std::string& tail_port_name) {
|
||||||
|
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||||
|
ModulePortId blsr_tail_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(tail_port_name, config_region));
|
||||||
|
BasicPort blsr_tail_port_info = module_manager.module_port(top_module, blsr_tail_port);
|
||||||
|
|
||||||
|
for (size_t iinst = 0; iinst < sr_banks.shift_register_bank_modules(config_region).size(); ++iinst) {
|
||||||
|
ModuleId sr_bank_module = sr_banks.shift_register_bank_modules(config_region)[iinst];
|
||||||
|
size_t sr_bank_instance = sr_banks.shift_register_bank_instances(config_region)[iinst];
|
||||||
|
VTR_ASSERT(sr_bank_module);
|
||||||
|
|
||||||
|
ModulePortId sr_module_tail_port = module_manager.find_module_port(sr_bank_module, tail_port_name);
|
||||||
|
BasicPort sr_module_tail_port_info = module_manager.module_port(sr_bank_module, sr_module_tail_port);
|
||||||
|
VTR_ASSERT(sr_module_tail_port_info.get_width() == blsr_tail_port_info.get_width());
|
||||||
|
for (size_t ipin = 0; ipin < sr_module_tail_port_info.pins().size(); ++ipin) {
|
||||||
|
/* Create net */
|
||||||
|
ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
|
||||||
|
sr_bank_module, sr_bank_instance,
|
||||||
|
sr_module_tail_port, sr_module_tail_port_info.pins()[ipin]);
|
||||||
|
VTR_ASSERT(ModuleNetId::INVALID() != net);
|
||||||
|
|
||||||
|
/* Add net sink */
|
||||||
|
module_manager.add_module_net_sink(top_module, net,
|
||||||
|
top_module, 0,
|
||||||
|
blsr_tail_port, blsr_tail_port_info.pins()[ipin]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
* Add BL/WL nets from shift register module to each configurable child
|
||||||
|
* BL pins of shift register module are connected to the BL input pins of each PB/CB/SB
|
||||||
|
* For all the PB/CB/SB in the same column, they share the same set of BLs
|
||||||
|
* A quick example
|
||||||
|
*
|
||||||
|
* +-----------------------+
|
||||||
|
* | Shift register chain |
|
||||||
|
* +-----------------------+
|
||||||
|
* BL[i .. i + sqrt(N)]
|
||||||
|
* |
|
||||||
|
* | CLB[1][H]
|
||||||
|
* | +---------+
|
||||||
|
* | | SRAM |
|
||||||
|
* +-->| [0..N] |
|
||||||
|
* | +---------+
|
||||||
|
* |
|
||||||
|
* ...
|
||||||
|
* | CLB[1][1]
|
||||||
|
* | +---------+
|
||||||
|
* | | SRAM |
|
||||||
|
* +-->| [0..N] |
|
||||||
|
* | +---------+
|
||||||
|
* |
|
||||||
|
* @note optional BL/WL is applicable to WLR, which may not always exist
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_blwls(ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const MemoryBankShiftRegisterBanks& sr_banks,
|
||||||
|
const std::string& sr_blwl_port_name,
|
||||||
|
const std::string& child_blwl_port_name,
|
||||||
|
const bool& optional_blwl = false) {
|
||||||
|
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||||
|
for (size_t iinst = 0; iinst < sr_banks.shift_register_bank_modules(config_region).size(); ++iinst) {
|
||||||
|
ModuleId sr_bank_module = sr_banks.shift_register_bank_modules(config_region)[iinst];
|
||||||
|
size_t sr_bank_instance = sr_banks.shift_register_bank_instances(config_region)[iinst];
|
||||||
|
VTR_ASSERT(sr_bank_module);
|
||||||
|
|
||||||
|
ModulePortId sr_module_blwl_port = module_manager.find_module_port(sr_bank_module, sr_blwl_port_name);
|
||||||
|
if (!sr_module_blwl_port && optional_blwl) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
VTR_ASSERT(sr_module_blwl_port);
|
||||||
|
BasicPort sr_module_blwl_port_info = module_manager.module_port(sr_bank_module, sr_module_blwl_port);
|
||||||
|
|
||||||
|
|
||||||
|
for (size_t sink_id = 0; sink_id < sr_banks.shift_register_bank_sink_child_ids(config_region, sr_bank_module, sr_bank_instance).size(); ++sink_id) {
|
||||||
|
size_t child_id = sr_banks.shift_register_bank_sink_child_ids(config_region, sr_bank_module, sr_bank_instance)[sink_id];
|
||||||
|
ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id];
|
||||||
|
size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[child_id];
|
||||||
|
|
||||||
|
/* Find the BL port */
|
||||||
|
ModulePortId child_blwl_port = module_manager.find_module_port(child_module, child_blwl_port_name);
|
||||||
|
BasicPort child_blwl_port_info = module_manager.module_port(child_module, child_blwl_port);
|
||||||
|
|
||||||
|
size_t cur_sr_module_blwl_pin_id = sr_banks.shift_register_bank_source_blwl_ids(config_region, sr_bank_module, sr_bank_instance)[sink_id];
|
||||||
|
|
||||||
|
/* Create net */
|
||||||
|
ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
|
||||||
|
sr_bank_module, sr_bank_instance,
|
||||||
|
sr_module_blwl_port,
|
||||||
|
sr_module_blwl_port_info.pins()[cur_sr_module_blwl_pin_id]);
|
||||||
|
VTR_ASSERT(ModuleNetId::INVALID() != net);
|
||||||
|
|
||||||
|
/* Add net sink */
|
||||||
|
size_t sink_pin_id = sr_banks.shift_register_bank_sink_pin_ids(config_region, sr_bank_module, sr_bank_instance)[sink_id];
|
||||||
|
module_manager.add_module_net_sink(top_module, net,
|
||||||
|
child_module, child_instance, child_blwl_port, sink_pin_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* This function to add nets for quicklogic memory banks using shift registers to manipulate BL/WLs
|
||||||
|
* Each configuration region has independent BL/WL shift register banks
|
||||||
|
* - Find the number of BLs and WLs required for each region
|
||||||
|
* - Find the number of BL and WL shift register chains required for each region
|
||||||
|
* - Create the module of shift register chain for each unique size
|
||||||
|
* - Create nets to connect from top-level module inputs to BL/WL shift register chains
|
||||||
|
* - Create nets to connect from BL/WL shift register chains to BL/WL of configurable children
|
||||||
|
*
|
||||||
|
* @note this function only adds the BL protocol
|
||||||
|
*
|
||||||
|
* Detailed schematic of each memory bank:
|
||||||
|
* @note The numbers are just made to show a simplified example, practical cases are more complicated!
|
||||||
|
*
|
||||||
|
* sr_clk sr_head sr_tail
|
||||||
|
* | | ^
|
||||||
|
* v v |
|
||||||
|
* +-------------------------------------------------+
|
||||||
|
* | Bit Line shift register chains |
|
||||||
|
* +-------------------------------------------------+
|
||||||
|
* | | |
|
||||||
|
* +---------+ BL[0:9] BL[10:17] BL[18:22]
|
||||||
|
* | | | | |
|
||||||
|
* | | | | |
|
||||||
|
* | Word |--WL[0:3]-->-----------+---------------+---- ... |------+-->
|
||||||
|
* | | | | | | | |
|
||||||
|
* | Line | | v | v | v
|
||||||
|
* | | | +-------+ | +-------+ | +------+
|
||||||
|
* | shift | +-->| SRAM | +-->| SRAM | +->| SRAM |
|
||||||
|
* | | | | [0:8] | | | [0:5] | ... | | [0:7]|
|
||||||
|
* | register| | +-------+ | +-------+ | +------+
|
||||||
|
* | | | | |
|
||||||
|
* | chains |--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_shift_register_config_bus(ModuleManager& module_manager,
|
||||||
|
MemoryBankShiftRegisterBanks& sr_banks,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const ConfigProtocol& config_protocol) {
|
||||||
|
CircuitModelId sram_model = config_protocol.memory_model();
|
||||||
|
CircuitModelId bl_memory_model = config_protocol.bl_memory_model();
|
||||||
|
/* Find out the unique shift register chain sizes */
|
||||||
|
vtr::vector<ConfigRegionId, size_t> unique_sr_sizes;
|
||||||
|
unique_sr_sizes.resize(module_manager.regions(top_module).size());
|
||||||
|
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||||
|
/* TODO: Need to find how to cut the BLs when there are multiple banks for shift registers in a region */
|
||||||
|
size_t num_bls = compute_memory_bank_regional_num_bls(module_manager, top_module,
|
||||||
|
config_region,
|
||||||
|
circuit_lib, sram_model);
|
||||||
|
unique_sr_sizes[config_region] = num_bls;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build submodules for shift register chains */
|
||||||
|
for (const size_t& sr_size : unique_sr_sizes) {
|
||||||
|
std::string sr_module_name = generate_bl_shift_register_module_name(circuit_lib.model_name(bl_memory_model), sr_size);
|
||||||
|
build_bl_shift_register_chain_module(module_manager,
|
||||||
|
circuit_lib,
|
||||||
|
sr_module_name,
|
||||||
|
bl_memory_model,
|
||||||
|
sr_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Instanciate the shift register chains in the top-level module */
|
||||||
|
sr_banks.resize_regions(module_manager.regions(top_module).size());
|
||||||
|
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||||
|
std::string sr_module_name = generate_bl_shift_register_module_name(circuit_lib.model_name(bl_memory_model), unique_sr_sizes[config_region]);
|
||||||
|
ModuleId sr_bank_module = module_manager.find_module(sr_module_name);
|
||||||
|
VTR_ASSERT(sr_bank_module);
|
||||||
|
|
||||||
|
size_t cur_inst = module_manager.num_instance(top_module, sr_bank_module);
|
||||||
|
module_manager.add_child_module(top_module, sr_bank_module);
|
||||||
|
|
||||||
|
sr_banks.add_shift_register_instance(config_region, sr_bank_module, cur_inst);
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
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];
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
|
||||||
|
sr_banks.add_shift_register_sink_nodes(config_region, sr_bank_module, cur_inst, child_id, sink_bl_pin);
|
||||||
|
sr_banks.add_shift_register_source_blwls(config_region, sr_bank_module, cur_inst, bl_pin_id);
|
||||||
|
|
||||||
|
cur_bl_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create connections between top-level module and the BL shift register banks
|
||||||
|
* - Connect the head port from top-level module to each shift register bank
|
||||||
|
* - Connect the tail port from each shift register bank to top-level module
|
||||||
|
*/
|
||||||
|
add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_heads(module_manager, top_module, sr_banks,
|
||||||
|
std::string(BL_SHIFT_REGISTER_CHAIN_HEAD_NAME));
|
||||||
|
|
||||||
|
add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_tails(module_manager, top_module, sr_banks,
|
||||||
|
std::string(BL_SHIFT_REGISTER_CHAIN_TAIL_NAME));
|
||||||
|
|
||||||
|
/* Create connections between BLs of top-level module and BLs of child modules for each region */
|
||||||
|
add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_blwls(module_manager, top_module, sr_banks,
|
||||||
|
std::string(BL_SHIFT_REGISTER_CHAIN_BL_OUT_NAME),
|
||||||
|
std::string(MEMORY_BL_PORT_NAME));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* Top-level function to add nets for quicklogic memory banks using shift registers to control BL/WLs
|
||||||
|
*
|
||||||
|
* @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_shift_register_config_bus()
|
||||||
|
**********************************************************************/
|
||||||
|
static
|
||||||
|
void add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(ModuleManager& module_manager,
|
||||||
|
MemoryBankShiftRegisterBanks& sr_banks,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const ConfigProtocol& config_protocol) {
|
||||||
|
CircuitModelId sram_model = config_protocol.memory_model();
|
||||||
|
CircuitModelId wl_memory_model = config_protocol.wl_memory_model();
|
||||||
|
/* Find out the unique shift register chain sizes */
|
||||||
|
vtr::vector<ConfigRegionId, size_t> unique_sr_sizes;
|
||||||
|
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||||
|
/* TODO: Need to find how to cut the BLs when there are multiple banks for shift registers in a region */
|
||||||
|
size_t num_wls = compute_memory_bank_regional_num_wls(module_manager, top_module,
|
||||||
|
config_region,
|
||||||
|
circuit_lib, sram_model);
|
||||||
|
unique_sr_sizes.push_back(num_wls);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Build submodules for shift register chains */
|
||||||
|
for (const size_t& sr_size : unique_sr_sizes) {
|
||||||
|
std::string sr_module_name = generate_wl_shift_register_module_name(circuit_lib.model_name(wl_memory_model), sr_size);
|
||||||
|
build_wl_shift_register_chain_module(module_manager,
|
||||||
|
circuit_lib,
|
||||||
|
sr_module_name,
|
||||||
|
wl_memory_model,
|
||||||
|
sr_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Instanciate the shift register chains in the top-level module */
|
||||||
|
sr_banks.resize_regions(module_manager.regions(top_module).size());
|
||||||
|
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||||
|
std::string sr_module_name = generate_wl_shift_register_module_name(circuit_lib.model_name(wl_memory_model), unique_sr_sizes[config_region]);
|
||||||
|
ModuleId sr_bank_module = module_manager.find_module(sr_module_name);
|
||||||
|
VTR_ASSERT(sr_bank_module);
|
||||||
|
|
||||||
|
size_t cur_inst = module_manager.num_instance(top_module, sr_bank_module);
|
||||||
|
module_manager.add_child_module(top_module, sr_bank_module);
|
||||||
|
|
||||||
|
sr_banks.add_shift_register_instance(config_region, sr_bank_module, cur_inst);
|
||||||
|
|
||||||
|
/**************************************************************
|
||||||
|
* 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);
|
||||||
|
|
||||||
|
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 cur_wl_index = 0;
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
|
||||||
|
for (const size_t& sink_wl_pin : child_wl_port_info.pins()) {
|
||||||
|
size_t wl_pin_id = wl_start_index_per_tile[coord.y()] + cur_wl_index;
|
||||||
|
sr_banks.add_shift_register_sink_nodes(config_region, sr_bank_module, cur_inst, child_id, sink_wl_pin);
|
||||||
|
sr_banks.add_shift_register_source_blwls(config_region, sr_bank_module, cur_inst, wl_pin_id);
|
||||||
|
|
||||||
|
cur_wl_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create connections between top-level module and the BL shift register banks
|
||||||
|
* - Connect the head port from top-level module to each shift register bank
|
||||||
|
* - Connect the tail port from each shift register bank to top-level module
|
||||||
|
*/
|
||||||
|
add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_heads(module_manager, top_module, sr_banks,
|
||||||
|
std::string(WL_SHIFT_REGISTER_CHAIN_HEAD_NAME));
|
||||||
|
|
||||||
|
add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_tails(module_manager, top_module, sr_banks,
|
||||||
|
std::string(WL_SHIFT_REGISTER_CHAIN_TAIL_NAME));
|
||||||
|
|
||||||
|
/* Create connections between BLs of top-level module and BLs of child modules for each region */
|
||||||
|
add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_blwls(module_manager, top_module, sr_banks,
|
||||||
|
std::string(WL_SHIFT_REGISTER_CHAIN_WL_OUT_NAME),
|
||||||
|
std::string(MEMORY_WL_PORT_NAME));
|
||||||
|
add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_blwls(module_manager, top_module, sr_banks,
|
||||||
|
std::string(WL_SHIFT_REGISTER_CHAIN_WLR_OUT_NAME),
|
||||||
|
std::string(MEMORY_WLR_PORT_NAME),
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
/*********************************************************************
|
/*********************************************************************
|
||||||
* Top-level function to add nets for quicklogic memory banks
|
* Top-level function to add nets for quicklogic memory banks
|
||||||
* - Each configuration region has independent memory bank circuitry
|
* - Each configuration region has independent memory bank circuitry
|
||||||
|
@ -761,6 +1470,7 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_flatten_config_bus(ModuleManager
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_manager,
|
void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_manager,
|
||||||
DecoderLibrary& decoder_lib,
|
DecoderLibrary& decoder_lib,
|
||||||
|
std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
|
||||||
const ModuleId& top_module,
|
const ModuleId& top_module,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
const ConfigProtocol& config_protocol,
|
const ConfigProtocol& config_protocol,
|
||||||
|
@ -778,7 +1488,7 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BLWL_PROTOCOL_SHIFT_REGISTER: {
|
case BLWL_PROTOCOL_SHIFT_REGISTER: {
|
||||||
/* TODO */
|
add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(module_manager, blwl_sr_banks[0], top_module, circuit_lib, config_protocol);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
@ -797,7 +1507,7 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BLWL_PROTOCOL_SHIFT_REGISTER: {
|
case BLWL_PROTOCOL_SHIFT_REGISTER: {
|
||||||
/* TODO */
|
add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(module_manager, blwl_sr_banks[1], top_module, circuit_lib, config_protocol);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
@ -872,7 +1582,14 @@ void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BLWL_PROTOCOL_SHIFT_REGISTER: {
|
case BLWL_PROTOCOL_SHIFT_REGISTER: {
|
||||||
/* TODO */
|
/* Each region will have independent shift register banks */
|
||||||
|
for (const ConfigRegionId& config_region : module_manager.regions(module_id)) {
|
||||||
|
size_t num_heads = config_protocol.bl_num_banks();
|
||||||
|
BasicPort blsr_head_port(generate_regional_blwl_port_name(std::string(BL_SHIFT_REGISTER_CHAIN_HEAD_NAME), config_region), num_heads);
|
||||||
|
module_manager.add_port(module_id, blsr_head_port, ModuleManager::MODULE_INPUT_PORT);
|
||||||
|
BasicPort blsr_tail_port(generate_regional_blwl_port_name(std::string(BL_SHIFT_REGISTER_CHAIN_TAIL_NAME), config_region), num_heads);
|
||||||
|
module_manager.add_port(module_id, blsr_tail_port, ModuleManager::MODULE_OUTPUT_PORT);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
@ -914,7 +1631,14 @@ void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BLWL_PROTOCOL_SHIFT_REGISTER: {
|
case BLWL_PROTOCOL_SHIFT_REGISTER: {
|
||||||
/* TODO */
|
/* Each region will have independent shift register banks */
|
||||||
|
for (const ConfigRegionId& config_region : module_manager.regions(module_id)) {
|
||||||
|
size_t num_heads = config_protocol.wl_num_banks();
|
||||||
|
BasicPort wlsr_head_port(generate_regional_blwl_port_name(std::string(WL_SHIFT_REGISTER_CHAIN_HEAD_NAME), config_region), num_heads);
|
||||||
|
module_manager.add_port(module_id, wlsr_head_port, ModuleManager::MODULE_INPUT_PORT);
|
||||||
|
BasicPort wlsr_tail_port(generate_regional_blwl_port_name(std::string(WL_SHIFT_REGISTER_CHAIN_TAIL_NAME), config_region), num_heads);
|
||||||
|
module_manager.add_port(module_id, wlsr_tail_port, ModuleManager::MODULE_OUTPUT_PORT);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
|
|
|
@ -7,12 +7,14 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <array>
|
||||||
#include "vtr_vector.h"
|
#include "vtr_vector.h"
|
||||||
#include "vtr_ndmatrix.h"
|
#include "vtr_ndmatrix.h"
|
||||||
#include "module_manager.h"
|
#include "module_manager.h"
|
||||||
#include "config_protocol.h"
|
#include "config_protocol.h"
|
||||||
#include "circuit_library.h"
|
#include "circuit_library.h"
|
||||||
#include "decoder_library.h"
|
#include "decoder_library.h"
|
||||||
|
#include "memory_bank_shift_register_banks.h"
|
||||||
#include "build_top_module_memory_utils.h"
|
#include "build_top_module_memory_utils.h"
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
|
@ -24,6 +26,7 @@ namespace openfpga {
|
||||||
|
|
||||||
void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_manager,
|
void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_manager,
|
||||||
DecoderLibrary& decoder_lib,
|
DecoderLibrary& decoder_lib,
|
||||||
|
std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
|
||||||
const ModuleId& top_module,
|
const ModuleId& top_module,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
const ConfigProtocol& config_protocol,
|
const ConfigProtocol& config_protocol,
|
||||||
|
|
|
@ -50,6 +50,21 @@ bool FabricGlobalPortInfo::global_port_is_prog(const FabricGlobalPortId& global_
|
||||||
return global_port_is_prog_[global_port_id];
|
return global_port_is_prog_[global_port_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FabricGlobalPortInfo::global_port_is_shift_register(const FabricGlobalPortId& global_port_id) const {
|
||||||
|
VTR_ASSERT(valid_global_port_id(global_port_id));
|
||||||
|
return global_port_is_shift_register_[global_port_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FabricGlobalPortInfo::global_port_is_bl(const FabricGlobalPortId& global_port_id) const {
|
||||||
|
VTR_ASSERT(valid_global_port_id(global_port_id));
|
||||||
|
return global_port_is_bl_[global_port_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FabricGlobalPortInfo::global_port_is_wl(const FabricGlobalPortId& global_port_id) const {
|
||||||
|
VTR_ASSERT(valid_global_port_id(global_port_id));
|
||||||
|
return global_port_is_wl_[global_port_id];
|
||||||
|
}
|
||||||
|
|
||||||
bool FabricGlobalPortInfo::global_port_is_config_enable(const FabricGlobalPortId& global_port_id) const {
|
bool FabricGlobalPortInfo::global_port_is_config_enable(const FabricGlobalPortId& global_port_id) const {
|
||||||
VTR_ASSERT(valid_global_port_id(global_port_id));
|
VTR_ASSERT(valid_global_port_id(global_port_id));
|
||||||
return global_port_is_config_enable_[global_port_id];
|
return global_port_is_config_enable_[global_port_id];
|
||||||
|
@ -77,6 +92,9 @@ FabricGlobalPortId FabricGlobalPortInfo::create_global_port(const ModulePortId&
|
||||||
global_port_is_set_.push_back(false);
|
global_port_is_set_.push_back(false);
|
||||||
global_port_is_reset_.push_back(false);
|
global_port_is_reset_.push_back(false);
|
||||||
global_port_is_prog_.push_back(false);
|
global_port_is_prog_.push_back(false);
|
||||||
|
global_port_is_shift_register_.push_back(false);
|
||||||
|
global_port_is_bl_.push_back(false);
|
||||||
|
global_port_is_wl_.push_back(false);
|
||||||
global_port_is_io_.push_back(false);
|
global_port_is_io_.push_back(false);
|
||||||
global_port_is_config_enable_.push_back(false);
|
global_port_is_config_enable_.push_back(false);
|
||||||
global_port_default_values_.push_back(0);
|
global_port_default_values_.push_back(0);
|
||||||
|
@ -108,6 +126,24 @@ void FabricGlobalPortInfo::set_global_port_is_prog(const FabricGlobalPortId& glo
|
||||||
global_port_is_prog_[global_port_id] = is_prog;
|
global_port_is_prog_[global_port_id] = is_prog;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FabricGlobalPortInfo::set_global_port_is_shift_register(const FabricGlobalPortId& global_port_id,
|
||||||
|
const bool& is_shift_register) {
|
||||||
|
VTR_ASSERT(valid_global_port_id(global_port_id));
|
||||||
|
global_port_is_shift_register_[global_port_id] = is_shift_register;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FabricGlobalPortInfo::set_global_port_is_bl(const FabricGlobalPortId& global_port_id,
|
||||||
|
const bool& is_bl) {
|
||||||
|
VTR_ASSERT(valid_global_port_id(global_port_id));
|
||||||
|
global_port_is_bl_[global_port_id] = is_bl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FabricGlobalPortInfo::set_global_port_is_wl(const FabricGlobalPortId& global_port_id,
|
||||||
|
const bool& is_wl) {
|
||||||
|
VTR_ASSERT(valid_global_port_id(global_port_id));
|
||||||
|
global_port_is_wl_[global_port_id] = is_wl;
|
||||||
|
}
|
||||||
|
|
||||||
void FabricGlobalPortInfo::set_global_port_is_config_enable(const FabricGlobalPortId& global_port_id,
|
void FabricGlobalPortInfo::set_global_port_is_config_enable(const FabricGlobalPortId& global_port_id,
|
||||||
const bool& is_config_enable) {
|
const bool& is_config_enable) {
|
||||||
VTR_ASSERT(valid_global_port_id(global_port_id));
|
VTR_ASSERT(valid_global_port_id(global_port_id));
|
||||||
|
|
|
@ -36,6 +36,9 @@ class FabricGlobalPortInfo {
|
||||||
bool global_port_is_set(const FabricGlobalPortId& global_port_id) const;
|
bool global_port_is_set(const FabricGlobalPortId& global_port_id) const;
|
||||||
bool global_port_is_reset(const FabricGlobalPortId& global_port_id) const;
|
bool global_port_is_reset(const FabricGlobalPortId& global_port_id) const;
|
||||||
bool global_port_is_prog(const FabricGlobalPortId& global_port_id) const;
|
bool global_port_is_prog(const FabricGlobalPortId& global_port_id) const;
|
||||||
|
bool global_port_is_bl(const FabricGlobalPortId& global_port_id) const;
|
||||||
|
bool global_port_is_wl(const FabricGlobalPortId& global_port_id) const;
|
||||||
|
bool global_port_is_shift_register(const FabricGlobalPortId& global_port_id) const;
|
||||||
bool global_port_is_config_enable(const FabricGlobalPortId& global_port_id) const;
|
bool global_port_is_config_enable(const FabricGlobalPortId& global_port_id) const;
|
||||||
bool global_port_is_io(const FabricGlobalPortId& global_port_id) const;
|
bool global_port_is_io(const FabricGlobalPortId& global_port_id) const;
|
||||||
size_t global_port_default_value(const FabricGlobalPortId& global_port_id) const;
|
size_t global_port_default_value(const FabricGlobalPortId& global_port_id) const;
|
||||||
|
@ -52,6 +55,12 @@ class FabricGlobalPortInfo {
|
||||||
const bool& is_reset);
|
const bool& is_reset);
|
||||||
void set_global_port_is_prog(const FabricGlobalPortId& global_port_id,
|
void set_global_port_is_prog(const FabricGlobalPortId& global_port_id,
|
||||||
const bool& is_prog);
|
const bool& is_prog);
|
||||||
|
void set_global_port_is_shift_register(const FabricGlobalPortId& global_port_id,
|
||||||
|
const bool& is_shift_register);
|
||||||
|
void set_global_port_is_bl(const FabricGlobalPortId& global_port_id,
|
||||||
|
const bool& is_bl);
|
||||||
|
void set_global_port_is_wl(const FabricGlobalPortId& global_port_id,
|
||||||
|
const bool& is_wl);
|
||||||
void set_global_port_is_config_enable(const FabricGlobalPortId& global_port_id,
|
void set_global_port_is_config_enable(const FabricGlobalPortId& global_port_id,
|
||||||
const bool& is_config_enable);
|
const bool& is_config_enable);
|
||||||
void set_global_port_is_io(const FabricGlobalPortId& global_port_id,
|
void set_global_port_is_io(const FabricGlobalPortId& global_port_id,
|
||||||
|
@ -68,6 +77,9 @@ class FabricGlobalPortInfo {
|
||||||
vtr::vector<FabricGlobalPortId, bool> global_port_is_reset_;
|
vtr::vector<FabricGlobalPortId, bool> global_port_is_reset_;
|
||||||
vtr::vector<FabricGlobalPortId, bool> global_port_is_set_;
|
vtr::vector<FabricGlobalPortId, bool> global_port_is_set_;
|
||||||
vtr::vector<FabricGlobalPortId, bool> global_port_is_prog_;
|
vtr::vector<FabricGlobalPortId, bool> global_port_is_prog_;
|
||||||
|
vtr::vector<FabricGlobalPortId, bool> global_port_is_shift_register_;
|
||||||
|
vtr::vector<FabricGlobalPortId, bool> global_port_is_bl_;
|
||||||
|
vtr::vector<FabricGlobalPortId, bool> global_port_is_wl_;
|
||||||
vtr::vector<FabricGlobalPortId, bool> global_port_is_config_enable_;
|
vtr::vector<FabricGlobalPortId, bool> global_port_is_config_enable_;
|
||||||
vtr::vector<FabricGlobalPortId, bool> global_port_is_io_;
|
vtr::vector<FabricGlobalPortId, bool> global_port_is_io_;
|
||||||
vtr::vector<FabricGlobalPortId, size_t> global_port_default_values_;
|
vtr::vector<FabricGlobalPortId, size_t> global_port_default_values_;
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
#include <algorithm>
|
||||||
|
#include "vtr_assert.h"
|
||||||
|
#include "memory_bank_shift_register_banks.h"
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
std::vector<ModuleId> MemoryBankShiftRegisterBanks::shift_register_bank_unique_modules() const {
|
||||||
|
std::vector<ModuleId> sr_bank_modules;
|
||||||
|
for (const auto& region : sr_instance_sink_child_ids_) {
|
||||||
|
for (const auto& pair : region) {
|
||||||
|
if (sr_bank_modules.end() == std::find(sr_bank_modules.begin(), sr_bank_modules.end(), pair.first.first)) {
|
||||||
|
sr_bank_modules.push_back(pair.first.first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sr_bank_modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<ModuleId> MemoryBankShiftRegisterBanks::shift_register_bank_modules(const ConfigRegionId& region) const {
|
||||||
|
std::vector<ModuleId> sr_bank_modules;
|
||||||
|
VTR_ASSERT(valid_region_id(region));
|
||||||
|
for (const auto& pair : sr_instance_sink_child_ids_[region]) {
|
||||||
|
sr_bank_modules.push_back(pair.first.first);
|
||||||
|
}
|
||||||
|
return sr_bank_modules;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<size_t> MemoryBankShiftRegisterBanks::shift_register_bank_instances(const ConfigRegionId& region) const {
|
||||||
|
std::vector<size_t> sr_bank_instances;
|
||||||
|
VTR_ASSERT(valid_region_id(region));
|
||||||
|
for (const auto& pair : sr_instance_sink_child_ids_[region]) {
|
||||||
|
sr_bank_instances.push_back(pair.first.second);
|
||||||
|
}
|
||||||
|
return sr_bank_instances;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<size_t> MemoryBankShiftRegisterBanks::shift_register_bank_sink_child_ids(const ConfigRegionId& region,
|
||||||
|
const ModuleId& sr_module,
|
||||||
|
const size_t& sr_instance) const {
|
||||||
|
VTR_ASSERT(valid_region_id(region));
|
||||||
|
|
||||||
|
auto result = sr_instance_sink_child_ids_[region].find(std::make_pair(sr_module, sr_instance));
|
||||||
|
/* Return an empty vector if not found */
|
||||||
|
if (result != sr_instance_sink_child_ids_[region].end()) {
|
||||||
|
return result->second;
|
||||||
|
}
|
||||||
|
return std::vector<size_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<size_t> MemoryBankShiftRegisterBanks::shift_register_bank_sink_pin_ids(const ConfigRegionId& region,
|
||||||
|
const ModuleId& sr_module,
|
||||||
|
const size_t& sr_instance) const {
|
||||||
|
VTR_ASSERT(valid_region_id(region));
|
||||||
|
|
||||||
|
auto result = sr_instance_sink_child_pin_ids_[region].find(std::make_pair(sr_module, sr_instance));
|
||||||
|
/* Return an empty vector if not found */
|
||||||
|
if (result != sr_instance_sink_child_pin_ids_[region].end()) {
|
||||||
|
return result->second;
|
||||||
|
}
|
||||||
|
return std::vector<size_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<size_t> MemoryBankShiftRegisterBanks::shift_register_bank_source_blwl_ids(const ConfigRegionId& region,
|
||||||
|
const ModuleId& sr_module,
|
||||||
|
const size_t& sr_instance) const {
|
||||||
|
VTR_ASSERT(valid_region_id(region));
|
||||||
|
|
||||||
|
auto result = sr_instance_source_blwl_ids_[region].find(std::make_pair(sr_module, sr_instance));
|
||||||
|
/* Return an empty vector if not found */
|
||||||
|
if (result != sr_instance_source_blwl_ids_[region].end()) {
|
||||||
|
return result->second;
|
||||||
|
}
|
||||||
|
return std::vector<size_t>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBankShiftRegisterBanks::resize_regions(const size_t& num_regions) {
|
||||||
|
sr_instance_sink_child_ids_.resize(num_regions);
|
||||||
|
sr_instance_sink_child_pin_ids_.resize(num_regions);
|
||||||
|
sr_instance_source_blwl_ids_.resize(num_regions);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBankShiftRegisterBanks::add_shift_register_instance(const ConfigRegionId& region,
|
||||||
|
const ModuleId& sr_module,
|
||||||
|
const size_t& sr_instance) {
|
||||||
|
VTR_ASSERT(valid_region_id(region));
|
||||||
|
sr_instance_sink_child_ids_[region][std::make_pair(sr_module, sr_instance)];
|
||||||
|
sr_instance_sink_child_pin_ids_[region][std::make_pair(sr_module, sr_instance)];
|
||||||
|
sr_instance_source_blwl_ids_[region][std::make_pair(sr_module, sr_instance)];
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBankShiftRegisterBanks::add_shift_register_sink_nodes(const ConfigRegionId& region,
|
||||||
|
const ModuleId& sr_module,
|
||||||
|
const size_t& sr_instance,
|
||||||
|
const size_t& sink_child_id,
|
||||||
|
const size_t& sink_child_pin_id) {
|
||||||
|
VTR_ASSERT(valid_region_id(region));
|
||||||
|
sr_instance_sink_child_ids_[region][std::make_pair(sr_module, sr_instance)].push_back(sink_child_id);
|
||||||
|
sr_instance_sink_child_pin_ids_[region][std::make_pair(sr_module, sr_instance)].push_back(sink_child_pin_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBankShiftRegisterBanks::add_shift_register_source_blwls(const ConfigRegionId& region,
|
||||||
|
const ModuleId& sr_module,
|
||||||
|
const size_t& sr_instance,
|
||||||
|
const size_t& sink_blwl_id) {
|
||||||
|
VTR_ASSERT(valid_region_id(region));
|
||||||
|
sr_instance_source_blwl_ids_[region][std::make_pair(sr_module, sr_instance)].push_back(sink_blwl_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemoryBankShiftRegisterBanks::valid_region_id(const ConfigRegionId& region) const {
|
||||||
|
return size_t(region) < sr_instance_sink_child_ids_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
|
@ -0,0 +1,87 @@
|
||||||
|
#ifndef MEMORY_BANK_SHIFT_REGISTER_BANKS_H
|
||||||
|
#define MEMORY_BANK_SHIFT_REGISTER_BANKS_H
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include "vtr_vector.h"
|
||||||
|
#include "module_manager.h"
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* This files includes data structures that stores detailed information about
|
||||||
|
* shift register banks for each configuration region in the top-level module, including
|
||||||
|
* - Module id of each shift register bank
|
||||||
|
* - Instance id of each shift register bank
|
||||||
|
* - The connectivity of of each shift register bank to reconfigurable child under a configuration region
|
||||||
|
* - The ids of each child to be connected
|
||||||
|
* - The Bit Line (BL) or Word Line (WL) pin id of each child
|
||||||
|
|
||||||
|
* @note This data structure is mainly used as a database for adding connections around shift register banks in top-level module
|
||||||
|
******************************************************************************/
|
||||||
|
class MemoryBankShiftRegisterBanks {
|
||||||
|
public: /* Accessors */
|
||||||
|
/* @brief Return a list of modules of unique shift register banks across all the regions */
|
||||||
|
std::vector<ModuleId> shift_register_bank_unique_modules() const;
|
||||||
|
|
||||||
|
/* @brief Return a list of modules of shift register banks under a specific configuration region of top-level module */
|
||||||
|
std::vector<ModuleId> shift_register_bank_modules(const ConfigRegionId& region) const;
|
||||||
|
|
||||||
|
/* @brief Return a list of instances of shift register banks under a specific configuration region of top-level module */
|
||||||
|
std::vector<size_t> shift_register_bank_instances(const ConfigRegionId& region) const;
|
||||||
|
|
||||||
|
/* @brief Return a list of ids of reconfigurable children for a given instance of shift register bank
|
||||||
|
* under a specific configuration region of top-level module
|
||||||
|
*/
|
||||||
|
std::vector<size_t> shift_register_bank_sink_child_ids(const ConfigRegionId& region,
|
||||||
|
const ModuleId& sr_module,
|
||||||
|
const size_t& sr_instance) const;
|
||||||
|
|
||||||
|
/* @brief Return a list of BL/WL ids of reconfigurable children for a given instance of shift register bank
|
||||||
|
* under a specific configuration region of top-level module
|
||||||
|
*/
|
||||||
|
std::vector<size_t> shift_register_bank_sink_pin_ids(const ConfigRegionId& region,
|
||||||
|
const ModuleId& sr_module,
|
||||||
|
const size_t& sr_instance) const;
|
||||||
|
|
||||||
|
/* @brief Return a list of BL/WL ids of a given instance of shift register bank
|
||||||
|
* under a specific configuration region of top-level module
|
||||||
|
*/
|
||||||
|
std::vector<size_t> shift_register_bank_source_blwl_ids(const ConfigRegionId& region,
|
||||||
|
const ModuleId& sr_module,
|
||||||
|
const size_t& sr_instance) const;
|
||||||
|
|
||||||
|
public: /* Mutators */
|
||||||
|
void resize_regions(const size_t& num_regions);
|
||||||
|
|
||||||
|
/* @brief Add the module id and instance id of a shift register under a specific configuration region of top-level module */
|
||||||
|
void add_shift_register_instance(const ConfigRegionId& region,
|
||||||
|
const ModuleId& sr_module,
|
||||||
|
const size_t& sr_instance);
|
||||||
|
|
||||||
|
/* @brief Add the child id and pin id of BL/WL to which a shift register is connected to under a specific configuration region of top-level module */
|
||||||
|
void add_shift_register_sink_nodes(const ConfigRegionId& region,
|
||||||
|
const ModuleId& sr_module,
|
||||||
|
const size_t& sr_instance,
|
||||||
|
const size_t& sink_child_id,
|
||||||
|
const size_t& sink_child_pin_id);
|
||||||
|
|
||||||
|
/* @brief Add the BL/WL id under a specific configuration region of top-level module to which a shift register is connected to */
|
||||||
|
void add_shift_register_source_blwls(const ConfigRegionId& region,
|
||||||
|
const ModuleId& sr_module,
|
||||||
|
const size_t& sr_instance,
|
||||||
|
const size_t& sink_blwl_id);
|
||||||
|
public: /* Validators */
|
||||||
|
bool valid_region_id(const ConfigRegionId& region) const;
|
||||||
|
|
||||||
|
private: /* Internal data */
|
||||||
|
/* [config_region][(shift_register_module, shift_register_instance)][i] = (reconfigurable_child_id, blwl_port_pin_index)*/
|
||||||
|
vtr::vector<ConfigRegionId, std::map<std::pair<ModuleId, size_t>, std::vector<size_t>>> sr_instance_sink_child_ids_;
|
||||||
|
vtr::vector<ConfigRegionId, std::map<std::pair<ModuleId, size_t>, std::vector<size_t>>> sr_instance_sink_child_pin_ids_;
|
||||||
|
vtr::vector<ConfigRegionId, std::map<std::pair<ModuleId, size_t>, std::vector<size_t>>> sr_instance_source_blwl_ids_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
||||||
|
|
||||||
|
#endif
|
|
@ -249,8 +249,12 @@ void build_module_fabric_dependent_bitstream_ql_memory_bank(const ConfigProtocol
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* TODO */
|
|
||||||
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type());
|
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type());
|
||||||
|
bl_addr_port_info.set_width(1); /* Deposit minimum width */
|
||||||
|
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||||
|
size_t num_bls = compute_memory_bank_regional_num_bls(module_manager, top_module, config_region, circuit_lib, config_protocol.memory_model());
|
||||||
|
bl_addr_port_info.set_width(std::max(num_bls, bl_addr_port_info.get_width()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* For different WL control protocol, the address ports are different
|
/* For different WL control protocol, the address ports are different
|
||||||
|
@ -275,8 +279,12 @@ void build_module_fabric_dependent_bitstream_ql_memory_bank(const ConfigProtocol
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* TODO */
|
|
||||||
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type());
|
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type());
|
||||||
|
wl_addr_port_info.set_width(1); /* Deposit minimum width */
|
||||||
|
for (const ConfigRegionId& config_region : module_manager.regions(top_module)) {
|
||||||
|
size_t num_wls = compute_memory_bank_regional_num_wls(module_manager, top_module, config_region, circuit_lib, config_protocol.memory_model());
|
||||||
|
wl_addr_port_info.set_width(std::max(num_wls, wl_addr_port_info.get_width()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reserve bits before build-up */
|
/* Reserve bits before build-up */
|
||||||
|
@ -297,26 +305,30 @@ void build_module_fabric_dependent_bitstream_ql_memory_bank(const ConfigProtocol
|
||||||
|
|
||||||
/* Find the BL/WL port (different region may have different sizes of BL/WLs) */
|
/* Find the BL/WL port (different region may have different sizes of BL/WLs) */
|
||||||
ModulePortId cur_bl_addr_port;
|
ModulePortId cur_bl_addr_port;
|
||||||
|
BasicPort cur_bl_addr_port_info;
|
||||||
if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) {
|
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));
|
cur_bl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_BL_ADDRESS_PORT_NAME));
|
||||||
|
cur_bl_addr_port_info = module_manager.module_port(top_module, cur_bl_addr_port);
|
||||||
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) {
|
} 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));
|
cur_bl_addr_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_BL_PORT_NAME), config_region));
|
||||||
|
cur_bl_addr_port_info = module_manager.module_port(top_module, cur_bl_addr_port);
|
||||||
} else {
|
} else {
|
||||||
/* TODO */
|
|
||||||
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type());
|
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type());
|
||||||
|
cur_bl_addr_port_info.set_width(compute_memory_bank_regional_num_bls(module_manager, top_module, config_region, circuit_lib, config_protocol.memory_model()));
|
||||||
}
|
}
|
||||||
BasicPort cur_bl_addr_port_info = module_manager.module_port(top_module, cur_bl_addr_port);
|
|
||||||
|
|
||||||
ModulePortId cur_wl_addr_port;
|
ModulePortId cur_wl_addr_port;
|
||||||
|
BasicPort cur_wl_addr_port_info;
|
||||||
if (BLWL_PROTOCOL_DECODER == config_protocol.wl_protocol_type()) {
|
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));
|
cur_wl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_WL_ADDRESS_PORT_NAME));
|
||||||
|
cur_wl_addr_port_info = module_manager.module_port(top_module, cur_wl_addr_port);
|
||||||
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()) {
|
} 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));
|
cur_wl_addr_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_WL_PORT_NAME), config_region));
|
||||||
|
cur_wl_addr_port_info = module_manager.module_port(top_module, cur_wl_addr_port);
|
||||||
} else {
|
} else {
|
||||||
/* TODO */
|
|
||||||
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type());
|
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type());
|
||||||
|
cur_wl_addr_port_info.set_width(compute_memory_bank_regional_num_wls(module_manager, top_module, config_region, circuit_lib, config_protocol.memory_model()));
|
||||||
}
|
}
|
||||||
BasicPort cur_wl_addr_port_info = module_manager.module_port(top_module, cur_wl_addr_port);
|
|
||||||
|
|
||||||
/**************************************************************
|
/**************************************************************
|
||||||
* Precompute the BLs and WLs distribution across the FPGA fabric
|
* Precompute the BLs and WLs distribution across the FPGA fabric
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
#include "memory_bank_flatten_fabric_bitstream.h"
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
size_t MemoryBankFlattenFabricBitstream::size() const {
|
||||||
|
return bitstream_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MemoryBankFlattenFabricBitstream::bl_vector_size() const {
|
||||||
|
/* 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_vec_size = 0;
|
||||||
|
for (const auto& bl_vec : bitstream_.begin()->second) {
|
||||||
|
bl_vec_size += bl_vec.size();
|
||||||
|
}
|
||||||
|
return bl_vec_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MemoryBankFlattenFabricBitstream::wl_vector_size() const {
|
||||||
|
/* 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 wl_vec_size = 0;
|
||||||
|
for (const auto& wl_vec : bitstream_.begin()->first) {
|
||||||
|
wl_vec_size += wl_vec.size();
|
||||||
|
}
|
||||||
|
return wl_vec_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> MemoryBankFlattenFabricBitstream::bl_vector(const std::vector<std::string>& wl_vec) const {
|
||||||
|
return bitstream_.at(wl_vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::vector<std::string>> MemoryBankFlattenFabricBitstream::wl_vectors() const {
|
||||||
|
std::vector<std::vector<std::string>> wl_vecs;
|
||||||
|
for (const auto& pair : bitstream_) {
|
||||||
|
wl_vecs.push_back(pair.first);
|
||||||
|
}
|
||||||
|
return wl_vecs;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBankFlattenFabricBitstream::add_blwl_vectors(const std::vector<std::string>& bl_vec,
|
||||||
|
const std::vector<std::string>& wl_vec) {
|
||||||
|
/* TODO: Add sanity check. Give a warning if the wl vector is already there */
|
||||||
|
bitstream_[wl_vec] = bl_vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
|
@ -0,0 +1,49 @@
|
||||||
|
#ifndef MEMORY_BANK_FLATTEN_FABRIC_BITSTREAM_H
|
||||||
|
#define MEMORY_BANK_FLATTEN_FABRIC_BITSTREAM_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include "vtr_vector.h"
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* This files includes data structures that stores a downloadable format of fabric bitstream
|
||||||
|
* which is compatible with memory bank configuration protocol using flatten BL/WL buses
|
||||||
|
* @note This data structure is mainly used to output bitstream file for compatible protocols
|
||||||
|
******************************************************************************/
|
||||||
|
class MemoryBankFlattenFabricBitstream {
|
||||||
|
public: /* Accessors */
|
||||||
|
/* @brief Return the length of bitstream */
|
||||||
|
size_t size() const;
|
||||||
|
|
||||||
|
/* @brief Return the BL address size */
|
||||||
|
size_t bl_vector_size() const;
|
||||||
|
|
||||||
|
/* @brief Return the WL address size */
|
||||||
|
size_t wl_vector_size() const;
|
||||||
|
|
||||||
|
/* @brief Return the BL vectors with a given WL key */
|
||||||
|
std::vector<std::string> bl_vector(const std::vector<std::string>& wl_vec) const;
|
||||||
|
|
||||||
|
/* @brief Return all the WL vectors in a downloaded sequence */
|
||||||
|
std::vector<std::vector<std::string>> wl_vectors() const;
|
||||||
|
|
||||||
|
public: /* Mutators */
|
||||||
|
/* @brief add a pair of BL/WL vectors to the bitstream database */
|
||||||
|
void add_blwl_vectors(const std::vector<std::string>& bl_vec,
|
||||||
|
const std::vector<std::string>& wl_vec);
|
||||||
|
public: /* Validators */
|
||||||
|
private: /* Internal data */
|
||||||
|
/* [(wl_bank0, wl_bank1, ...)] = [(bl_bank0, bl_bank1, ...)]
|
||||||
|
* Must use (WL, BL) as pairs in the map!!!
|
||||||
|
* This is because BL data may not be unique while WL must be unique
|
||||||
|
*/
|
||||||
|
std::map<std::vector<std::string>, std::vector<std::string>> bitstream_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,82 @@
|
||||||
|
#include "vtr_assert.h"
|
||||||
|
#include "memory_bank_shift_register_fabric_bitstream.h"
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
MemoryBankShiftRegisterFabricBitstream::word_range MemoryBankShiftRegisterFabricBitstream::words() const {
|
||||||
|
return vtr::make_range(bitstream_word_ids_.begin(), bitstream_word_ids_.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MemoryBankShiftRegisterFabricBitstream::num_words() const {
|
||||||
|
return bitstream_word_ids_.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MemoryBankShiftRegisterFabricBitstream::bl_word_size() const {
|
||||||
|
/* For a fast runtime, we just inspect the last element
|
||||||
|
* It is the validator which should ensure all the words have a uniform size
|
||||||
|
*/
|
||||||
|
return bitstream_word_bls_[bitstream_word_ids_.back()].size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MemoryBankShiftRegisterFabricBitstream::wl_word_size() const {
|
||||||
|
/* For a fast runtime, we just inspect the last element
|
||||||
|
* It is the validator which should ensure all the words have a uniform size
|
||||||
|
*/
|
||||||
|
return bitstream_word_wls_[bitstream_word_ids_.back()].size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MemoryBankShiftRegisterFabricBitstream::bl_width() const {
|
||||||
|
/* For a fast runtime, we just inspect the last element
|
||||||
|
* It is the validator which should ensure all the words have a uniform size
|
||||||
|
*/
|
||||||
|
return bitstream_word_bls_[bitstream_word_ids_.back()].back().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t MemoryBankShiftRegisterFabricBitstream::wl_width() const {
|
||||||
|
/* For a fast runtime, we just inspect the last element
|
||||||
|
* It is the validator which should ensure all the words have a uniform size
|
||||||
|
*/
|
||||||
|
return bitstream_word_wls_[bitstream_word_ids_.back()].back().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> MemoryBankShiftRegisterFabricBitstream::bl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const {
|
||||||
|
VTR_ASSERT(valid_word_id(word_id));
|
||||||
|
return bitstream_word_bls_[word_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> MemoryBankShiftRegisterFabricBitstream::wl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const {
|
||||||
|
VTR_ASSERT(valid_word_id(word_id));
|
||||||
|
return bitstream_word_wls_[word_id];
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBankShiftRegisterFabricBitstreamWordId MemoryBankShiftRegisterFabricBitstream::create_word() {
|
||||||
|
/* Create a new id*/
|
||||||
|
MemoryBankShiftRegisterFabricBitstreamWordId word_id = MemoryBankShiftRegisterFabricBitstreamWordId(bitstream_word_ids_.size());
|
||||||
|
/* Update the id list */
|
||||||
|
bitstream_word_ids_.push_back(word_id);
|
||||||
|
|
||||||
|
/* Initialize other attributes */
|
||||||
|
bitstream_word_bls_.emplace_back();
|
||||||
|
bitstream_word_wls_.emplace_back();
|
||||||
|
|
||||||
|
return word_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBankShiftRegisterFabricBitstream::add_bl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id,
|
||||||
|
const std::string& bl_vec) {
|
||||||
|
VTR_ASSERT(valid_word_id(word_id));
|
||||||
|
return bitstream_word_bls_[word_id].push_back(bl_vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryBankShiftRegisterFabricBitstream::add_wl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id,
|
||||||
|
const std::string& wl_vec) {
|
||||||
|
VTR_ASSERT(valid_word_id(word_id));
|
||||||
|
return bitstream_word_wls_[word_id].push_back(wl_vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MemoryBankShiftRegisterFabricBitstream::valid_word_id(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const {
|
||||||
|
return ( size_t(word_id) < bitstream_word_ids_.size() ) && ( word_id == bitstream_word_ids_[word_id] );
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
|
@ -0,0 +1,96 @@
|
||||||
|
#ifndef MEMORY_BANK_SHIFT_REGISTER_FABRIC_BITSTREAM_H
|
||||||
|
#define MEMORY_BANK_SHIFT_REGISTER_FABRIC_BITSTREAM_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include "vtr_vector.h"
|
||||||
|
#include "memory_bank_shift_register_fabric_bitstream_fwd.h"
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* This files includes data structures that stores a downloadable format of fabric bitstream
|
||||||
|
* which is compatible with memory bank configuration protocol using shift register to control BL/WLs
|
||||||
|
* @note This data structure is mainly used to output bitstream file for compatible protocols
|
||||||
|
******************************************************************************/
|
||||||
|
class MemoryBankShiftRegisterFabricBitstream {
|
||||||
|
public: /* Types */
|
||||||
|
typedef vtr::vector<MemoryBankShiftRegisterFabricBitstreamWordId, MemoryBankShiftRegisterFabricBitstreamWordId>::const_iterator word_iterator;
|
||||||
|
/* Create range */
|
||||||
|
typedef vtr::Range<word_iterator> word_range;
|
||||||
|
|
||||||
|
public: /* Accessors: aggregates */
|
||||||
|
word_range words() const;
|
||||||
|
|
||||||
|
public: /* Accessors */
|
||||||
|
/* @brief Return the length of bitstream */
|
||||||
|
size_t num_words() const;
|
||||||
|
|
||||||
|
/* @brief Return the length of BL part of each word. All the word should have a uniform size */
|
||||||
|
size_t bl_word_size() const;
|
||||||
|
|
||||||
|
/* @brief Return the length of WL part of each word. All the word should have a uniform size */
|
||||||
|
size_t wl_word_size() const;
|
||||||
|
|
||||||
|
/* @brief Return the width of each BL word, which is the number of heads through which a BL word can be loaded in parallel */
|
||||||
|
size_t bl_width() const;
|
||||||
|
|
||||||
|
/* @brief Return the width of each WL word, which is the number of heads through which a WL word can be loaded in parallel */
|
||||||
|
size_t wl_width() const;
|
||||||
|
|
||||||
|
/* @brief Return the BL vectors with a given word id*/
|
||||||
|
std::vector<std::string> bl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const;
|
||||||
|
|
||||||
|
/* @brief Return the WL vectors in a given word id */
|
||||||
|
std::vector<std::string> wl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const;
|
||||||
|
|
||||||
|
public: /* Mutators */
|
||||||
|
/* @brief Create a new word */
|
||||||
|
MemoryBankShiftRegisterFabricBitstreamWordId create_word();
|
||||||
|
|
||||||
|
/* @brief Add BLs to a given word */
|
||||||
|
void add_bl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id,
|
||||||
|
const std::string& bl_vec);
|
||||||
|
|
||||||
|
/* @brief Add WLs to a given word */
|
||||||
|
void add_wl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id,
|
||||||
|
const std::string& wl_vec);
|
||||||
|
|
||||||
|
public: /* Validators */
|
||||||
|
bool valid_word_id(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const;
|
||||||
|
|
||||||
|
private: /* Internal data */
|
||||||
|
/* Organization of the bitstream
|
||||||
|
*
|
||||||
|
* ============= Begin of Word 1 ==============
|
||||||
|
* |<--No of -->|<-- No of -->|
|
||||||
|
* | BL heads | WL heads |
|
||||||
|
* 010101 .. 101 101110 .. 001 ----
|
||||||
|
* ... ... ^
|
||||||
|
* |
|
||||||
|
* max. shift register length per word
|
||||||
|
* |
|
||||||
|
* v
|
||||||
|
* 110001 .. 111 100100 .. 110 ----
|
||||||
|
* ============= End of Word 1 ==============
|
||||||
|
* ============= Begin of Word 2 ==============
|
||||||
|
* 010101 .. 101 101110 .. 001 ----
|
||||||
|
* ... ... ^
|
||||||
|
* |
|
||||||
|
* max. shift register length per word
|
||||||
|
* |
|
||||||
|
* v
|
||||||
|
* 110001 .. 111 100100 .. 110 ----
|
||||||
|
* ============= End of Word 2 ==============
|
||||||
|
* .... more words
|
||||||
|
*/
|
||||||
|
vtr::vector<MemoryBankShiftRegisterFabricBitstreamWordId, MemoryBankShiftRegisterFabricBitstreamWordId> bitstream_word_ids_;
|
||||||
|
vtr::vector<MemoryBankShiftRegisterFabricBitstreamWordId, std::vector<std::string>> bitstream_word_bls_;
|
||||||
|
vtr::vector<MemoryBankShiftRegisterFabricBitstreamWordId, std::vector<std::string>> bitstream_word_wls_;
|
||||||
|
};
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,23 @@
|
||||||
|
/**************************************************
|
||||||
|
* This file includes only declarations for
|
||||||
|
* the data structures for MemoryBankShiftRegisterFabricBitstream
|
||||||
|
* Please refer to memory_bank_shift_register_fabric_bitstream.h for more details
|
||||||
|
*************************************************/
|
||||||
|
#ifndef MEMORY_BANK_SHIFT_REGISTER_FABRIC_BITSTREAM_FWD_H
|
||||||
|
#define MEMORY_BANK_SHIFT_REGISTER_FABRIC_BITSTREAM_FWD_H
|
||||||
|
|
||||||
|
#include "vtr_strong_id.h"
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
/* Strong Ids for ModuleManager */
|
||||||
|
struct memory_bank_shift_register_fabric_bitstream_word_id_tag;
|
||||||
|
|
||||||
|
typedef vtr::StrongId<memory_bank_shift_register_fabric_bitstream_word_id_tag> MemoryBankShiftRegisterFabricBitstreamWordId;
|
||||||
|
|
||||||
|
class MemoryBankShiftRegisterFabricBitstream;
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
||||||
|
|
||||||
|
#endif
|
|
@ -190,23 +190,18 @@ int write_memory_bank_fabric_bitstream_to_text_file(std::fstream& fp,
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
static
|
static
|
||||||
int write_memory_bank_flatten_fabric_bitstream_to_text_file(std::fstream& fp,
|
int write_memory_bank_flatten_fabric_bitstream_to_text_file(std::fstream& fp,
|
||||||
|
const bool& fast_configuration,
|
||||||
const bool& bit_value_to_skip,
|
const bool& bit_value_to_skip,
|
||||||
const FabricBitstream& fabric_bitstream) {
|
const FabricBitstream& fabric_bitstream) {
|
||||||
int status = 0;
|
int status = 0;
|
||||||
|
|
||||||
MemoryBankFlattenFabricBitstream fabric_bits = build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, bit_value_to_skip);
|
MemoryBankFlattenFabricBitstream fabric_bits = build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, fast_configuration, bit_value_to_skip);
|
||||||
|
|
||||||
/* The address sizes and data input sizes are the same across any element,
|
/* The address sizes and data input sizes are the same across any element,
|
||||||
* just get it from the 1st element to save runtime
|
* just get it from the 1st element to save runtime
|
||||||
*/
|
*/
|
||||||
size_t bl_addr_size = 0;
|
size_t bl_addr_size = fabric_bits.bl_vector_size();
|
||||||
for (const auto& bl_vec : fabric_bits.begin()->second) {
|
size_t wl_addr_size = fabric_bits.wl_vector_size();
|
||||||
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 */
|
/* Output information about how to intepret the bitstream */
|
||||||
fp << "// Bitstream length: " << fabric_bits.size() << std::endl;
|
fp << "// Bitstream length: " << fabric_bits.size() << std::endl;
|
||||||
|
@ -215,14 +210,14 @@ int write_memory_bank_flatten_fabric_bitstream_to_text_file(std::fstream& fp,
|
||||||
fp << "<wl_address " << wl_addr_size << " bits>";
|
fp << "<wl_address " << wl_addr_size << " bits>";
|
||||||
fp << std::endl;
|
fp << std::endl;
|
||||||
|
|
||||||
for (const auto& addr_pair : fabric_bits) {
|
for (const auto& wl_vec : fabric_bits.wl_vectors()) {
|
||||||
/* Write BL address code */
|
/* Write BL address code */
|
||||||
for (const auto& bl_vec : addr_pair.second) {
|
for (const auto& bl_unit : fabric_bits.bl_vector(wl_vec)) {
|
||||||
fp << bl_vec;
|
fp << bl_unit;
|
||||||
}
|
}
|
||||||
/* Write WL address code */
|
/* Write WL address code */
|
||||||
for (const auto& wl_vec : addr_pair.first) {
|
for (const auto& wl_unit : wl_vec) {
|
||||||
fp << wl_vec;
|
fp << wl_unit;
|
||||||
}
|
}
|
||||||
fp << std::endl;
|
fp << std::endl;
|
||||||
}
|
}
|
||||||
|
@ -230,6 +225,57 @@ int write_memory_bank_flatten_fabric_bitstream_to_text_file(std::fstream& fp,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Write the fabric bitstream fitting a memory bank protocol
|
||||||
|
* to a plain text file
|
||||||
|
*
|
||||||
|
* Return:
|
||||||
|
* - 0 if succeed
|
||||||
|
* - 1 if critical errors occured
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
int write_memory_bank_shift_register_fabric_bitstream_to_text_file(std::fstream& fp,
|
||||||
|
const bool& fast_configuration,
|
||||||
|
const bool& bit_value_to_skip,
|
||||||
|
const FabricBitstream& fabric_bitstream) {
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
|
MemoryBankShiftRegisterFabricBitstream fabric_bits = build_memory_bank_shift_register_fabric_bitstream(fabric_bitstream, fast_configuration, bit_value_to_skip);
|
||||||
|
|
||||||
|
/* Output information about how to intepret the bitstream */
|
||||||
|
fp << "// Bitstream word count: " << fabric_bits.num_words() << std::endl;
|
||||||
|
fp << "// Bitstream bl word size: " << fabric_bits.bl_word_size() << std::endl;
|
||||||
|
fp << "// Bitstream wl word size: " << fabric_bits.wl_word_size() << std::endl;
|
||||||
|
fp << "// Bitstream width (LSB -> MSB): ";
|
||||||
|
fp << "<bl shift register heads " << fabric_bits.bl_width() << " bits>";
|
||||||
|
fp << "<wl shift register heads " << fabric_bits.wl_width() << " bits>";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
size_t word_cnt = 0;
|
||||||
|
|
||||||
|
for (const auto& word : fabric_bits.words()) {
|
||||||
|
fp << "// Word " << word_cnt << std::endl;
|
||||||
|
|
||||||
|
/* Write BL address code */
|
||||||
|
fp << "// BL part " << std::endl;
|
||||||
|
for (const auto& bl_vec : fabric_bits.bl_vectors(word)) {
|
||||||
|
fp << bl_vec;
|
||||||
|
fp << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write WL address code */
|
||||||
|
fp << "// WL part " << std::endl;
|
||||||
|
for (const auto& wl_vec : fabric_bits.wl_vectors(word)) {
|
||||||
|
fp << wl_vec;
|
||||||
|
fp << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
word_cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* Write the fabric bitstream fitting a frame-based protocol
|
* Write the fabric bitstream fitting a frame-based protocol
|
||||||
* to a plain text file
|
* to a plain text file
|
||||||
|
@ -369,10 +415,15 @@ int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manage
|
||||||
apply_fast_configuration,
|
apply_fast_configuration,
|
||||||
bit_value_to_skip,
|
bit_value_to_skip,
|
||||||
fabric_bitstream);
|
fabric_bitstream);
|
||||||
} else {
|
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) {
|
||||||
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,
|
status = write_memory_bank_flatten_fabric_bitstream_to_text_file(fp,
|
||||||
|
apply_fast_configuration,
|
||||||
|
bit_value_to_skip,
|
||||||
|
fabric_bitstream);
|
||||||
|
} else {
|
||||||
|
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type());
|
||||||
|
status = write_memory_bank_shift_register_fabric_bitstream_to_text_file(fp,
|
||||||
|
apply_fast_configuration,
|
||||||
bit_value_to_skip,
|
bit_value_to_skip,
|
||||||
fabric_bitstream);
|
fabric_bitstream);
|
||||||
}
|
}
|
||||||
|
|
|
@ -97,7 +97,7 @@ void print_pnr_sdc_global_clock_ports(std::fstream& fp,
|
||||||
/* Should try to find a port defintion from simulation parameters
|
/* Should try to find a port defintion from simulation parameters
|
||||||
* If found, it means that we need to use special clock name!
|
* If found, it means that we need to use special clock name!
|
||||||
*/
|
*/
|
||||||
for (const SimulationClockId& sim_clock : sim_setting.clocks()) {
|
for (const SimulationClockId& sim_clock : sim_setting.operating_clocks()) {
|
||||||
if (port_to_constrain == sim_setting.clock_port(sim_clock)) {
|
if (port_to_constrain == sim_setting.clock_port(sim_clock)) {
|
||||||
clock_period = 1./sim_setting.clock_frequency(sim_clock);
|
clock_period = 1./sim_setting.clock_frequency(sim_clock);
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,6 +55,7 @@ namespace openfpga {
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
void fpga_fabric_verilog(ModuleManager &module_manager,
|
void fpga_fabric_verilog(ModuleManager &module_manager,
|
||||||
NetlistManager &netlist_manager,
|
NetlistManager &netlist_manager,
|
||||||
|
const std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
|
||||||
const CircuitLibrary &circuit_lib,
|
const CircuitLibrary &circuit_lib,
|
||||||
const MuxLibrary &mux_lib,
|
const MuxLibrary &mux_lib,
|
||||||
const DecoderLibrary &decoder_lib,
|
const DecoderLibrary &decoder_lib,
|
||||||
|
@ -94,6 +95,7 @@ void fpga_fabric_verilog(ModuleManager &module_manager,
|
||||||
* Without the modules in the module manager, core logic generation is not possible!!!
|
* Without the modules in the module manager, core logic generation is not possible!!!
|
||||||
*/
|
*/
|
||||||
print_verilog_submodule(module_manager, netlist_manager,
|
print_verilog_submodule(module_manager, netlist_manager,
|
||||||
|
blwl_sr_banks,
|
||||||
mux_lib, decoder_lib, circuit_lib,
|
mux_lib, decoder_lib, circuit_lib,
|
||||||
submodule_dir_path,
|
submodule_dir_path,
|
||||||
options);
|
options);
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "io_location_map.h"
|
#include "io_location_map.h"
|
||||||
#include "fabric_global_port_info.h"
|
#include "fabric_global_port_info.h"
|
||||||
#include "vpr_netlist_annotation.h"
|
#include "vpr_netlist_annotation.h"
|
||||||
|
#include "memory_bank_shift_register_banks.h"
|
||||||
#include "fabric_verilog_options.h"
|
#include "fabric_verilog_options.h"
|
||||||
#include "verilog_testbench_options.h"
|
#include "verilog_testbench_options.h"
|
||||||
|
|
||||||
|
@ -35,6 +36,7 @@ namespace openfpga {
|
||||||
|
|
||||||
void fpga_fabric_verilog(ModuleManager& module_manager,
|
void fpga_fabric_verilog(ModuleManager& module_manager,
|
||||||
NetlistManager& netlist_manager,
|
NetlistManager& netlist_manager,
|
||||||
|
const std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
const MuxLibrary& mux_lib,
|
const MuxLibrary& mux_lib,
|
||||||
const DecoderLibrary& decoder_lib,
|
const DecoderLibrary& decoder_lib,
|
||||||
|
|
|
@ -26,6 +26,7 @@ constexpr char* MUXES_VERILOG_FILE_NAME = "muxes.v";
|
||||||
constexpr char* LOCAL_ENCODER_VERILOG_FILE_NAME = "local_encoder.v";
|
constexpr char* LOCAL_ENCODER_VERILOG_FILE_NAME = "local_encoder.v";
|
||||||
constexpr char* ARCH_ENCODER_VERILOG_FILE_NAME = "arch_encoder.v";
|
constexpr char* ARCH_ENCODER_VERILOG_FILE_NAME = "arch_encoder.v";
|
||||||
constexpr char* MEMORIES_VERILOG_FILE_NAME = "memories.v";
|
constexpr char* MEMORIES_VERILOG_FILE_NAME = "memories.v";
|
||||||
|
constexpr char* SHIFT_REGISTER_BANKS_VERILOG_FILE_NAME = "shift_register_banks.v";
|
||||||
constexpr char* WIRES_VERILOG_FILE_NAME = "wires.v";
|
constexpr char* WIRES_VERILOG_FILE_NAME = "wires.v";
|
||||||
constexpr char* ESSENTIALS_VERILOG_FILE_NAME = "inv_buf_passgate.v";
|
constexpr char* ESSENTIALS_VERILOG_FILE_NAME = "inv_buf_passgate.v";
|
||||||
constexpr char* CONFIG_PERIPHERAL_VERILOG_FILE_NAME = "config_peripherals.v";
|
constexpr char* CONFIG_PERIPHERAL_VERILOG_FILE_NAME = "config_peripherals.v";
|
||||||
|
|
|
@ -0,0 +1,81 @@
|
||||||
|
/*********************************************************************
|
||||||
|
* This file includes functions to generate Verilog submodules for
|
||||||
|
* the memories that are affiliated to multiplexers and other programmable
|
||||||
|
* circuit models, such as IOPADs, LUTs, etc.
|
||||||
|
********************************************************************/
|
||||||
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
/* Headers from vtrutil library */
|
||||||
|
#include "vtr_assert.h"
|
||||||
|
#include "vtr_log.h"
|
||||||
|
|
||||||
|
/* Headers from openfpgautil library */
|
||||||
|
#include "openfpga_digest.h"
|
||||||
|
|
||||||
|
#include "mux_graph.h"
|
||||||
|
#include "module_manager.h"
|
||||||
|
#include "circuit_library_utils.h"
|
||||||
|
#include "mux_utils.h"
|
||||||
|
|
||||||
|
#include "openfpga_naming.h"
|
||||||
|
|
||||||
|
#include "verilog_constants.h"
|
||||||
|
#include "verilog_writer_utils.h"
|
||||||
|
#include "verilog_module_writer.h"
|
||||||
|
#include "verilog_shift_register_banks.h"
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
/*********************************************************************
|
||||||
|
* Generate Verilog modules for
|
||||||
|
* the shift register banks that are used to control BL/WLs
|
||||||
|
********************************************************************/
|
||||||
|
void print_verilog_submodule_shift_register_banks(const ModuleManager& module_manager,
|
||||||
|
NetlistManager& netlist_manager,
|
||||||
|
const std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
|
||||||
|
const std::string& submodule_dir,
|
||||||
|
const FabricVerilogOption& options) {
|
||||||
|
|
||||||
|
/* Plug in with the mux subckt */
|
||||||
|
std::string verilog_fname(submodule_dir + std::string(SHIFT_REGISTER_BANKS_VERILOG_FILE_NAME));
|
||||||
|
|
||||||
|
/* Create the file stream */
|
||||||
|
std::fstream fp;
|
||||||
|
fp.open(verilog_fname, std::fstream::out | std::fstream::trunc);
|
||||||
|
|
||||||
|
check_file_stream(verilog_fname.c_str(), fp);
|
||||||
|
|
||||||
|
/* Print out debugging information for if the file is not opened/created properly */
|
||||||
|
VTR_LOG("Writing Verilog netlist for shift register banks '%s' ...",
|
||||||
|
verilog_fname.c_str());
|
||||||
|
|
||||||
|
print_verilog_file_header(fp, "Shift register banks used in FPGA");
|
||||||
|
|
||||||
|
/* Create the memory circuits for the multiplexer */
|
||||||
|
for (const auto& sr_bank : blwl_sr_banks) {
|
||||||
|
for (const ModuleId& sr_module : sr_bank.shift_register_bank_unique_modules()) {
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_id(sr_module));
|
||||||
|
/* Write the module content in Verilog format */
|
||||||
|
write_verilog_module_to_file(fp, module_manager, sr_module,
|
||||||
|
options.explicit_port_mapping(),
|
||||||
|
options.default_net_type());
|
||||||
|
|
||||||
|
/* Add an empty line as a splitter */
|
||||||
|
fp << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Close the file stream */
|
||||||
|
fp.close();
|
||||||
|
|
||||||
|
/* Add fname to the netlist name list */
|
||||||
|
NetlistId nlist_id = netlist_manager.add_netlist(verilog_fname);
|
||||||
|
VTR_ASSERT(NetlistId::INVALID() != nlist_id);
|
||||||
|
netlist_manager.set_netlist_type(nlist_id, NetlistManager::SUBMODULE_NETLIST);
|
||||||
|
|
||||||
|
VTR_LOG("Done\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
|
@ -0,0 +1,29 @@
|
||||||
|
#ifndef VERILOG_SHIFT_REGISTER_BANKS_H
|
||||||
|
#define VERILOG_SHIFT_REGISTER_BANKS_H
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Include header files that are required by function declaration
|
||||||
|
*******************************************************************/
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include "memory_bank_shift_register_banks.h"
|
||||||
|
#include "module_manager.h"
|
||||||
|
#include "netlist_manager.h"
|
||||||
|
#include "fabric_verilog_options.h"
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Function declaration
|
||||||
|
*******************************************************************/
|
||||||
|
|
||||||
|
/* begin namespace openfpga */
|
||||||
|
namespace openfpga {
|
||||||
|
|
||||||
|
void print_verilog_submodule_shift_register_banks(const ModuleManager& module_manager,
|
||||||
|
NetlistManager& netlist_manager,
|
||||||
|
const std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
|
||||||
|
const std::string& submodule_dir,
|
||||||
|
const FabricVerilogOption& options);
|
||||||
|
|
||||||
|
} /* end namespace openfpga */
|
||||||
|
|
||||||
|
#endif
|
|
@ -14,6 +14,7 @@
|
||||||
#include "verilog_lut.h"
|
#include "verilog_lut.h"
|
||||||
#include "verilog_wire.h"
|
#include "verilog_wire.h"
|
||||||
#include "verilog_memory.h"
|
#include "verilog_memory.h"
|
||||||
|
#include "verilog_shift_register_banks.h"
|
||||||
#include "verilog_writer_utils.h"
|
#include "verilog_writer_utils.h"
|
||||||
|
|
||||||
#include "verilog_constants.h"
|
#include "verilog_constants.h"
|
||||||
|
@ -33,6 +34,7 @@ namespace openfpga {
|
||||||
********************************************************************/
|
********************************************************************/
|
||||||
void print_verilog_submodule(ModuleManager& module_manager,
|
void print_verilog_submodule(ModuleManager& module_manager,
|
||||||
NetlistManager& netlist_manager,
|
NetlistManager& netlist_manager,
|
||||||
|
const std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
|
||||||
const MuxLibrary& mux_lib,
|
const MuxLibrary& mux_lib,
|
||||||
const DecoderLibrary& decoder_lib,
|
const DecoderLibrary& decoder_lib,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
|
@ -84,14 +86,22 @@ void print_verilog_submodule(ModuleManager& module_manager,
|
||||||
submodule_dir,
|
submodule_dir,
|
||||||
fpga_verilog_opts.default_net_type());
|
fpga_verilog_opts.default_net_type());
|
||||||
|
|
||||||
/* 4. Memories */
|
/* Memories */
|
||||||
print_verilog_submodule_memories(const_cast<const ModuleManager&>(module_manager),
|
print_verilog_submodule_memories(const_cast<const ModuleManager&>(module_manager),
|
||||||
netlist_manager,
|
netlist_manager,
|
||||||
mux_lib, circuit_lib,
|
mux_lib, circuit_lib,
|
||||||
submodule_dir,
|
submodule_dir,
|
||||||
fpga_verilog_opts);
|
fpga_verilog_opts);
|
||||||
|
|
||||||
/* 5. Dump template for all the modules */
|
/* Shift register banks */
|
||||||
|
print_verilog_submodule_shift_register_banks(const_cast<const ModuleManager&>(module_manager),
|
||||||
|
netlist_manager,
|
||||||
|
blwl_sr_banks,
|
||||||
|
submodule_dir,
|
||||||
|
fpga_verilog_opts);
|
||||||
|
|
||||||
|
|
||||||
|
/* Dump template for all the modules */
|
||||||
if (true == fpga_verilog_opts.print_user_defined_template()) {
|
if (true == fpga_verilog_opts.print_user_defined_template()) {
|
||||||
print_verilog_submodule_templates(const_cast<const ModuleManager&>(module_manager),
|
print_verilog_submodule_templates(const_cast<const ModuleManager&>(module_manager),
|
||||||
circuit_lib,
|
circuit_lib,
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "netlist_manager.h"
|
#include "netlist_manager.h"
|
||||||
#include "mux_library.h"
|
#include "mux_library.h"
|
||||||
#include "decoder_library.h"
|
#include "decoder_library.h"
|
||||||
|
#include "memory_bank_shift_register_banks.h"
|
||||||
#include "fabric_verilog_options.h"
|
#include "fabric_verilog_options.h"
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
|
@ -19,6 +20,7 @@ namespace openfpga {
|
||||||
|
|
||||||
void print_verilog_submodule(ModuleManager& module_manager,
|
void print_verilog_submodule(ModuleManager& module_manager,
|
||||||
NetlistManager& netlist_manager,
|
NetlistManager& netlist_manager,
|
||||||
|
const std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
|
||||||
const MuxLibrary& mux_lib,
|
const MuxLibrary& mux_lib,
|
||||||
const DecoderLibrary& decoder_lib,
|
const DecoderLibrary& decoder_lib,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
|
|
|
@ -515,7 +515,7 @@ void print_verilog_testbench_clock_stimuli(std::fstream& fp,
|
||||||
/* Skip all the unrelated pin constraints */
|
/* Skip all the unrelated pin constraints */
|
||||||
VTR_ASSERT(clock_port.get_name() == pin_constraints.net(pin_constraint));
|
VTR_ASSERT(clock_port.get_name() == pin_constraints.net(pin_constraint));
|
||||||
/* Try to find which clock source is considered in simulation settings for this pin */
|
/* Try to find which clock source is considered in simulation settings for this pin */
|
||||||
for (const SimulationClockId& sim_clock_id : simulation_parameters.clocks()) {
|
for (const SimulationClockId& sim_clock_id : simulation_parameters.operating_clocks()) {
|
||||||
if (pin_constraints.pin(pin_constraint) == simulation_parameters.clock_port(sim_clock_id)) {
|
if (pin_constraints.pin(pin_constraint) == simulation_parameters.clock_port(sim_clock_id)) {
|
||||||
clk_freq_to_use = (0.5 / simulation_parameters.clock_frequency(sim_clock_id)) / VERILOG_SIM_TIMESCALE;
|
clk_freq_to_use = (0.5 / simulation_parameters.clock_frequency(sim_clock_id)) / VERILOG_SIM_TIMESCALE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -272,6 +272,11 @@ void print_verilog_top_testbench_global_clock_ports_stimuli(std::fstream& fp,
|
||||||
ModulePortId module_global_port = fabric_global_port_info.global_module_port(fabric_global_port);
|
ModulePortId module_global_port = fabric_global_port_info.global_module_port(fabric_global_port);
|
||||||
VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port));
|
VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port));
|
||||||
|
|
||||||
|
/* Skip shift register clocks, they are handled in another way */
|
||||||
|
if (true == fabric_global_port_info.global_port_is_shift_register(fabric_global_port)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
BasicPort stimuli_clock_port;
|
BasicPort stimuli_clock_port;
|
||||||
if (true == fabric_global_port_info.global_port_is_prog(fabric_global_port)) {
|
if (true == fabric_global_port_info.global_port_is_prog(fabric_global_port)) {
|
||||||
stimuli_clock_port.set_name(std::string(TOP_TB_PROG_CLOCK_PORT_NAME));
|
stimuli_clock_port.set_name(std::string(TOP_TB_PROG_CLOCK_PORT_NAME));
|
||||||
|
@ -290,7 +295,7 @@ void print_verilog_top_testbench_global_clock_ports_stimuli(std::fstream& fp,
|
||||||
/* Should try to find a port defintion from simulation parameters
|
/* Should try to find a port defintion from simulation parameters
|
||||||
* If found, it means that we need to use special clock name!
|
* If found, it means that we need to use special clock name!
|
||||||
*/
|
*/
|
||||||
for (const SimulationClockId& sim_clock : simulation_parameters.clocks()) {
|
for (const SimulationClockId& sim_clock : simulation_parameters.operating_clocks()) {
|
||||||
if (global_port_to_connect == simulation_parameters.clock_port(sim_clock)) {
|
if (global_port_to_connect == simulation_parameters.clock_port(sim_clock)) {
|
||||||
stimuli_clock_port.set_name(generate_top_testbench_clock_name(std::string(TOP_TB_OP_CLOCK_PORT_PREFIX), simulation_parameters.clock_name(sim_clock)));
|
stimuli_clock_port.set_name(generate_top_testbench_clock_name(std::string(TOP_TB_OP_CLOCK_PORT_PREFIX), simulation_parameters.clock_name(sim_clock)));
|
||||||
}
|
}
|
||||||
|
@ -563,6 +568,11 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp,
|
||||||
fabric_global_port_info,
|
fabric_global_port_info,
|
||||||
simulation_parameters);
|
simulation_parameters);
|
||||||
|
|
||||||
|
print_verilog_top_testbench_global_shift_register_clock_ports_stimuli(fp,
|
||||||
|
module_manager,
|
||||||
|
top_module,
|
||||||
|
fabric_global_port_info);
|
||||||
|
|
||||||
print_verilog_top_testbench_global_config_done_ports_stimuli(fp,
|
print_verilog_top_testbench_global_config_done_ports_stimuli(fp,
|
||||||
module_manager,
|
module_manager,
|
||||||
top_module,
|
top_module,
|
||||||
|
@ -640,7 +650,7 @@ void print_verilog_top_testbench_benchmark_clock_ports(std::fstream& fp,
|
||||||
/* Skip all the unrelated pin constraints */
|
/* Skip all the unrelated pin constraints */
|
||||||
VTR_ASSERT(clock_port_name == pin_constraints.net(pin_constraint));
|
VTR_ASSERT(clock_port_name == pin_constraints.net(pin_constraint));
|
||||||
/* Try to find which clock source is considered in simulation settings for this pin */
|
/* Try to find which clock source is considered in simulation settings for this pin */
|
||||||
for (const SimulationClockId& sim_clock_id : simulation_parameters.clocks()) {
|
for (const SimulationClockId& sim_clock_id : simulation_parameters.operating_clocks()) {
|
||||||
if (pin_constraints.pin(pin_constraint) == simulation_parameters.clock_port(sim_clock_id)) {
|
if (pin_constraints.pin(pin_constraint) == simulation_parameters.clock_port(sim_clock_id)) {
|
||||||
std::string sim_clock_port_name = generate_top_testbench_clock_name(std::string(TOP_TB_OP_CLOCK_PORT_PREFIX), simulation_parameters.clock_name(sim_clock_id));
|
std::string sim_clock_port_name = generate_top_testbench_clock_name(std::string(TOP_TB_OP_CLOCK_PORT_PREFIX), simulation_parameters.clock_name(sim_clock_id));
|
||||||
clock_source_to_connect = BasicPort(sim_clock_port_name, 1);
|
clock_source_to_connect = BasicPort(sim_clock_port_name, 1);
|
||||||
|
@ -742,7 +752,7 @@ void print_verilog_top_testbench_ports(std::fstream& fp,
|
||||||
fp << generate_verilog_port(VERILOG_PORT_REG, prog_clock_register_port) << ";" << std::endl;
|
fp << generate_verilog_port(VERILOG_PORT_REG, prog_clock_register_port) << ";" << std::endl;
|
||||||
|
|
||||||
/* Multiple operating clocks based on the simulation settings */
|
/* Multiple operating clocks based on the simulation settings */
|
||||||
for (const SimulationClockId& sim_clock : simulation_parameters.clocks()) {
|
for (const SimulationClockId& sim_clock : simulation_parameters.operating_clocks()) {
|
||||||
std::string sim_clock_port_name = generate_top_testbench_clock_name(std::string(TOP_TB_OP_CLOCK_PORT_PREFIX), simulation_parameters.clock_name(sim_clock));
|
std::string sim_clock_port_name = generate_top_testbench_clock_name(std::string(TOP_TB_OP_CLOCK_PORT_PREFIX), simulation_parameters.clock_name(sim_clock));
|
||||||
BasicPort sim_clock_port(sim_clock_port_name, 1);
|
BasicPort sim_clock_port(sim_clock_port_name, 1);
|
||||||
fp << generate_verilog_port(VERILOG_PORT_WIRE, sim_clock_port) << ";" << std::endl;
|
fp << generate_verilog_port(VERILOG_PORT_WIRE, sim_clock_port) << ";" << std::endl;
|
||||||
|
@ -862,9 +872,9 @@ size_t calculate_num_config_clock_cycles(const ConfigProtocol& config_protocol,
|
||||||
100. * ((float)num_config_clock_cycles / (float)full_num_config_clock_cycles - 1.));
|
100. * ((float)num_config_clock_cycles / (float)full_num_config_clock_cycles - 1.));
|
||||||
}
|
}
|
||||||
} else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) {
|
} 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();
|
num_config_clock_cycles = 1 + build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, fast_configuration, bit_value_to_skip).size();
|
||||||
} else if (BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()) {
|
} else if (BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()) {
|
||||||
/* TODO */
|
num_config_clock_cycles = 1 + build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, fast_configuration, bit_value_to_skip).size();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1010,7 +1020,7 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp,
|
||||||
fp << std::endl;
|
fp << std::endl;
|
||||||
|
|
||||||
/* Generate stimuli waveform for multiple user-defined operating clock signals */
|
/* Generate stimuli waveform for multiple user-defined operating clock signals */
|
||||||
for (const SimulationClockId& sim_clock : simulation_parameters.clocks()) {
|
for (const SimulationClockId& sim_clock : simulation_parameters.operating_clocks()) {
|
||||||
print_verilog_comment(fp, "----- Begin raw operating clock signal '" + simulation_parameters.clock_name(sim_clock) + "' generation -----");
|
print_verilog_comment(fp, "----- Begin raw operating clock signal '" + simulation_parameters.clock_name(sim_clock) + "' generation -----");
|
||||||
std::string sim_clock_port_name = generate_top_testbench_clock_name(std::string(TOP_TB_OP_CLOCK_PORT_PREFIX), simulation_parameters.clock_name(sim_clock));
|
std::string sim_clock_port_name = generate_top_testbench_clock_name(std::string(TOP_TB_OP_CLOCK_PORT_PREFIX), simulation_parameters.clock_name(sim_clock));
|
||||||
BasicPort sim_clock_port(sim_clock_port_name, 1);
|
BasicPort sim_clock_port(sim_clock_port_name, 1);
|
||||||
|
@ -1112,21 +1122,30 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp,
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
static
|
static
|
||||||
void print_verilog_top_testbench_configuration_protocol_stimulus(std::fstream& fp,
|
void print_verilog_top_testbench_configuration_protocol_stimulus(std::fstream& fp,
|
||||||
const e_config_protocol_type& config_protocol_type,
|
const ConfigProtocol& config_protocol,
|
||||||
const ModuleManager& module_manager,
|
const ModuleManager& module_manager,
|
||||||
const ModuleId& top_module,
|
const ModuleId& top_module,
|
||||||
|
const bool& fast_configuration,
|
||||||
|
const bool& bit_value_to_skip,
|
||||||
|
const FabricBitstream& fabric_bitstream,
|
||||||
const float& prog_clock_period,
|
const float& prog_clock_period,
|
||||||
const float& timescale) {
|
const float& timescale) {
|
||||||
/* Validate the file stream */
|
/* Validate the file stream */
|
||||||
valid_file_stream(fp);
|
valid_file_stream(fp);
|
||||||
|
|
||||||
/* Branch on the type of configuration protocol */
|
/* Branch on the type of configuration protocol */
|
||||||
switch (config_protocol_type) {
|
switch (config_protocol.type()) {
|
||||||
case CONFIG_MEM_STANDALONE:
|
case CONFIG_MEM_STANDALONE:
|
||||||
break;
|
break;
|
||||||
case CONFIG_MEM_SCAN_CHAIN:
|
case CONFIG_MEM_SCAN_CHAIN:
|
||||||
break;
|
break;
|
||||||
case CONFIG_MEM_QL_MEMORY_BANK:
|
case CONFIG_MEM_QL_MEMORY_BANK:
|
||||||
|
print_verilog_top_testbench_configuration_protocol_ql_memory_bank_stimulus(fp,
|
||||||
|
config_protocol,
|
||||||
|
module_manager,top_module,
|
||||||
|
fast_configuration, bit_value_to_skip, fabric_bitstream,
|
||||||
|
prog_clock_period, timescale);
|
||||||
|
break;
|
||||||
case CONFIG_MEM_MEMORY_BANK:
|
case CONFIG_MEM_MEMORY_BANK:
|
||||||
case CONFIG_MEM_FRAME_BASED: {
|
case CONFIG_MEM_FRAME_BASED: {
|
||||||
ModulePortId en_port_id = module_manager.find_module_port(top_module,
|
ModulePortId en_port_id = module_manager.find_module_port(top_module,
|
||||||
|
@ -1935,7 +1954,7 @@ int print_verilog_full_testbench(const ModuleManager& module_manager,
|
||||||
float prog_clock_period = (1./simulation_parameters.programming_clock_frequency());
|
float prog_clock_period = (1./simulation_parameters.programming_clock_frequency());
|
||||||
float default_op_clock_period = (1./simulation_parameters.default_operating_clock_frequency());
|
float default_op_clock_period = (1./simulation_parameters.default_operating_clock_frequency());
|
||||||
float max_op_clock_period = 0.;
|
float max_op_clock_period = 0.;
|
||||||
for (const SimulationClockId& clock_id : simulation_parameters.clocks()) {
|
for (const SimulationClockId& clock_id : simulation_parameters.operating_clocks()) {
|
||||||
max_op_clock_period = std::max(max_op_clock_period, (float)(1./simulation_parameters.clock_frequency(clock_id)));
|
max_op_clock_period = std::max(max_op_clock_period, (float)(1./simulation_parameters.clock_frequency(clock_id)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1956,8 +1975,9 @@ int print_verilog_full_testbench(const ModuleManager& module_manager,
|
||||||
|
|
||||||
/* Generate stimuli for programming interface */
|
/* Generate stimuli for programming interface */
|
||||||
print_verilog_top_testbench_configuration_protocol_stimulus(fp,
|
print_verilog_top_testbench_configuration_protocol_stimulus(fp,
|
||||||
config_protocol.type(),
|
config_protocol,
|
||||||
module_manager, top_module,
|
module_manager, top_module,
|
||||||
|
fast_configuration, bit_value_to_skip, fabric_bitstream,
|
||||||
prog_clock_period,
|
prog_clock_period,
|
||||||
VERILOG_SIM_TIMESCALE);
|
VERILOG_SIM_TIMESCALE);
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,17 @@
|
||||||
/* begin namespace openfpga */
|
/* begin namespace openfpga */
|
||||||
namespace openfpga {
|
namespace openfpga {
|
||||||
|
|
||||||
|
constexpr char* TOP_TB_BL_SHIFT_REGISTER_CLOCK_PORT_NAME = "bl_sr_clock";
|
||||||
|
constexpr char* TOP_TB_WL_SHIFT_REGISTER_CLOCK_PORT_NAME = "wl_sr_clock";
|
||||||
|
constexpr char* TOP_TB_START_BL_SHIFT_REGISTER_PORT_NAME = "start_bl_sr";
|
||||||
|
constexpr char* TOP_TB_START_WL_SHIFT_REGISTER_PORT_NAME = "start_wl_sr";
|
||||||
|
constexpr char* TOP_TB_BL_SHIFT_REGISTER_COUNT_PORT_NAME = "bl_sr_count";
|
||||||
|
constexpr char* TOP_TB_WL_SHIFT_REGISTER_COUNT_PORT_NAME = "wl_sr_count";
|
||||||
|
constexpr char* TOP_TB_BITSTREAM_BL_HEAD_WIDTH_VARIABLE = "BITSTREAM_BL_HEAD_WIDTH";
|
||||||
|
constexpr char* TOP_TB_BITSTREAM_WL_HEAD_WIDTH_VARIABLE = "BITSTREAM_WL_HEAD_WIDTH";
|
||||||
|
constexpr char* TOP_TB_BITSTREAM_BL_WORD_SIZE_VARIABLE = "BITSTREAM_BL_WORD_SIZE";
|
||||||
|
constexpr char* TOP_TB_BITSTREAM_WL_WORD_SIZE_VARIABLE = "BITSTREAM_WL_WORD_SIZE";
|
||||||
|
|
||||||
void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp,
|
void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp,
|
||||||
const ModuleManager& module_manager,
|
const ModuleManager& module_manager,
|
||||||
const ModuleId& top_module,
|
const ModuleId& top_module,
|
||||||
|
@ -61,7 +72,28 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type());
|
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type());
|
||||||
/* TODO */
|
print_verilog_comment(fp, std::string("---- Bit-Line ports -----"));
|
||||||
|
for (const ConfigRegionId& region : module_manager.regions(top_module)) {
|
||||||
|
ModulePortId sr_head_port_id = module_manager.find_module_port(top_module,
|
||||||
|
generate_regional_blwl_port_name(std::string(BL_SHIFT_REGISTER_CHAIN_HEAD_NAME), region));
|
||||||
|
BasicPort sr_head_port = module_manager.module_port(top_module, sr_head_port_id);
|
||||||
|
fp << generate_verilog_port(VERILOG_PORT_REG, sr_head_port) << ";" << std::endl;
|
||||||
|
|
||||||
|
ModulePortId sr_tail_port_id = module_manager.find_module_port(top_module,
|
||||||
|
generate_regional_blwl_port_name(std::string(BL_SHIFT_REGISTER_CHAIN_TAIL_NAME), region));
|
||||||
|
BasicPort sr_tail_port = module_manager.module_port(top_module, sr_tail_port_id);
|
||||||
|
fp << generate_verilog_port(VERILOG_PORT_WIRE, sr_tail_port) << ";" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* BL Shift register clock and registers */
|
||||||
|
BasicPort sr_clock_port(std::string(TOP_TB_BL_SHIFT_REGISTER_CLOCK_PORT_NAME), 1);
|
||||||
|
fp << generate_verilog_port(VERILOG_PORT_REG, sr_clock_port) << ";" << std::endl;
|
||||||
|
|
||||||
|
/* Register to enable/disable bl/wl shift register clocks */
|
||||||
|
BasicPort start_bl_sr_port(TOP_TB_START_BL_SHIFT_REGISTER_PORT_NAME, 1);
|
||||||
|
fp << generate_verilog_port(VERILOG_PORT_REG, start_bl_sr_port) << ";" << std::endl;
|
||||||
|
/* Register to count bl/wl shift register clocks */
|
||||||
|
fp << "integer " << TOP_TB_BL_SHIFT_REGISTER_COUNT_PORT_NAME << ";" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print the address port for the Word-Line decoder here */
|
/* Print the address port for the Word-Line decoder here */
|
||||||
|
@ -82,7 +114,28 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type());
|
VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type());
|
||||||
/* TODO */
|
print_verilog_comment(fp, std::string("---- Word-Line ports -----"));
|
||||||
|
for (const ConfigRegionId& region : module_manager.regions(top_module)) {
|
||||||
|
ModulePortId sr_head_port_id = module_manager.find_module_port(top_module,
|
||||||
|
generate_regional_blwl_port_name(std::string(WL_SHIFT_REGISTER_CHAIN_HEAD_NAME), region));
|
||||||
|
BasicPort sr_head_port = module_manager.module_port(top_module, sr_head_port_id);
|
||||||
|
fp << generate_verilog_port(VERILOG_PORT_REG, sr_head_port) << ";" << std::endl;
|
||||||
|
|
||||||
|
ModulePortId sr_tail_port_id = module_manager.find_module_port(top_module,
|
||||||
|
generate_regional_blwl_port_name(std::string(WL_SHIFT_REGISTER_CHAIN_TAIL_NAME), region));
|
||||||
|
BasicPort sr_tail_port = module_manager.module_port(top_module, sr_tail_port_id);
|
||||||
|
fp << generate_verilog_port(VERILOG_PORT_WIRE, sr_tail_port) << ";" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* WL Shift register clock and registers */
|
||||||
|
BasicPort sr_clock_port(std::string(TOP_TB_WL_SHIFT_REGISTER_CLOCK_PORT_NAME), 1);
|
||||||
|
fp << generate_verilog_port(VERILOG_PORT_REG, sr_clock_port) << ";" << std::endl;
|
||||||
|
|
||||||
|
/* Register to enable/disable bl/wl shift register clocks */
|
||||||
|
BasicPort start_wl_sr_port(TOP_TB_START_WL_SHIFT_REGISTER_PORT_NAME, 1);
|
||||||
|
fp << generate_verilog_port(VERILOG_PORT_REG, start_wl_sr_port) << ";" << std::endl;
|
||||||
|
/* Register to count bl/wl shift register clocks */
|
||||||
|
fp << "integer " << TOP_TB_WL_SHIFT_REGISTER_COUNT_PORT_NAME << ";" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print the data-input port: only available when BL has a decoder */
|
/* Print the data-input port: only available when BL has a decoder */
|
||||||
|
@ -146,6 +199,139 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp,
|
||||||
fp << ";" << std::endl;
|
fp << ";" << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void print_verilog_top_testbench_global_shift_register_clock_ports_stimuli(std::fstream& fp,
|
||||||
|
const ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const FabricGlobalPortInfo& fabric_global_port_info) {
|
||||||
|
/* Validate the file stream */
|
||||||
|
valid_file_stream(fp);
|
||||||
|
|
||||||
|
/* Connect global clock ports to shift-register programming clock signal */
|
||||||
|
for (const FabricGlobalPortId& fabric_global_port : fabric_global_port_info.global_ports()) {
|
||||||
|
/* Only care shift register clocks */
|
||||||
|
if (false == fabric_global_port_info.global_port_is_clock(fabric_global_port)
|
||||||
|
|| false == fabric_global_port_info.global_port_is_shift_register(fabric_global_port)
|
||||||
|
|| false == fabric_global_port_info.global_port_is_prog(fabric_global_port)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* Find the module port */
|
||||||
|
ModulePortId module_global_port = fabric_global_port_info.global_module_port(fabric_global_port);
|
||||||
|
VTR_ASSERT(true == module_manager.valid_module_port_id(top_module, module_global_port));
|
||||||
|
|
||||||
|
BasicPort stimuli_clock_port;
|
||||||
|
|
||||||
|
if (true == fabric_global_port_info.global_port_is_bl(fabric_global_port)) {
|
||||||
|
stimuli_clock_port.set_name(std::string(TOP_TB_BL_SHIFT_REGISTER_CLOCK_PORT_NAME));
|
||||||
|
stimuli_clock_port.set_width(1);
|
||||||
|
} else {
|
||||||
|
VTR_ASSERT(true == fabric_global_port_info.global_port_is_wl(fabric_global_port));
|
||||||
|
stimuli_clock_port.set_name(std::string(TOP_TB_WL_SHIFT_REGISTER_CLOCK_PORT_NAME));
|
||||||
|
stimuli_clock_port.set_width(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const size_t& pin : module_manager.module_port(top_module, module_global_port).pins()) {
|
||||||
|
BasicPort global_port_to_connect(module_manager.module_port(top_module, module_global_port).get_name(), pin, pin);
|
||||||
|
print_verilog_wire_connection(fp, global_port_to_connect,
|
||||||
|
stimuli_clock_port,
|
||||||
|
1 == fabric_global_port_info.global_port_default_value(fabric_global_port));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate the Verilog codes for a shift register clocks that controls BL/WL protocols
|
||||||
|
*/
|
||||||
|
static
|
||||||
|
void print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(std::fstream& fp,
|
||||||
|
const BasicPort& start_sr_port,
|
||||||
|
const BasicPort& sr_clock_port,
|
||||||
|
const float& sr_clock_period) {
|
||||||
|
/* Validate the file stream */
|
||||||
|
valid_file_stream(fp);
|
||||||
|
|
||||||
|
fp << "always";
|
||||||
|
fp << " @(posedge " << generate_verilog_port(VERILOG_PORT_CONKT, start_sr_port) << ")";
|
||||||
|
fp << " begin";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
fp << "\t";
|
||||||
|
fp << generate_verilog_port_constant_values(sr_clock_port, std::vector<size_t>(sr_clock_port.get_width(), 0), true);
|
||||||
|
fp << ";" << std::endl;
|
||||||
|
|
||||||
|
fp << "\t";
|
||||||
|
fp << "while (" << generate_verilog_port(VERILOG_PORT_CONKT, start_sr_port) << ") begin";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
fp << "\t\t";
|
||||||
|
fp << "#" << sr_clock_period << " ";
|
||||||
|
print_verilog_register_connection(fp, sr_clock_port, sr_clock_port, true);
|
||||||
|
|
||||||
|
fp << "\t";
|
||||||
|
fp << "end";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
fp << "\t";
|
||||||
|
fp << generate_verilog_port_constant_values(sr_clock_port, std::vector<size_t>(sr_clock_port.get_width(), 0), true);
|
||||||
|
fp << ";" << std::endl;
|
||||||
|
|
||||||
|
fp << "end";
|
||||||
|
fp << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_verilog_top_testbench_configuration_protocol_ql_memory_bank_stimulus(std::fstream& fp,
|
||||||
|
const ConfigProtocol& config_protocol,
|
||||||
|
const ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const bool& fast_configuration,
|
||||||
|
const bool& bit_value_to_skip,
|
||||||
|
const FabricBitstream& fabric_bitstream,
|
||||||
|
const float& prog_clock_period,
|
||||||
|
const float& timescale) {
|
||||||
|
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);
|
||||||
|
print_verilog_comment(fp, std::string("---- Generate enable signal waveform -----"));
|
||||||
|
print_verilog_shifted_clock_stimuli(fp, en_register_port,
|
||||||
|
0.25 * prog_clock_period / timescale,
|
||||||
|
0.5 * prog_clock_period / timescale, 0);
|
||||||
|
|
||||||
|
/* Stimulus only for shift-register-based BL/WL protocols */
|
||||||
|
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME) + std::string(TOP_TB_CLOCK_REG_POSTFIX), 1);
|
||||||
|
BasicPort bl_sr_clock_port(TOP_TB_BL_SHIFT_REGISTER_CLOCK_PORT_NAME, 1);
|
||||||
|
BasicPort wl_sr_clock_port(TOP_TB_WL_SHIFT_REGISTER_CLOCK_PORT_NAME, 1);
|
||||||
|
BasicPort start_bl_sr_port(TOP_TB_START_BL_SHIFT_REGISTER_PORT_NAME, 1);
|
||||||
|
BasicPort start_wl_sr_port(TOP_TB_START_WL_SHIFT_REGISTER_PORT_NAME, 1);
|
||||||
|
|
||||||
|
/* Reorganize the fabric bitstream by the same address across regions */
|
||||||
|
if (CONFIG_MEM_QL_MEMORY_BANK == config_protocol.type()) {
|
||||||
|
MemoryBankShiftRegisterFabricBitstream fabric_bits_by_addr = build_memory_bank_shift_register_fabric_bitstream(fabric_bitstream,
|
||||||
|
fast_configuration,
|
||||||
|
bit_value_to_skip);
|
||||||
|
|
||||||
|
/* TODO: Consider auto-tuned clock period for now:
|
||||||
|
* - the BL/WL shift register clock only works in the second half of the programming clock period
|
||||||
|
* - add 2 idle clocks to avoid racing between programming clock and shift register clocks at edge
|
||||||
|
*/
|
||||||
|
float bl_sr_clock_period = 0.25 * prog_clock_period / (fabric_bits_by_addr.bl_word_size() + 2) / timescale;
|
||||||
|
float wl_sr_clock_period = 0.25 * prog_clock_period / (fabric_bits_by_addr.wl_word_size() + 2) / timescale;
|
||||||
|
|
||||||
|
if (BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()) {
|
||||||
|
print_verilog_comment(fp, "----- BL Shift register clock generator -----");
|
||||||
|
print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(fp, start_bl_sr_port, bl_sr_clock_port, bl_sr_clock_period);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type()) {
|
||||||
|
print_verilog_comment(fp, "----- WL Shift register clock generator -----");
|
||||||
|
print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(fp, start_wl_sr_port, wl_sr_clock_port, wl_sr_clock_period);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Verilog codes to load bitstream from a bit file for memory bank using flatten BL/WLs */
|
/* Verilog codes to load bitstream from a bit file for memory bank using flatten BL/WLs */
|
||||||
static
|
static
|
||||||
void print_verilog_full_testbench_ql_memory_bank_flatten_bitstream(std::fstream& fp,
|
void print_verilog_full_testbench_ql_memory_bank_flatten_bitstream(std::fstream& fp,
|
||||||
|
@ -158,13 +344,9 @@ void print_verilog_full_testbench_ql_memory_bank_flatten_bitstream(std::fstream&
|
||||||
/* Validate the file stream */
|
/* Validate the file stream */
|
||||||
valid_file_stream(fp);
|
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 */
|
/* Reorganize the fabric bitstream by the same address across regions */
|
||||||
MemoryBankFlattenFabricBitstream fabric_bits_by_addr = build_memory_bank_flatten_fabric_bitstream(fabric_bitstream,
|
MemoryBankFlattenFabricBitstream fabric_bits_by_addr = build_memory_bank_flatten_fabric_bitstream(fabric_bitstream,
|
||||||
|
fast_configuration,
|
||||||
bit_value_to_skip);
|
bit_value_to_skip);
|
||||||
|
|
||||||
/* Feed address and data input pair one by one
|
/* Feed address and data input pair one by one
|
||||||
|
@ -285,6 +467,268 @@ void print_verilog_full_testbench_ql_memory_bank_flatten_bitstream(std::fstream&
|
||||||
print_verilog_comment(fp, "----- End bitstream loading during configuration phase -----");
|
print_verilog_comment(fp, "----- End bitstream loading during configuration phase -----");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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_shift_register_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);
|
||||||
|
|
||||||
|
/* Reorganize the fabric bitstream by the same address across regions */
|
||||||
|
MemoryBankShiftRegisterFabricBitstream fabric_bits_by_addr = build_memory_bank_shift_register_fabric_bitstream(fabric_bitstream,
|
||||||
|
fast_configuration,
|
||||||
|
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_head_ports;
|
||||||
|
for (const ConfigRegionId& region : module_manager.regions(top_module)) {
|
||||||
|
ModulePortId cur_bl_head_port_id = module_manager.find_module_port(top_module,
|
||||||
|
generate_regional_blwl_port_name(std::string(BL_SHIFT_REGISTER_CHAIN_HEAD_NAME), region));
|
||||||
|
bl_head_ports.push_back(module_manager.module_port(top_module, cur_bl_head_port_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<BasicPort> wl_head_ports;
|
||||||
|
for (const ConfigRegionId& region : module_manager.regions(top_module)) {
|
||||||
|
ModulePortId cur_wl_head_port_id = module_manager.find_module_port(top_module,
|
||||||
|
generate_regional_blwl_port_name(std::string(WL_SHIFT_REGISTER_CHAIN_HEAD_NAME), region));
|
||||||
|
wl_head_ports.push_back(module_manager.module_port(top_module, cur_wl_head_port_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate the total size of BL/WL ports */
|
||||||
|
size_t bl_head_port_width = 0;
|
||||||
|
for (const BasicPort& bl_head_port : bl_head_ports) {
|
||||||
|
bl_head_port_width += bl_head_port.get_width();
|
||||||
|
}
|
||||||
|
VTR_ASSERT(bl_head_port_width == fabric_bits_by_addr.bl_width());
|
||||||
|
|
||||||
|
size_t wl_head_port_width = 0;
|
||||||
|
for (const BasicPort& wl_head_port : wl_head_ports) {
|
||||||
|
wl_head_port_width += wl_head_port.get_width();
|
||||||
|
}
|
||||||
|
VTR_ASSERT(wl_head_port_width == fabric_bits_by_addr.wl_width());
|
||||||
|
|
||||||
|
std::vector<size_t> initial_bl_head_values(bl_head_port_width, 0);
|
||||||
|
std::vector<size_t> initial_wl_head_values(wl_head_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.num_words());
|
||||||
|
print_verilog_define_flag(fp, std::string(TOP_TB_BITSTREAM_WIDTH_VARIABLE), std::max(bl_head_port_width, wl_head_port_width));
|
||||||
|
print_verilog_define_flag(fp, std::string(TOP_TB_BITSTREAM_BL_HEAD_WIDTH_VARIABLE), bl_head_port_width);
|
||||||
|
print_verilog_define_flag(fp, std::string(TOP_TB_BITSTREAM_WL_HEAD_WIDTH_VARIABLE), wl_head_port_width);
|
||||||
|
print_verilog_define_flag(fp, std::string(TOP_TB_BITSTREAM_BL_WORD_SIZE_VARIABLE), fabric_bits_by_addr.bl_word_size());
|
||||||
|
print_verilog_define_flag(fp, std::string(TOP_TB_BITSTREAM_WL_WORD_SIZE_VARIABLE), fabric_bits_by_addr.wl_word_size());
|
||||||
|
|
||||||
|
/* 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:`";
|
||||||
|
fp << TOP_TB_BITSTREAM_LENGTH_VARIABLE << "*(`" << TOP_TB_BITSTREAM_BL_WORD_SIZE_VARIABLE;
|
||||||
|
fp << " + `"<< TOP_TB_BITSTREAM_WL_WORD_SIZE_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 head port default input -----");
|
||||||
|
fp << "\t";
|
||||||
|
fp << generate_verilog_ports_constant_values(bl_head_ports, initial_bl_head_values);
|
||||||
|
fp << ";";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
print_verilog_comment(fp, "----- Word-Line head port default input -----");
|
||||||
|
fp << "\t";
|
||||||
|
fp << generate_verilog_ports_constant_values(wl_head_ports, initial_wl_head_values);
|
||||||
|
fp << ";";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
fp << "\t";
|
||||||
|
fp << TOP_TB_BITSTREAM_INDEX_REG_NAME << " <= 0";
|
||||||
|
fp << ";";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
BasicPort start_bl_sr_port(TOP_TB_START_BL_SHIFT_REGISTER_PORT_NAME, 1);
|
||||||
|
BasicPort start_wl_sr_port(TOP_TB_START_WL_SHIFT_REGISTER_PORT_NAME, 1);
|
||||||
|
|
||||||
|
fp << "\t";
|
||||||
|
fp << generate_verilog_port_constant_values(start_bl_sr_port, std::vector<size_t>(start_bl_sr_port.get_width(), 0), true);
|
||||||
|
fp << ";";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
fp << "\t";
|
||||||
|
fp << generate_verilog_port_constant_values(start_wl_sr_port, std::vector<size_t>(start_wl_sr_port.get_width(), 0), true);
|
||||||
|
fp << ";";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
fp << "end";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
|
||||||
|
BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME) + std::string(TOP_TB_CLOCK_REG_POSTFIX), 1);
|
||||||
|
BasicPort bl_sr_clock_port(TOP_TB_BL_SHIFT_REGISTER_CLOCK_PORT_NAME, 1);
|
||||||
|
BasicPort wl_sr_clock_port(TOP_TB_WL_SHIFT_REGISTER_CLOCK_PORT_NAME, 1);
|
||||||
|
|
||||||
|
print_verilog_comment(fp, "----- Begin bitstream loading during configuration phase -----");
|
||||||
|
fp << "always";
|
||||||
|
fp << " @(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ")";
|
||||||
|
fp << " begin";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
/* Finished all the configuration words, raise the configuration done signal */
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* When there are still configuration words to be load, start the BL and WL shift register clock */
|
||||||
|
fp << "\t\t";
|
||||||
|
fp << generate_verilog_port_constant_values(start_bl_sr_port, std::vector<size_t>(start_bl_sr_port.get_width(), 1), true);
|
||||||
|
fp << ";";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
fp << "\t\t";
|
||||||
|
fp << generate_verilog_port_constant_values(start_wl_sr_port, std::vector<size_t>(start_wl_sr_port.get_width(), 1), true);
|
||||||
|
fp << ";";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
fp << "\t\t";
|
||||||
|
fp << TOP_TB_BL_SHIFT_REGISTER_COUNT_PORT_NAME << " = 0;";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
fp << "\t\t";
|
||||||
|
fp << TOP_TB_WL_SHIFT_REGISTER_COUNT_PORT_NAME << " = 0;";
|
||||||
|
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;
|
||||||
|
|
||||||
|
/* Load data to BL shift register chains */
|
||||||
|
fp << "always";
|
||||||
|
fp << " @(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, bl_sr_clock_port) << ")";
|
||||||
|
fp << " begin";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
fp << "\t";
|
||||||
|
fp << "if (";
|
||||||
|
fp << TOP_TB_BL_SHIFT_REGISTER_COUNT_PORT_NAME;
|
||||||
|
fp << " >= ";
|
||||||
|
fp << "`" << TOP_TB_BITSTREAM_BL_WORD_SIZE_VARIABLE << " - 1";
|
||||||
|
fp << ") begin";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
fp << "\t\t";
|
||||||
|
fp << generate_verilog_port_constant_values(start_bl_sr_port, std::vector<size_t>(start_bl_sr_port.get_width(), 0), true);
|
||||||
|
fp << ";" << std::endl;
|
||||||
|
|
||||||
|
fp << "\t\t";
|
||||||
|
fp << TOP_TB_BL_SHIFT_REGISTER_COUNT_PORT_NAME << " = 0;";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
fp << "\t";
|
||||||
|
fp << "end else begin" << std::endl;
|
||||||
|
|
||||||
|
fp << "\t\t";
|
||||||
|
fp << generate_verilog_ports(bl_head_ports);
|
||||||
|
fp << " <= ";
|
||||||
|
fp << TOP_TB_BITSTREAM_MEM_REG_NAME << "[(";
|
||||||
|
fp << TOP_TB_BITSTREAM_INDEX_REG_NAME << "-1)*(`" << TOP_TB_BITSTREAM_BL_WORD_SIZE_VARIABLE << " + `" << TOP_TB_BITSTREAM_WL_WORD_SIZE_VARIABLE << ") + " << TOP_TB_BL_SHIFT_REGISTER_COUNT_PORT_NAME;
|
||||||
|
fp << "];" << std::endl;
|
||||||
|
|
||||||
|
fp << "\t\t";
|
||||||
|
fp << TOP_TB_BL_SHIFT_REGISTER_COUNT_PORT_NAME << " = ";
|
||||||
|
fp << TOP_TB_BL_SHIFT_REGISTER_COUNT_PORT_NAME << " + 1;";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
fp << "\t";
|
||||||
|
fp << "end";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
fp << "end";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
/* Load data to WL shift register chains */
|
||||||
|
fp << "always";
|
||||||
|
fp << " @(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, wl_sr_clock_port) << ")";
|
||||||
|
fp << " begin";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
fp << "\t";
|
||||||
|
fp << "if (";
|
||||||
|
fp << TOP_TB_WL_SHIFT_REGISTER_COUNT_PORT_NAME;
|
||||||
|
fp << " >= ";
|
||||||
|
fp << "`" << TOP_TB_BITSTREAM_WL_WORD_SIZE_VARIABLE << " - 1";
|
||||||
|
fp << ") begin";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
fp << "\t\t";
|
||||||
|
fp << generate_verilog_port_constant_values(start_wl_sr_port, std::vector<size_t>(start_wl_sr_port.get_width(), 0), true);
|
||||||
|
fp << ";" << std::endl;
|
||||||
|
|
||||||
|
fp << "\t\t";
|
||||||
|
fp << TOP_TB_WL_SHIFT_REGISTER_COUNT_PORT_NAME << " = 0;";
|
||||||
|
fp << std::endl;
|
||||||
|
|
||||||
|
fp << "\t";
|
||||||
|
fp << "end else begin" << std::endl;
|
||||||
|
|
||||||
|
fp << "\t\t";
|
||||||
|
fp << generate_verilog_ports(wl_head_ports);
|
||||||
|
fp << " <= ";
|
||||||
|
fp << TOP_TB_BITSTREAM_MEM_REG_NAME << "[(";
|
||||||
|
fp << TOP_TB_BITSTREAM_INDEX_REG_NAME << "-1)*(`" << TOP_TB_BITSTREAM_BL_WORD_SIZE_VARIABLE << " + `" << TOP_TB_BITSTREAM_WL_WORD_SIZE_VARIABLE << ") + `" << TOP_TB_BITSTREAM_BL_WORD_SIZE_VARIABLE << " + " << TOP_TB_WL_SHIFT_REGISTER_COUNT_PORT_NAME;
|
||||||
|
fp << "];" << std::endl;
|
||||||
|
|
||||||
|
fp << "\t\t";
|
||||||
|
fp << TOP_TB_WL_SHIFT_REGISTER_COUNT_PORT_NAME << " = ";
|
||||||
|
fp << TOP_TB_WL_SHIFT_REGISTER_COUNT_PORT_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 */
|
/* Verilog codes to load bitstream from a bit file for memory bank using BL/WL decoders */
|
||||||
static
|
static
|
||||||
void print_verilog_full_testbench_ql_memory_bank_decoder_bitstream(std::fstream& fp,
|
void print_verilog_full_testbench_ql_memory_bank_decoder_bitstream(std::fstream& fp,
|
||||||
|
@ -445,6 +889,13 @@ void print_verilog_full_testbench_ql_memory_bank_bitstream(std::fstream& fp,
|
||||||
bit_value_to_skip,
|
bit_value_to_skip,
|
||||||
module_manager, top_module,
|
module_manager, top_module,
|
||||||
fabric_bitstream);
|
fabric_bitstream);
|
||||||
|
} else if ( (BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type())
|
||||||
|
&& (BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type()) ) {
|
||||||
|
print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(fp, bitstream_file,
|
||||||
|
fast_configuration,
|
||||||
|
bit_value_to_skip,
|
||||||
|
module_manager, top_module,
|
||||||
|
fabric_bitstream);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,27 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp,
|
||||||
const ModuleId& top_module,
|
const ModuleId& top_module,
|
||||||
const ConfigProtocol& config_protocol);
|
const ConfigProtocol& config_protocol);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate the Verilog codes that connect shift register clock stimuli to FPGA ports
|
||||||
|
*/
|
||||||
|
void print_verilog_top_testbench_global_shift_register_clock_ports_stimuli(std::fstream& fp,
|
||||||
|
const ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const FabricGlobalPortInfo& fabric_global_port_info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Generate the Verilog codes that generate stimuli waveforms for BL/WL protocols
|
||||||
|
*/
|
||||||
|
void print_verilog_top_testbench_configuration_protocol_ql_memory_bank_stimulus(std::fstream& fp,
|
||||||
|
const ConfigProtocol& config_protocol,
|
||||||
|
const ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const bool& fast_configuration,
|
||||||
|
const bool& bit_value_to_skip,
|
||||||
|
const FabricBitstream& fabric_bitstream,
|
||||||
|
const float& prog_clock_period,
|
||||||
|
const float& timescale);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Print stimulus for a FPGA fabric with a memory bank configuration protocol
|
* @brief Print stimulus for a FPGA fabric with a memory bank configuration protocol
|
||||||
* where configuration bits are programming in serial (one by one)
|
* where configuration bits are programming in serial (one by one)
|
||||||
|
|
|
@ -305,7 +305,7 @@ bool check_configurable_memory_circuit_model(const ConfigProtocol& config_protoc
|
||||||
num_err++;
|
num_err++;
|
||||||
}
|
}
|
||||||
if (bl_memory_model) {
|
if (bl_memory_model) {
|
||||||
num_err += check_ccff_circuit_model_ports(circuit_lib,
|
num_err += check_bl_ccff_circuit_model_ports(circuit_lib,
|
||||||
bl_memory_model);
|
bl_memory_model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +317,7 @@ bool check_configurable_memory_circuit_model(const ConfigProtocol& config_protoc
|
||||||
num_err++;
|
num_err++;
|
||||||
}
|
}
|
||||||
if (wl_memory_model) {
|
if (wl_memory_model) {
|
||||||
num_err += check_ccff_circuit_model_ports(circuit_lib,
|
num_err += check_wl_ccff_circuit_model_ports(circuit_lib,
|
||||||
wl_memory_model);
|
wl_memory_model);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -233,7 +233,29 @@ MemoryBankFabricBitstream build_memory_bank_fabric_bitstream_by_address(const Fa
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream,
|
MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream,
|
||||||
|
const bool& fast_configuration,
|
||||||
const bool& bit_value_to_skip) {
|
const bool& bit_value_to_skip) {
|
||||||
|
/* If fast configuration is not enabled, we need all the wl address even some of them have all-zero BLs */
|
||||||
|
if (!fast_configuration) {
|
||||||
|
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)) {
|
||||||
|
/* Create string for BL address */
|
||||||
|
std::string bl_addr_str(fabric_bitstream.bit_bl_address(bit_id).size(), bit_value_to_skip);
|
||||||
|
|
||||||
|
/* 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deposit the config bit */
|
||||||
|
fabric_bits_per_region[region][wl_addr_str] = bl_addr_str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Build the bitstream by each region, here we use (WL, BL) pairs when storing bitstreams */
|
/* 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;
|
vtr::vector<FabricBitRegionId, std::map<std::string, std::string>> fabric_bits_per_region;
|
||||||
fabric_bits_per_region.resize(fabric_bitstream.num_regions());
|
fabric_bits_per_region.resize(fabric_bitstream.num_regions());
|
||||||
|
@ -313,12 +335,98 @@ MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(cons
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/* Add the pair to std map */
|
/* Add the pair to std map */
|
||||||
fabric_bits[cur_wl_vectors] = cur_bl_vectors;
|
fabric_bits.add_blwl_vectors(cur_bl_vectors, cur_wl_vectors);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fabric_bits;
|
return fabric_bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* Reshape a list of vectors by aligning all of them to the last element
|
||||||
|
* For example:
|
||||||
|
* - Align vectors to the last element
|
||||||
|
*
|
||||||
|
* index ---------------------->
|
||||||
|
* vector 0: 000000001111101010
|
||||||
|
* vector 1: 00000011010101
|
||||||
|
* vector 2: 0010101111000110
|
||||||
|
*
|
||||||
|
* - Fill void in each vector with desired bits (Here assume fill 'x'
|
||||||
|
* index ---------------------->
|
||||||
|
* vector 0: 000000001111101010
|
||||||
|
* vector 1: xxxx00000011010101
|
||||||
|
* vector 2: xx0010101111000110
|
||||||
|
*
|
||||||
|
* - Rotate the array by 90 degree
|
||||||
|
* index ----------------------->
|
||||||
|
* vector 0: 0xx
|
||||||
|
* vector 1: 0xx
|
||||||
|
* ...
|
||||||
|
* vector N: 010
|
||||||
|
*
|
||||||
|
*******************************************************************/
|
||||||
|
static
|
||||||
|
std::vector<std::string> reshape_bitstream_vectors_to_first_element(const std::vector<std::string>& bitstream_vectors,
|
||||||
|
const char& default_bit_to_fill) {
|
||||||
|
/* Find the max sizes of BL bits, this determines the size of shift register chain */
|
||||||
|
size_t max_vec_size = 0;
|
||||||
|
for (const auto& vec : bitstream_vectors) {
|
||||||
|
max_vec_size = std::max(max_vec_size, vec.size());
|
||||||
|
}
|
||||||
|
/* Reshape the BL vectors */
|
||||||
|
std::vector<std::string> reshaped_vectors(bitstream_vectors.size(), std::string());
|
||||||
|
size_t col_cnt = 0;
|
||||||
|
for (const auto& vec : bitstream_vectors) {
|
||||||
|
reshaped_vectors[col_cnt] += vec;
|
||||||
|
reshaped_vectors[col_cnt] += std::string(max_vec_size - vec.size(), default_bit_to_fill);
|
||||||
|
col_cnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Add the BL word to final bitstream */
|
||||||
|
std::vector<std::string> rotated_vectors;
|
||||||
|
for (size_t irow = 0; irow < max_vec_size; ++irow) {
|
||||||
|
std::string cur_vec;
|
||||||
|
for (size_t icol = 0; icol < reshaped_vectors.size(); ++icol) {
|
||||||
|
cur_vec.push_back(reshaped_vectors[icol][irow]);
|
||||||
|
}
|
||||||
|
rotated_vectors.push_back(cur_vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rotated_vectors;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBankShiftRegisterFabricBitstream build_memory_bank_shift_register_fabric_bitstream(const FabricBitstream& fabric_bitstream,
|
||||||
|
const bool& fast_configuration,
|
||||||
|
//const std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
|
||||||
|
const bool& bit_value_to_skip) {
|
||||||
|
MemoryBankFlattenFabricBitstream raw_fabric_bits = build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, fast_configuration, bit_value_to_skip);
|
||||||
|
MemoryBankShiftRegisterFabricBitstream fabric_bits;
|
||||||
|
|
||||||
|
/* Iterate over each word */
|
||||||
|
for (const auto& wl_vec : raw_fabric_bits.wl_vectors()) {
|
||||||
|
std::vector<std::string> bl_vec = raw_fabric_bits.bl_vector(wl_vec);
|
||||||
|
|
||||||
|
MemoryBankShiftRegisterFabricBitstreamWordId word_id = fabric_bits.create_word();
|
||||||
|
|
||||||
|
std::vector<std::string> reshaped_bl_vectors = reshape_bitstream_vectors_to_first_element(bl_vec, '0');
|
||||||
|
/* Reverse the vectors due to the shift register chain nature: first-in first-out */
|
||||||
|
std::reverse(reshaped_bl_vectors.begin(), reshaped_bl_vectors.end());
|
||||||
|
/* Add the BL word to final bitstream */
|
||||||
|
for (const auto& reshaped_bl_vec : reshaped_bl_vectors) {
|
||||||
|
fabric_bits.add_bl_vectors(word_id, reshaped_bl_vec);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> reshaped_wl_vectors = reshape_bitstream_vectors_to_first_element(wl_vec, '0');
|
||||||
|
/* Reverse the vectors due to the shift register chain nature: first-in first-out */
|
||||||
|
std::reverse(reshaped_wl_vectors.begin(), reshaped_wl_vectors.end());
|
||||||
|
/* Add the BL word to final bitstream */
|
||||||
|
for (const auto& reshaped_wl_vec : reshaped_wl_vectors) {
|
||||||
|
fabric_bits.add_wl_vectors(word_id, reshaped_wl_vec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fabric_bits;
|
||||||
|
}
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* For fast configuration, the number of bits to be skipped
|
* For fast configuration, the number of bits to be skipped
|
||||||
|
|
|
@ -9,7 +9,11 @@
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <array>
|
||||||
#include "bitstream_manager.h"
|
#include "bitstream_manager.h"
|
||||||
|
#include "memory_bank_flatten_fabric_bitstream.h"
|
||||||
|
#include "memory_bank_shift_register_banks.h"
|
||||||
|
#include "memory_bank_shift_register_fabric_bitstream.h"
|
||||||
#include "fabric_bitstream.h"
|
#include "fabric_bitstream.h"
|
||||||
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
|
@ -37,12 +41,8 @@ FrameFabricBitstream build_frame_based_fabric_bitstream_by_address(const FabricB
|
||||||
size_t find_frame_based_fast_configuration_fabric_bitstream_size(const FabricBitstream& fabric_bitstream,
|
size_t find_frame_based_fast_configuration_fabric_bitstream_size(const FabricBitstream& fabric_bitstream,
|
||||||
const bool& bit_value_to_skip);
|
const bool& bit_value_to_skip);
|
||||||
|
|
||||||
/* Must use (WL, BL) as pairs in the map!!!
|
|
||||||
* This is because BL data may not be unique while WL must be unique
|
|
||||||
*/
|
|
||||||
typedef std::map<std::vector<std::string>, std::vector<std::string>> MemoryBankFlattenFabricBitstream;
|
|
||||||
/********************************************************************
|
/********************************************************************
|
||||||
* @ brief Reorganize the fabric bitstream for memory banks which use flatten or shift register to manipulate BL and WLs
|
* @ brief Reorganize the fabric bitstream for memory banks which use flatten BL and WLs
|
||||||
* For each configuration region, we will merge BL address (which are 1-hot codes) under the same WL address
|
* For each configuration region, we will merge BL address (which are 1-hot codes) under the same WL address
|
||||||
*
|
*
|
||||||
* Quick Example
|
* Quick Example
|
||||||
|
@ -62,6 +62,40 @@ typedef std::map<std::vector<std::string>, std::vector<std::string>> MemoryBankF
|
||||||
* @note the std::map may cause large memory footprint for large bitstream databases!
|
* @note the std::map may cause large memory footprint for large bitstream databases!
|
||||||
*******************************************************************/
|
*******************************************************************/
|
||||||
MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream,
|
MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream,
|
||||||
|
const bool& fast_configuration,
|
||||||
|
const bool& bit_value_to_skip);
|
||||||
|
|
||||||
|
/********************************************************************
|
||||||
|
* @ brief Reorganize the fabric bitstream for memory banks which use 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
|
||||||
|
*
|
||||||
|
* Because that the BL/WL are loaded through shift registers (perhaps using multiple heads), the bitstream will be reorganized as
|
||||||
|
* Considering single head:
|
||||||
|
*
|
||||||
|
* <bl of region A>_<bl of region B> <wl of region A>_<wl of region B>
|
||||||
|
* 1_1 0_0
|
||||||
|
* 0_1 0_0
|
||||||
|
* 1_0 0_0
|
||||||
|
*
|
||||||
|
* @note the std::map may cause large memory footprint for large bitstream databases!
|
||||||
|
*******************************************************************/
|
||||||
|
MemoryBankShiftRegisterFabricBitstream build_memory_bank_shift_register_fabric_bitstream(const FabricBitstream& fabric_bitstream,
|
||||||
|
const bool& fast_configuration,
|
||||||
|
//const std::array<MemoryBankShiftRegisterBanks, 2>& blwl_sr_banks,
|
||||||
const bool& bit_value_to_skip);
|
const bool& bit_value_to_skip);
|
||||||
|
|
||||||
/* Alias to a specific organization of bitstreams for memory bank configuration protocol */
|
/* Alias to a specific organization of bitstreams for memory bank configuration protocol */
|
||||||
|
|
|
@ -84,6 +84,21 @@ size_t find_module_ql_memory_bank_num_blwls(const ModuleManager& module_manager,
|
||||||
return num_blwls;
|
return num_blwls;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t compute_memory_bank_regional_num_bls(const ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const ConfigRegionId& config_region,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitModelId& sram_model) {
|
||||||
|
size_t num_bls = 0;
|
||||||
|
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);
|
||||||
|
for (const auto& pair : num_bls_per_tile) {
|
||||||
|
num_bls += pair.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_bls;
|
||||||
|
}
|
||||||
|
|
||||||
std::map<int, size_t> compute_memory_bank_regional_bitline_numbers_per_tile(const ModuleManager& module_manager,
|
std::map<int, size_t> compute_memory_bank_regional_bitline_numbers_per_tile(const ModuleManager& module_manager,
|
||||||
const ModuleId& top_module,
|
const ModuleId& top_module,
|
||||||
const ConfigRegionId& config_region,
|
const ConfigRegionId& config_region,
|
||||||
|
@ -100,6 +115,22 @@ std::map<int, size_t> compute_memory_bank_regional_bitline_numbers_per_tile(cons
|
||||||
return num_bls_per_tile;
|
return num_bls_per_tile;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t compute_memory_bank_regional_num_wls(const ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const ConfigRegionId& config_region,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitModelId& sram_model) {
|
||||||
|
size_t num_wls = 0;
|
||||||
|
|
||||||
|
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);
|
||||||
|
for (const auto& pair : num_wls_per_tile) {
|
||||||
|
num_wls += pair.second;
|
||||||
|
}
|
||||||
|
|
||||||
|
return num_wls;
|
||||||
|
}
|
||||||
|
|
||||||
std::map<int, size_t> compute_memory_bank_regional_wordline_numbers_per_tile(const ModuleManager& module_manager,
|
std::map<int, size_t> compute_memory_bank_regional_wordline_numbers_per_tile(const ModuleManager& module_manager,
|
||||||
const ModuleId& top_module,
|
const ModuleId& top_module,
|
||||||
const ConfigRegionId& config_region,
|
const ConfigRegionId& config_region,
|
||||||
|
|
|
@ -48,6 +48,14 @@ size_t find_module_ql_memory_bank_num_blwls(const ModuleManager& module_manager,
|
||||||
const CircuitModelId& sram_model,
|
const CircuitModelId& sram_model,
|
||||||
const e_config_protocol_type& sram_orgz_type,
|
const e_config_protocol_type& sram_orgz_type,
|
||||||
const e_circuit_model_port_type& circuit_port_type);
|
const e_circuit_model_port_type& circuit_port_type);
|
||||||
|
/**
|
||||||
|
* @brief Precompute the total number of bit lines required by a specific configuration region
|
||||||
|
*/
|
||||||
|
size_t compute_memory_bank_regional_num_bls(const ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const ConfigRegionId& config_region,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitModelId& sram_model);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Precompute the number of bit lines required by each tile under a specific configuration region
|
* @brief Precompute the number of bit lines required by each tile under a specific configuration region
|
||||||
|
@ -60,6 +68,15 @@ std::map<int, size_t> compute_memory_bank_regional_bitline_numbers_per_tile(cons
|
||||||
const ConfigRegionId& config_region,
|
const ConfigRegionId& config_region,
|
||||||
const CircuitLibrary& circuit_lib,
|
const CircuitLibrary& circuit_lib,
|
||||||
const CircuitModelId& sram_model);
|
const CircuitModelId& sram_model);
|
||||||
|
/**
|
||||||
|
* @brief Precompute the total number of word lines required by a specific configuration region
|
||||||
|
*/
|
||||||
|
size_t compute_memory_bank_regional_num_wls(const ModuleManager& module_manager,
|
||||||
|
const ModuleId& top_module,
|
||||||
|
const ConfigRegionId& config_region,
|
||||||
|
const CircuitLibrary& circuit_lib,
|
||||||
|
const CircuitModelId& sram_model);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Precompute the number of word lines required by each tile under a specific configuration region
|
* @brief Precompute the number of word lines required by each tile under a specific configuration region
|
||||||
* @note
|
* @note
|
||||||
|
|
|
@ -447,11 +447,15 @@ size_t estimate_num_configurable_children_to_skip_by_config_protocol(const Confi
|
||||||
|| CONFIG_MEM_QL_MEMORY_BANK == config_protocol.type()) {
|
|| CONFIG_MEM_QL_MEMORY_BANK == config_protocol.type()) {
|
||||||
VTR_ASSERT(2 <= curr_region_num_config_child);
|
VTR_ASSERT(2 <= curr_region_num_config_child);
|
||||||
num_child_to_skip = 2;
|
num_child_to_skip = 2;
|
||||||
/* If flatten bus is used, BL/WL may not need decoders */
|
/* - If flatten bus is used, BL/WL may not need decoders
|
||||||
if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) {
|
* - If shift registers are used, BL/WLs do not need decoders. And shift registers are not counted as configurable children
|
||||||
|
*/
|
||||||
|
if ( BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()
|
||||||
|
|| BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type() ) {
|
||||||
num_child_to_skip--;
|
num_child_to_skip--;
|
||||||
}
|
}
|
||||||
if (BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()) {
|
if ( BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()
|
||||||
|
|| BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type() ) {
|
||||||
num_child_to_skip--;
|
num_child_to_skip--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -165,21 +165,33 @@
|
||||||
<port type="output" prefix="inpad" lib_name="Y" size="1"/>
|
<port type="output" prefix="inpad" lib_name="Y" size="1"/>
|
||||||
</circuit_model>
|
</circuit_model>
|
||||||
<!-- The following flip-flop is used to build the shift register chains for configuring memory banks -->
|
<!-- 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">
|
<circuit_model type="ccff" name="BL_DFFRQ" prefix="BL_DFFRQ" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/spice/dff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/dff.v" is_default="true">
|
||||||
<design_technology type="cmos"/>
|
<design_technology type="cmos"/>
|
||||||
<input_buffer exist="true" circuit_model_name="INVTX1"/>
|
<input_buffer exist="true" circuit_model_name="INVTX1"/>
|
||||||
<output_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="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="input" prefix="D" lib_name="SIN" size="1"/>
|
||||||
<port type="output" prefix="Q" size="1"/>
|
<port type="output" prefix="Q" lib_name="SOUT" size="1"/>
|
||||||
<port type="output" prefix="QN" size="1"/>
|
<port type="bl" prefix="BL" lib_name="BL" size="1"/>
|
||||||
<port type="clock" prefix="sr_clk" lib_name="CK" size="1" is_global="true" default_val="0" is_prog="true"/>
|
<port type="clock" prefix="bl_sr_clk" lib_name="CK" size="1" is_global="true" default_val="0" is_prog="true" is_shift_register="true"/>
|
||||||
|
</circuit_model>
|
||||||
|
<!-- The following flip-flop is used to build the shift register chains for configuring memory banks -->
|
||||||
|
<circuit_model type="ccff" name="WL_DFFRQ" prefix="WL_DFFRQ" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/spice/dff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/dff.v">
|
||||||
|
<design_technology type="cmos"/>
|
||||||
|
<input_buffer exist="true" circuit_model_name="INVTX1"/>
|
||||||
|
<output_buffer exist="true" circuit_model_name="INVTX1"/>
|
||||||
|
<port type="input" prefix="srReset" lib_name="RST" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true"/>
|
||||||
|
<port type="input" prefix="D" lib_name="SIN" size="1"/>
|
||||||
|
<port type="output" prefix="Q" lib_name="SOUT" size="1"/>
|
||||||
|
<port type="wl" prefix="wl" lib_name="WLW" size="1"/>
|
||||||
|
<port type="clock" prefix="wl_en" lib_name="WEN" size="1" is_global="true" default_val="0" is_prog="true"/>
|
||||||
|
<port type="clock" prefix="wl_sr_clk" lib_name="CK" size="1" is_global="true" default_val="0" is_prog="true" is_shift_register="true"/>
|
||||||
</circuit_model>
|
</circuit_model>
|
||||||
</circuit_library>
|
</circuit_library>
|
||||||
<configuration_protocol>
|
<configuration_protocol>
|
||||||
<organization type="ql_memory_bank" circuit_model_name="SRAM">
|
<organization type="ql_memory_bank" circuit_model_name="SRAM">
|
||||||
<bl protocol="shift_register" circuit_model_name="DFFR"/>
|
<bl protocol="shift_register" circuit_model_name="BL_DFFRQ"/>
|
||||||
<wl protocol="shift_register" circuit_model_name="DFFR"/>
|
<wl protocol="shift_register" circuit_model_name="WL_DFFRQ"/>
|
||||||
</organization>
|
</organization>
|
||||||
</configuration_protocol>
|
</configuration_protocol>
|
||||||
<connection_block>
|
<connection_block>
|
||||||
|
|
|
@ -0,0 +1,226 @@
|
||||||
|
<!-- 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_RE" prefix="SRAM_RE" 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="wlr" prefix="wlr" lib_name="RE" 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_RE" default_val="1"/>
|
||||||
|
<port type="input" prefix="outpad" lib_name="A" size="1"/>
|
||||||
|
<port type="output" prefix="inpad" lib_name="Y" size="1"/>
|
||||||
|
</circuit_model>
|
||||||
|
<!-- The following flip-flop is used to build the shift register chains for configuring memory banks -->
|
||||||
|
<circuit_model type="ccff" name="BL_DFFRQ" prefix="BL_DFFRQ" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/spice/dff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/dff.v">
|
||||||
|
<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" is_shift_register="true"/>
|
||||||
|
<port type="input" prefix="D" lib_name="SIN" size="1"/>
|
||||||
|
<port type="output" prefix="Q" lib_name="SOUT" size="1"/>
|
||||||
|
<port type="bl" prefix="BL" lib_name="BL" size="1"/>
|
||||||
|
<port type="clock" prefix="bl_sr_clk" lib_name="CK" size="1" is_global="true" default_val="0" is_prog="true" is_shift_register="true"/>
|
||||||
|
</circuit_model>
|
||||||
|
<!-- The following flip-flop is used to build the shift register chains for configuring memory banks -->
|
||||||
|
<circuit_model type="ccff" name="WLR_DFFRQ" prefix="WLR_DFFRQ" spice_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/spice/dff.sp" verilog_netlist="${OPENFPGA_PATH}/openfpga_flow/openfpga_cell_library/verilog/dff.v">
|
||||||
|
<design_technology type="cmos"/>
|
||||||
|
<input_buffer exist="true" circuit_model_name="INVTX1"/>
|
||||||
|
<output_buffer exist="true" circuit_model_name="INVTX1"/>
|
||||||
|
<port type="input" prefix="srReset" lib_name="RST" size="1" is_global="true" default_val="0" is_reset="true" is_prog="true" is_shift_register="true"/>
|
||||||
|
<port type="input" prefix="D" lib_name="SIN" size="1"/>
|
||||||
|
<port type="output" prefix="Q" lib_name="SOUT" size="1"/>
|
||||||
|
<port type="wl" prefix="wl" lib_name="WLW" size="1"/>
|
||||||
|
<port type="wlr" prefix="wlr" lib_name="WLR" size="1"/>
|
||||||
|
<port type="clock" prefix="wl_en" lib_name="WEN" size="1" is_global="true" default_val="0" is_prog="true"/>
|
||||||
|
<port type="clock" prefix="wl_sr_clk" lib_name="CK" size="1" is_global="true" default_val="0" is_prog="true" is_shift_register="true"/>
|
||||||
|
</circuit_model>
|
||||||
|
</circuit_library>
|
||||||
|
<configuration_protocol>
|
||||||
|
<organization type="ql_memory_bank" circuit_model_name="SRAM_RE">
|
||||||
|
<bl protocol="shift_register" circuit_model_name="BL_DFFRQ"/>
|
||||||
|
<wl protocol="shift_register" circuit_model_name="WLR_DFFRQ"/>
|
||||||
|
</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>
|
|
@ -437,3 +437,91 @@ assign Q = q_reg;
|
||||||
assign QN = !Q;
|
assign QN = !Q;
|
||||||
|
|
||||||
endmodule //End Of Module
|
endmodule //End Of Module
|
||||||
|
|
||||||
|
//-----------------------------------------------------
|
||||||
|
// Function : D-type flip-flop with
|
||||||
|
// - asynchronous active high reset
|
||||||
|
// @note This DFF is designed to drive BLs when shift registers are used
|
||||||
|
//-----------------------------------------------------
|
||||||
|
module BL_DFFRQ (
|
||||||
|
input RST, // Reset input
|
||||||
|
input CK, // Clock Input
|
||||||
|
input SIN, // Data Input
|
||||||
|
output SOUT, // Q output
|
||||||
|
output BL // BL output
|
||||||
|
);
|
||||||
|
//------------Internal Variables--------
|
||||||
|
reg q_reg;
|
||||||
|
|
||||||
|
//-------------Code Starts Here---------
|
||||||
|
always @ ( posedge CK or posedge RST)
|
||||||
|
if (RST) begin
|
||||||
|
q_reg <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
q_reg <= SIN;
|
||||||
|
end
|
||||||
|
|
||||||
|
assign SOUT = q_reg;
|
||||||
|
assign BL = q_reg;
|
||||||
|
|
||||||
|
endmodule //End Of Module
|
||||||
|
|
||||||
|
//-----------------------------------------------------
|
||||||
|
// Function : D-type flip-flop with
|
||||||
|
// - asynchronous active high reset
|
||||||
|
// @note This DFF is designed to drive WLs when shift registers are used
|
||||||
|
//-----------------------------------------------------
|
||||||
|
module WL_DFFRQ (
|
||||||
|
input RST, // Reset input
|
||||||
|
input CK, // Clock Input
|
||||||
|
input SIN, // Data Input
|
||||||
|
input WEN, // Write-enable
|
||||||
|
output SOUT, // Q output
|
||||||
|
output WLW // Drive WL write signals
|
||||||
|
);
|
||||||
|
//------------Internal Variables--------
|
||||||
|
reg q_reg;
|
||||||
|
|
||||||
|
//-------------Code Starts Here---------
|
||||||
|
always @ ( posedge CK or posedge RST)
|
||||||
|
if (RST) begin
|
||||||
|
q_reg <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
q_reg <= SIN;
|
||||||
|
end
|
||||||
|
|
||||||
|
assign SOUT = q_reg;
|
||||||
|
assign WLW = WEN ? q_reg : 1'b0;
|
||||||
|
|
||||||
|
endmodule //End Of Module
|
||||||
|
|
||||||
|
//-----------------------------------------------------
|
||||||
|
// Function : D-type flip-flop with
|
||||||
|
// - asynchronous active high reset
|
||||||
|
// @note This DFF is designed to drive WLs and WLRs when shift registers are used
|
||||||
|
//-----------------------------------------------------
|
||||||
|
module WLR_DFFRQ (
|
||||||
|
input RST, // Reset input
|
||||||
|
input CK, // Clock Input
|
||||||
|
input SIN, // Data Input
|
||||||
|
input WEN, // Write-enable
|
||||||
|
output SOUT, // Q output
|
||||||
|
output WLW, // Drive WL write signals
|
||||||
|
output WLR // Drive WL read signals
|
||||||
|
);
|
||||||
|
//------------Internal Variables--------
|
||||||
|
reg q_reg;
|
||||||
|
|
||||||
|
//-------------Code Starts Here---------
|
||||||
|
always @ ( posedge CK or posedge RST)
|
||||||
|
if (RST) begin
|
||||||
|
q_reg <= 1'b0;
|
||||||
|
end else begin
|
||||||
|
q_reg <= SIN;
|
||||||
|
end
|
||||||
|
|
||||||
|
assign SOUT = q_reg;
|
||||||
|
assign WLW = WEN ? q_reg : 1'b0;
|
||||||
|
assign WLR = 1'b0; // Use a constant output just for simple testing
|
||||||
|
|
||||||
|
endmodule //End Of Module
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
<!-- Simulation Setting for OpenFPGA framework
|
||||||
|
This file will use automatic inference for any settings
|
||||||
|
including:
|
||||||
|
- auto select the number of simulation cycles
|
||||||
|
- auto select the simulation clock frequency from VPR results
|
||||||
|
-->
|
||||||
|
<openfpga_simulation_setting>
|
||||||
|
<clock_setting>
|
||||||
|
<operating frequency="auto" num_cycles="auto" slack="0.2"/>
|
||||||
|
<programming frequency="100e6">
|
||||||
|
<clock name="bl_shift_register_clk" port="bl_sr_clk[0:0]" frequency="auto" is_shift_register="true"/>
|
||||||
|
<clock name="wl_shift_register_clk" port="wl_sr_clk[0:0]" frequency="auto" is_shift_register="true"/>
|
||||||
|
</programming>
|
||||||
|
</clock_setting>
|
||||||
|
<simulator_option>
|
||||||
|
<operating_condition temperature="25"/>
|
||||||
|
<output_log verbose="false" captab="false"/>
|
||||||
|
<accuracy type="abs" value="1e-13"/>
|
||||||
|
<runtime fast_simulation="true"/>
|
||||||
|
</simulator_option>
|
||||||
|
<monte_carlo num_simulation_points="2"/>
|
||||||
|
<measurement_setting>
|
||||||
|
<slew>
|
||||||
|
<rise upper_thres_pct="0.95" lower_thres_pct="0.05"/>
|
||||||
|
<fall upper_thres_pct="0.05" lower_thres_pct="0.95"/>
|
||||||
|
</slew>
|
||||||
|
<delay>
|
||||||
|
<rise input_thres_pct="0.5" output_thres_pct="0.5"/>
|
||||||
|
<fall input_thres_pct="0.5" output_thres_pct="0.5"/>
|
||||||
|
</delay>
|
||||||
|
</measurement_setting>
|
||||||
|
<stimulus>
|
||||||
|
<clock>
|
||||||
|
<rise slew_type="abs" slew_time="20e-12" />
|
||||||
|
<fall slew_type="abs" slew_time="20e-12" />
|
||||||
|
</clock>
|
||||||
|
<input>
|
||||||
|
<rise slew_type="abs" slew_time="25e-12" />
|
||||||
|
<fall slew_type="abs" slew_time="25e-12" />
|
||||||
|
</input>
|
||||||
|
</stimulus>
|
||||||
|
</openfpga_simulation_setting>
|
|
@ -59,6 +59,7 @@ run-task basic_tests/full_testbench/ql_memory_bank_use_wlr --debug --show_thread
|
||||||
run-task basic_tests/full_testbench/multi_region_ql_memory_bank --debug --show_thread_logs
|
run-task basic_tests/full_testbench/multi_region_ql_memory_bank --debug --show_thread_logs
|
||||||
run-task basic_tests/full_testbench/ql_memory_bank_flatten --debug --show_thread_logs
|
run-task basic_tests/full_testbench/ql_memory_bank_flatten --debug --show_thread_logs
|
||||||
run-task basic_tests/full_testbench/ql_memory_bank_flatten_use_wlr --debug --show_thread_logs
|
run-task basic_tests/full_testbench/ql_memory_bank_flatten_use_wlr --debug --show_thread_logs
|
||||||
|
run-task basic_tests/full_testbench/ql_memory_bank_shift_register --debug --show_thread_logs
|
||||||
|
|
||||||
echo -e "Testing testbenches without self checking features";
|
echo -e "Testing testbenches without self checking features";
|
||||||
run-task basic_tests/full_testbench/full_testbench_without_self_checking --debug --show_thread_logs
|
run-task basic_tests/full_testbench/full_testbench_without_self_checking --debug --show_thread_logs
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
# Configuration file for running experiments
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs
|
||||||
|
# Each job execute fpga_flow script on combination of architecture & benchmark
|
||||||
|
# timeout_each_job is timeout for each job
|
||||||
|
# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
|
||||||
|
|
||||||
|
[GENERAL]
|
||||||
|
run_engine=openfpga_shell
|
||||||
|
power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml
|
||||||
|
power_analysis = true
|
||||||
|
spice_output=false
|
||||||
|
verilog_output=true
|
||||||
|
timeout_each_job = 20*60
|
||||||
|
fpga_flow=yosys_vpr
|
||||||
|
|
||||||
|
[OpenFPGA_SHELL]
|
||||||
|
openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/write_full_testbench_example_script.openfpga
|
||||||
|
openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml
|
||||||
|
openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_shift_register_sim_openfpga.xml
|
||||||
|
|
||||||
|
openfpga_vpr_device_layout=
|
||||||
|
openfpga_fast_configuration=
|
||||||
|
|
||||||
|
[ARCHITECTURES]
|
||||||
|
arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml
|
||||||
|
|
||||||
|
[BENCHMARKS]
|
||||||
|
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
|
||||||
|
bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/or2/or2.v
|
||||||
|
bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch/and2_latch.v
|
||||||
|
|
||||||
|
[SYNTHESIS_PARAM]
|
||||||
|
bench0_top = and2
|
||||||
|
bench0_chan_width = 300
|
||||||
|
|
||||||
|
bench1_top = or2
|
||||||
|
bench1_chan_width = 300
|
||||||
|
|
||||||
|
bench2_top = and2_latch
|
||||||
|
bench2_chan_width = 300
|
||||||
|
|
||||||
|
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
|
||||||
|
end_flow_with_test=
|
Loading…
Reference in New Issue