From 6469ee30488e9947efe07466d1d370f3f1a7876e Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 28 Sep 2021 12:21:54 -0700 Subject: [PATCH 01/52] [HDL] Update DFF modules by adding custom cells required by shift registers in BL/WLs --- .../openfpga_cell_library/verilog/dff.v | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/openfpga_flow/openfpga_cell_library/verilog/dff.v b/openfpga_flow/openfpga_cell_library/verilog/dff.v index 2eb5765c9..35bea1ec8 100644 --- a/openfpga_flow/openfpga_cell_library/verilog/dff.v +++ b/openfpga_flow/openfpga_cell_library/verilog/dff.v @@ -437,3 +437,61 @@ assign Q = q_reg; assign QN = !Q; 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 + 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 = q_reg; +assign WLR = 1'b0; // Use a constant output just for simple testing + +endmodule //End Of Module From 2ce2fb269ae88294d7e1b0c5e8399e0d00cf4b02 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 28 Sep 2021 12:35:13 -0700 Subject: [PATCH 02/52] [HDL] Added a different FF model which is designed to drive WLW only --- .../openfpga_cell_library/verilog/dff.v | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/openfpga_flow/openfpga_cell_library/verilog/dff.v b/openfpga_flow/openfpga_cell_library/verilog/dff.v index 35bea1ec8..da641d785 100644 --- a/openfpga_flow/openfpga_cell_library/verilog/dff.v +++ b/openfpga_flow/openfpga_cell_library/verilog/dff.v @@ -472,6 +472,34 @@ endmodule //End Of Module // @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 + 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 = q_reg; + +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 From 4c04c0fbd7a00a827a3f677df6e87e0bff3d50e3 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 28 Sep 2021 12:35:42 -0700 Subject: [PATCH 03/52] [Arch] Reworked the example architecture for QL memory bank using shift register by using the latest HDL models --- .../k4_N4_40nm_qlbanksr_openfpga.xml | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml index 3e04af1c3..c07af9a10 100644 --- a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml +++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml @@ -165,21 +165,32 @@ - + - - - + + + + + + + + + + + + + + - - + + From 80232fc4590687e925ba24fc71aacf0adc574532 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 28 Sep 2021 12:36:36 -0700 Subject: [PATCH 04/52] [Arch] Add a new example architecture for QL memory bank using WLR in shift registers --- .../k4_N4_40nm_qlbanksr_wlr_openfpga.xml | 225 ++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_wlr_openfpga.xml diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_wlr_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_wlr_openfpga.xml new file mode 100644 index 000000000..9c8e0964c --- /dev/null +++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_wlr_openfpga.xml @@ -0,0 +1,225 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + + 10e-12 + + + 10e-12 + + + + + + + + + + + + + 10e-12 5e-12 5e-12 + + + 10e-12 5e-12 5e-12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 0a2979d61652439b84d38cf43716ab89e3c1b817 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 28 Sep 2021 14:20:35 -0700 Subject: [PATCH 05/52] [Engine] Update readarchopenfpga library by adding new syntax ``num_banks`` as well as update arch writer for BL/WL protocols --- .../libarchopenfpga/src/config_protocol.cpp | 26 +++++++++++++++++++ .../libarchopenfpga/src/config_protocol.h | 10 ++++++- .../src/read_xml_config_protocol.cpp | 12 +++++++-- .../src/write_xml_config_protocol.cpp | 17 ++++++++++-- 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/libopenfpga/libarchopenfpga/src/config_protocol.cpp b/libopenfpga/libarchopenfpga/src/config_protocol.cpp index 948046493..a5aa748e8 100644 --- a/libopenfpga/libarchopenfpga/src/config_protocol.cpp +++ b/libopenfpga/libarchopenfpga/src/config_protocol.cpp @@ -45,6 +45,10 @@ CircuitModelId ConfigProtocol::bl_memory_model() const { return bl_memory_model_; } +size_t ConfigProtocol::bl_num_banks() const { + return bl_num_banks_; +} + e_blwl_protocol_type ConfigProtocol::wl_protocol_type() const { return wl_protocol_type_; } @@ -57,6 +61,10 @@ CircuitModelId ConfigProtocol::wl_memory_model() const { return wl_memory_model_; } +size_t ConfigProtocol::wl_num_banks() const { + return wl_num_banks_; +} + /************************************************************************ * Public Mutators ***********************************************************************/ @@ -100,6 +108,15 @@ void ConfigProtocol::set_bl_memory_model(const CircuitModelId& 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) { 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_]); @@ -123,3 +140,12 @@ void ConfigProtocol::set_wl_memory_model(const CircuitModelId& 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; +} + diff --git a/libopenfpga/libarchopenfpga/src/config_protocol.h b/libopenfpga/libarchopenfpga/src/config_protocol.h index 24de1ff47..79bda1a46 100644 --- a/libopenfpga/libarchopenfpga/src/config_protocol.h +++ b/libopenfpga/libarchopenfpga/src/config_protocol.h @@ -29,9 +29,11 @@ class ConfigProtocol { e_blwl_protocol_type bl_protocol_type() const; std::string bl_memory_model_name() const; CircuitModelId bl_memory_model() const; + size_t bl_num_banks() const; e_blwl_protocol_type wl_protocol_type() const; std::string wl_memory_model_name() const; CircuitModelId wl_memory_model() const; + size_t wl_num_banks() const; public: /* Public Mutators */ void set_type(const e_config_protocol_type& type); 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_memory_model_name(const std::string& memory_model_name); 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_memory_model_name(const std::string& memory_model_name); void set_wl_memory_model(const CircuitModelId& memory_model); + void set_wl_num_banks(const size_t& num_banks); private: /* Internal data */ /* The type of configuration protocol. * In other words, it is about how to organize and access each configurable memory @@ -58,17 +62,21 @@ class ConfigProtocol { int num_regions_; /* BL & WL protocol: This is only applicable to memory-bank configuration protocols - * - type: defines which protocol to be used. By default, we consider decoders + * - type: defines which protocol to be used. By default, we consider decoders * - bl/wl_memory_model: defines the circuit model to be used when building shift register chains for BL/WL configuration. * It must be a valid CCFF circuit model. This is only applicable when shift-register protocol is selected * for BL or WL. + * - 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; std::string bl_memory_model_name_; CircuitModelId bl_memory_model_; + size_t bl_num_banks_; e_blwl_protocol_type wl_protocol_type_ = BLWL_PROTOCOL_DECODER; std::string wl_memory_model_name_; CircuitModelId wl_memory_model_; + size_t wl_num_banks_; }; #endif diff --git a/libopenfpga/libarchopenfpga/src/read_xml_config_protocol.cpp b/libopenfpga/libarchopenfpga/src/read_xml_config_protocol.cpp index ebfe64782..c84bbe93b 100644 --- a/libopenfpga/libarchopenfpga/src/read_xml_config_protocol.cpp +++ b/libopenfpga/libarchopenfpga/src/read_xml_config_protocol.cpp @@ -68,9 +68,13 @@ void read_xml_bl_protocol(pugi::xml_node& xml_bl_protocol, 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) { 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).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); - /* 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) { 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).as_int(1)); } } diff --git a/libopenfpga/libarchopenfpga/src/write_xml_config_protocol.cpp b/libopenfpga/libarchopenfpga/src/write_xml_config_protocol.cpp index 0f202bf04..7801049a3 100644 --- a/libopenfpga/libarchopenfpga/src/write_xml_config_protocol.cpp +++ b/libopenfpga/libarchopenfpga/src/write_xml_config_protocol.cpp @@ -26,11 +26,24 @@ void write_xml_config_organization(std::fstream& fp, openfpga::check_file_stream(fname, fp); fp << "\t\t" << "" << "\n"; + + /* Output BL/WL protocols */ + fp << "\t\t\t" << "" << "\n"; + + fp << "\t\t\t" << "" << "\n"; + + fp << "\t" << "" << "\n"; } /******************************************************************** From afd03d7eb7b9fc8d23ddb124f21dac4696cb90ba Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 28 Sep 2021 15:56:07 -0700 Subject: [PATCH 06/52] [Engine] Add more check codes for the CCFF circuit model used by BL/WL shift registers --- .../src/check_circuit_library.cpp | 96 +++++++++++++++++++ .../src/check_circuit_library.h | 6 ++ openfpga/src/utils/circuit_library_utils.cpp | 8 +- 3 files changed, 106 insertions(+), 4 deletions(-) diff --git a/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp b/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp index 689d1af6f..1a7eb60ed 100644 --- a/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp +++ b/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp @@ -326,6 +326,102 @@ size_t check_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib, 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 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 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 ***********************************************************************/ diff --git a/libopenfpga/libarchopenfpga/src/check_circuit_library.h b/libopenfpga/libarchopenfpga/src/check_circuit_library.h index a6690f60c..3d196d7c9 100644 --- a/libopenfpga/libarchopenfpga/src/check_circuit_library.h +++ b/libopenfpga/libarchopenfpga/src/check_circuit_library.h @@ -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, 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, const CircuitModelId& circuit_model, const bool& check_blwl); diff --git a/openfpga/src/utils/circuit_library_utils.cpp b/openfpga/src/utils/circuit_library_utils.cpp index bb59a0601..45eea879c 100644 --- a/openfpga/src/utils/circuit_library_utils.cpp +++ b/openfpga/src/utils/circuit_library_utils.cpp @@ -305,8 +305,8 @@ bool check_configurable_memory_circuit_model(const ConfigProtocol& config_protoc num_err++; } if (bl_memory_model) { - num_err += check_ccff_circuit_model_ports(circuit_lib, - bl_memory_model); + num_err += check_bl_ccff_circuit_model_ports(circuit_lib, + bl_memory_model); } /* Check circuit model for WL protocol */ @@ -317,8 +317,8 @@ bool check_configurable_memory_circuit_model(const ConfigProtocol& config_protoc num_err++; } if (wl_memory_model) { - num_err += check_ccff_circuit_model_ports(circuit_lib, - wl_memory_model); + num_err += check_wl_ccff_circuit_model_ports(circuit_lib, + wl_memory_model); } break; } From 834bdd2b0707847e082383792c56eb9a085b0669 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 28 Sep 2021 17:29:03 -0700 Subject: [PATCH 07/52] [Engine] Updating fabric generator to support BL/WL shift registers. Still WIP --- .../src/openfpga_reserved_words.h | 8 + .../fabric/build_top_module_memory_bank.cpp | 277 +++++++++++++++++- openfpga/src/utils/memory_bank_utils.cpp | 32 ++ openfpga/src/utils/memory_bank_utils.h | 17 ++ 4 files changed, 331 insertions(+), 3 deletions(-) diff --git a/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h b/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h index af151a7a5..4d51a8f12 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h +++ b/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h @@ -13,10 +13,18 @@ namespace openfpga { /* Top-level module name */ 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_OUT_NAME = "ccff_tail"; constexpr char* CONFIGURABLE_MEMORY_DATA_OUT_NAME = "mem_out"; 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 */ /* Prefix of global input, output and inout ports of FPGA fabric */ diff --git a/openfpga/src/fabric/build_top_module_memory_bank.cpp b/openfpga/src/fabric/build_top_module_memory_bank.cpp index 188efd2f4..d3711ba2a 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.cpp +++ b/openfpga/src/fabric/build_top_module_memory_bank.cpp @@ -30,6 +30,108 @@ /* begin namespace openfpga */ namespace openfpga { +/********************************************************************* + * 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 +void 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 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 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 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 (size_t iport = 0; iport < num_bl_ports; ++iport) { + CircuitPortId child_module_output_port = sram_bl_ports[iport]; + std::string chain_output_port_name = std::string(BL_SHIFT_REGISTER_CHAIN_BL_OUT_NAME); + std::vector output_nets = add_module_output_nets_to_chain_mem_modules(module_manager, mem_module, + chan_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_cmos_memory_config_chain_module(module_manager, mem_module, + circuit_lib, sram_input_ports[0], sram_output_ports[0]); + + /* If there is a second input defined, + * add nets to short wire the 2nd inputs to the first inputs + */ + if (2 == sram_input_ports.size()) { + add_module_nets_to_cmos_memory_scan_chain_module(module_manager, mem_module, + circuit_lib, sram_input_ports[1], sram_output_ports[0]); + } + + /* 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); +} + + /********************************************************************* * This function to add nets for quicklogic memory banks * Each configuration region has independent memory bank circuitry @@ -640,6 +742,161 @@ void add_top_module_nets_cmos_ql_memory_bank_bl_flatten_config_bus(ModuleManager } } +/********************************************************************* + * 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, + 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 */ + std::vector unique_sr_sizes; + for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { + /* TODO: Need to find how to cut the BLs when there are multiple banks for shift registers in a region */ + size_t num_bls = compute_memory_bank_regional_num_bls(module_manager, top_module, + config_region, + circuit_lib, sram_model); + unique_sr_sizes.push_back(num_bls); + } + + /* TODO: 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(bl_memory_model, sr_size); + // ModuleId sr_bank_module = build_bl_shift_register_chain_module(module_manager, + // circuit_lib, + // sr_module_name, + // bl_memory_model, + // sr_size); + //} + + /* TODO: Instanciate the shift register chains in the top-level module */ + //module_manager.add_child_module(top_module, sr_bank_module); + + /* TODO: create connections between top-level module and the BL shift register banks */ + + /* Create connections between BLs of top-level module and BLs of child modules for each region */ + for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { + /************************************************************** + * Precompute the BLs and WLs distribution across the FPGA fabric + * The distribution is a matrix which contains the starting index of BL/WL for each column or row + */ + std::pair child_x_range = compute_memory_bank_regional_configurable_child_x_range(module_manager, top_module, config_region); + std::map num_bls_per_tile = compute_memory_bank_regional_bitline_numbers_per_tile(module_manager, top_module, + config_region, + circuit_lib, sram_model); + std::map bl_start_index_per_tile = compute_memory_bank_regional_blwl_start_index_per_tile(child_x_range, num_bls_per_tile); + + /************************************************************** + * Add BL nets from top module to each configurable child + * BL pins of top module are connected to the BL input pins of each PB/CB/SB + * For all the PB/CB/SB in the same column, they share the same set of BLs + * A quick example + * + * BL[i .. i + sqrt(N)] + * | + * | CLB[1][H] + * | +---------+ + * | | SRAM | + * +-->| [0..N] | + * | +---------+ + * | + * ... + * | CLB[1][1] + * | +---------+ + * | | SRAM | + * +-->| [0..N] | + * | +---------+ + * | + */ + ModulePortId top_module_bl_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_BL_PORT_NAME), config_region)); + BasicPort top_module_bl_port_info = module_manager.module_port(top_module, top_module_bl_port); + + for (size_t child_id = 0; child_id < module_manager.region_configurable_children(top_module, config_region).size(); ++child_id) { + ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id]; + vtr::Point coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id]; + + size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[child_id]; + + /* Find the BL port */ + ModulePortId child_bl_port = module_manager.find_module_port(child_module, std::string(MEMORY_BL_PORT_NAME)); + BasicPort child_bl_port_info = module_manager.module_port(child_module, child_bl_port); + + size_t cur_bl_index = 0; + + for (const size_t& sink_bl_pin : child_bl_port_info.pins()) { + size_t bl_pin_id = bl_start_index_per_tile[coord.x()] + cur_bl_index; + VTR_ASSERT(bl_pin_id < top_module_bl_port_info.pins().size()); + + /* Create net */ + ModuleNetId net = create_module_source_pin_net(module_manager, top_module, + top_module, 0, + top_module_bl_port, + top_module_bl_port_info.pins()[bl_pin_id]); + VTR_ASSERT(ModuleNetId::INVALID() != net); + + /* Add net sink */ + module_manager.add_module_net_sink(top_module, net, + child_module, child_instance, child_bl_port, sink_bl_pin); + + cur_bl_index++; + } + } + } +} + /********************************************************************* * Top-level function to add nets for quicklogic memory banks using flatten BL/WLs * Each configuration region has independent BL/WLs @@ -778,7 +1035,7 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma break; } case BLWL_PROTOCOL_SHIFT_REGISTER: { - /* TODO */ + add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(module_manager, top_module, circuit_lib, config_protocol); break; } default: { @@ -872,7 +1129,14 @@ void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager, break; } 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_INPUT_PORT); + } break; } default: { @@ -914,7 +1178,14 @@ void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager, break; } 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_INPUT_PORT); + } break; } default: { diff --git a/openfpga/src/utils/memory_bank_utils.cpp b/openfpga/src/utils/memory_bank_utils.cpp index 66eb938f3..dcb224fc6 100644 --- a/openfpga/src/utils/memory_bank_utils.cpp +++ b/openfpga/src/utils/memory_bank_utils.cpp @@ -84,6 +84,22 @@ size_t find_module_ql_memory_bank_num_blwls(const ModuleManager& module_manager, 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; + + 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 coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id]; + num_bls += find_module_ql_memory_bank_num_blwls(module_manager, child_module, circuit_lib, sram_model, CONFIG_MEM_QL_MEMORY_BANK, CIRCUIT_MODEL_PORT_BL); + } + + return num_bls; +} + std::map compute_memory_bank_regional_bitline_numbers_per_tile(const ModuleManager& module_manager, const ModuleId& top_module, const ConfigRegionId& config_region, @@ -100,6 +116,22 @@ std::map compute_memory_bank_regional_bitline_numbers_per_tile(cons 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; + + 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 coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id]; + num_wls += find_module_ql_memory_bank_num_blwls(module_manager, child_module, circuit_lib, sram_model, CONFIG_MEM_QL_MEMORY_BANK, CIRCUIT_MODEL_PORT_WL); + } + + return num_wls; +} + std::map compute_memory_bank_regional_wordline_numbers_per_tile(const ModuleManager& module_manager, const ModuleId& top_module, const ConfigRegionId& config_region, diff --git a/openfpga/src/utils/memory_bank_utils.h b/openfpga/src/utils/memory_bank_utils.h index 237098927..730d19271 100644 --- a/openfpga/src/utils/memory_bank_utils.h +++ b/openfpga/src/utils/memory_bank_utils.h @@ -48,6 +48,14 @@ size_t find_module_ql_memory_bank_num_blwls(const ModuleManager& module_manager, const CircuitModelId& sram_model, const e_config_protocol_type& sram_orgz_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 @@ -60,6 +68,15 @@ std::map compute_memory_bank_regional_bitline_numbers_per_tile(cons const ConfigRegionId& config_region, const CircuitLibrary& circuit_lib, 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 * @note From 7723e00e6c46e3b50b1e7e199ea782cecf7c73ca Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 28 Sep 2021 22:49:24 -0700 Subject: [PATCH 08/52] [Engine] Adding the function that builds a shift register module for BL/WLs --- openfpga/src/base/openfpga_naming.cpp | 17 ++ openfpga/src/base/openfpga_naming.h | 6 + openfpga/src/fabric/build_memory_modules.cpp | 2 - openfpga/src/fabric/build_memory_modules.h | 16 + .../fabric/build_top_module_memory_bank.cpp | 282 ++++++++++++++++-- 5 files changed, 295 insertions(+), 28 deletions(-) diff --git a/openfpga/src/base/openfpga_naming.cpp b/openfpga/src/base/openfpga_naming.cpp index c3fdd3aa8..403ce4907 100644 --- a/openfpga/src/base/openfpga_naming.cpp +++ b/openfpga/src/base/openfpga_naming.cpp @@ -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)); } +/********************************************************************* + * 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 * This is very useful in Verilog code generation where the inputs of diff --git a/openfpga/src/base/openfpga_naming.h b/openfpga/src/base/openfpga_naming.h index 77a46e4a6..3e159a663 100644 --- a/openfpga/src/base/openfpga_naming.h +++ b/openfpga/src/base/openfpga_naming.h @@ -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, 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, const CircuitModelId& mux_model, const size_t& mux_size, diff --git a/openfpga/src/fabric/build_memory_modules.cpp b/openfpga/src/fabric/build_memory_modules.cpp index a8f7fceb4..844369fa9 100644 --- a/openfpga/src/fabric/build_memory_modules.cpp +++ b/openfpga/src/fabric/build_memory_modules.cpp @@ -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 * 3. It assumes fixed port name for output ports ********************************************************************/ -static std::vector add_module_output_nets_to_chain_mem_modules(ModuleManager& module_manager, const ModuleId& mem_module, const std::string& mem_module_output_name, @@ -162,7 +161,6 @@ void add_module_output_nets_to_mem_modules(ModuleManager& module_manager, * Do not use it to replace the * add_module_nets_cmos_memory_chain_config_bus() !!! *********************************************************************/ -static void add_module_nets_to_cmos_memory_config_chain_module(ModuleManager& module_manager, const ModuleId& parent_module, const CircuitLibrary& circuit_lib, diff --git a/openfpga/src/fabric/build_memory_modules.h b/openfpga/src/fabric/build_memory_modules.h index 3551426a2..6b6794d46 100644 --- a/openfpga/src/fabric/build_memory_modules.h +++ b/openfpga/src/fabric/build_memory_modules.h @@ -16,6 +16,22 @@ /* begin namespace openfpga */ namespace openfpga { +std::vector 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 add_module_nets_to_cmos_memory_config_chain_module(ModuleManager& module_manager, + const ModuleId& parent_module, + const CircuitLibrary& circuit_lib, + const CircuitPortId& model_input_port, + const CircuitPortId& model_output_port); + + void build_memory_modules(ModuleManager& module_manager, DecoderLibrary& arch_decoder_lib, const MuxLibrary& mux_lib, diff --git a/openfpga/src/fabric/build_top_module_memory_bank.cpp b/openfpga/src/fabric/build_top_module_memory_bank.cpp index d3711ba2a..ae1a792fd 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.cpp +++ b/openfpga/src/fabric/build_top_module_memory_bank.cpp @@ -24,6 +24,7 @@ #include "decoder_library_utils.h" #include "module_manager_utils.h" #include "memory_bank_utils.h" +#include "build_memory_modules.h" #include "build_decoder_modules.h" #include "build_top_module_memory_bank.h" @@ -44,11 +45,11 @@ namespace openfpga { * ********************************************************************/ static -void 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) { +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 sram_input_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_INPUT, true); @@ -102,13 +103,12 @@ void build_bl_shift_register_chain_module(ModuleManager& module_manager, 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 (size_t iport = 0; iport < num_bl_ports; ++iport) { - CircuitPortId child_module_output_port = sram_bl_ports[iport]; + 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); - std::vector output_nets = add_module_output_nets_to_chain_mem_modules(module_manager, mem_module, - chan_output_port_name, circuit_lib, - child_module_output_port, - sram_mem_module, i, sram_mem_instance); + 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); } } @@ -116,21 +116,121 @@ void build_bl_shift_register_chain_module(ModuleManager& module_manager, add_module_nets_to_cmos_memory_config_chain_module(module_manager, mem_module, circuit_lib, sram_input_ports[0], sram_output_ports[0]); - /* If there is a second input defined, - * add nets to short wire the 2nd inputs to the first inputs + /* 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 */ - if (2 == sram_input_ports.size()) { - add_module_nets_to_cmos_memory_scan_chain_module(module_manager, mem_module, - circuit_lib, sram_input_ports[1], sram_output_ports[0]); + 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 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 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 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 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_cmos_memory_config_chain_module(module_manager, mem_module, + circuit_lib, sram_input_ports[0], sram_output_ports[0]); + /* 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 @@ -813,14 +913,14 @@ void add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(Module } /* TODO: 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(bl_memory_model, sr_size); - // ModuleId sr_bank_module = build_bl_shift_register_chain_module(module_manager, - // circuit_lib, - // sr_module_name, - // bl_memory_model, - // sr_size); - //} + 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); + ModuleId sr_bank_module = build_bl_shift_register_chain_module(module_manager, + circuit_lib, + sr_module_name, + bl_memory_model, + sr_size); + } /* TODO: Instanciate the shift register chains in the top-level module */ //module_manager.add_child_module(top_module, sr_bank_module); @@ -1002,6 +1102,136 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_flatten_config_bus(ModuleManager } } +/********************************************************************* + * 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, + 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 */ + std::vector unique_sr_sizes; + for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { + /* TODO: Need to find how to cut the BLs when there are multiple banks for shift registers in a region */ + size_t num_wls = compute_memory_bank_regional_num_wls(module_manager, top_module, + config_region, + circuit_lib, sram_model); + unique_sr_sizes.push_back(num_wls); + } + + /* 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); + ModuleId sr_bank_module = build_wl_shift_register_chain_module(module_manager, + circuit_lib, + sr_module_name, + wl_memory_model, + sr_size); + } + + /* TODO: Instanciate the shift register chains in the top-level module */ + //module_manager.add_child_module(top_module, sr_bank_module); + + /* TODO: create connections between top-level module and the BL shift register banks */ + + /* Create connections between WLs of top-level module and WLs of child modules for each region */ + for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { + /************************************************************** + * Precompute the BLs and WLs distribution across the FPGA fabric + * The distribution is a matrix which contains the starting index of BL/WL for each column or row + */ + std::pair child_y_range = compute_memory_bank_regional_configurable_child_y_range(module_manager, top_module, config_region); + std::map num_wls_per_tile = compute_memory_bank_regional_wordline_numbers_per_tile(module_manager, top_module, + config_region, + circuit_lib, sram_model); + std::map wl_start_index_per_tile = compute_memory_bank_regional_blwl_start_index_per_tile(child_y_range, num_wls_per_tile); + + /************************************************************** + * Add WL nets from top module to each configurable child + */ + ModulePortId top_module_wl_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_WL_PORT_NAME), config_region)); + BasicPort top_module_wl_port_info = module_manager.module_port(top_module, top_module_wl_port); + + for (size_t child_id = 0; child_id < module_manager.region_configurable_children(top_module, config_region).size(); ++child_id) { + ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id]; + vtr::Point coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id]; + + size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[child_id]; + + /* Find the WL port */ + ModulePortId child_wl_port = module_manager.find_module_port(child_module, std::string(MEMORY_WL_PORT_NAME)); + BasicPort child_wl_port_info = module_manager.module_port(child_module, child_wl_port); + + size_t cur_wl_index = 0; + + for (const size_t& sink_wl_pin : child_wl_port_info.pins()) { + size_t wl_pin_id = wl_start_index_per_tile[coord.y()] + cur_wl_index; + VTR_ASSERT(wl_pin_id < top_module_wl_port_info.pins().size()); + + /* Create net */ + ModuleNetId net = create_module_source_pin_net(module_manager, top_module, + top_module, 0, + top_module_wl_port, + top_module_wl_port_info.pins()[wl_pin_id]); + VTR_ASSERT(ModuleNetId::INVALID() != net); + + /* Add net sink */ + module_manager.add_module_net_sink(top_module, net, + child_module, child_instance, child_wl_port, sink_wl_pin); + + cur_wl_index++; + } + } + + /************************************************************** + * Optional: Add WLR nets from top module to each configurable child + */ + ModulePortId top_module_wlr_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_WLR_PORT_NAME), config_region)); + BasicPort top_module_wlr_port_info; + if (top_module_wlr_port) { + top_module_wlr_port_info = module_manager.module_port(top_module, top_module_wlr_port); + for (size_t child_id = 0; child_id < module_manager.region_configurable_children(top_module, config_region).size(); ++child_id) { + ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id]; + vtr::Point coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id]; + + size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[child_id]; + + /* Find the WL port */ + ModulePortId child_wlr_port = module_manager.find_module_port(child_module, std::string(MEMORY_WLR_PORT_NAME)); + BasicPort child_wlr_port_info = module_manager.module_port(child_module, child_wlr_port); + + size_t cur_wlr_index = 0; + + for (const size_t& sink_wlr_pin : child_wlr_port_info.pins()) { + size_t wlr_pin_id = wl_start_index_per_tile[coord.y()] + cur_wlr_index; + VTR_ASSERT(wlr_pin_id < top_module_wlr_port_info.pins().size()); + + /* Create net */ + ModuleNetId net = create_module_source_pin_net(module_manager, top_module, + top_module, 0, + top_module_wlr_port, + top_module_wlr_port_info.pins()[wlr_pin_id]); + VTR_ASSERT(ModuleNetId::INVALID() != net); + + /* Add net sink */ + module_manager.add_module_net_sink(top_module, net, + child_module, child_instance, child_wlr_port, sink_wlr_pin); + + cur_wlr_index++; + } + } + } + } +} + + /********************************************************************* * Top-level function to add nets for quicklogic memory banks * - Each configuration region has independent memory bank circuitry @@ -1054,7 +1284,7 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma break; } case BLWL_PROTOCOL_SHIFT_REGISTER: { - /* TODO */ + add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(module_manager, top_module, circuit_lib, config_protocol); break; } default: { From 5da8f1db735e935dec38f9a08d8d0baad74c387f Mon Sep 17 00:00:00 2001 From: tangxifan Date: Tue, 28 Sep 2021 23:27:47 -0700 Subject: [PATCH 09/52] [Engine] Upgrading fabric generator to connect nets between top module and BL/WL shift register modules --- openfpga/src/fabric/build_top_module.cpp | 13 +- .../fabric/build_top_module_memory_bank.cpp | 121 +++++++++++++++++- 2 files changed, 121 insertions(+), 13 deletions(-) diff --git a/openfpga/src/fabric/build_top_module.cpp b/openfpga/src/fabric/build_top_module.cpp index 421b7198a..4fc4c396f 100644 --- a/openfpga/src/fabric/build_top_module.cpp +++ b/openfpga/src/fabric/build_top_module.cpp @@ -341,12 +341,6 @@ int build_top_module(ModuleManager& module_manager, 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 */ 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) { @@ -427,6 +421,13 @@ int build_top_module(ModuleManager& module_manager, 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; } diff --git a/openfpga/src/fabric/build_top_module_memory_bank.cpp b/openfpga/src/fabric/build_top_module_memory_bank.cpp index ae1a792fd..8b332e08d 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.cpp +++ b/openfpga/src/fabric/build_top_module_memory_bank.cpp @@ -912,7 +912,7 @@ void add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(Module unique_sr_sizes.push_back(num_bls); } - /* TODO: Build submodules for shift register chains */ + /* Build submodules for shift register chains */ for (const size_t& sr_size : unique_sr_sizes) { std::string sr_module_name = generate_bl_shift_register_module_name(circuit_lib.model_name(bl_memory_model), sr_size); ModuleId sr_bank_module = build_bl_shift_register_chain_module(module_manager, @@ -920,12 +920,65 @@ void add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(Module sr_module_name, bl_memory_model, sr_size); + /* Instanciate the shift register chains in the top-level module */ + module_manager.add_child_module(top_module, sr_bank_module); } - /* TODO: Instanciate the shift register chains in the top-level module */ - //module_manager.add_child_module(top_module, sr_bank_module); + /* TODO: 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 + */ + 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(std::string(BL_SHIFT_REGISTER_CHAIN_HEAD_NAME), config_region)); + BasicPort blsr_head_port_info = module_manager.module_port(top_module, blsr_head_port); - /* TODO: create connections between top-level module and the BL shift register banks */ + 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); + ModuleId child_sr_module = module_manager.find_module(sr_module_name); + ModulePortId child_blsr_head_port = module_manager.find_module_port(child_sr_module, std::string(BL_SHIFT_REGISTER_CHAIN_HEAD_NAME)); + BasicPort child_blsr_head_port_info = module_manager.module_port(child_sr_module, child_blsr_head_port); + for (size_t child_instance = 0; child_instance < module_manager.num_instance(top_module, child_sr_module); ++child_instance) { + for (const size_t& sink_pin : child_blsr_head_port_info.pins()) { + /* Create net */ + ModuleNetId net = create_module_source_pin_net(module_manager, top_module, + top_module, 0, + blsr_head_port, + blsr_head_port_info.pins()[sink_pin]); + VTR_ASSERT(ModuleNetId::INVALID() != net); + + /* Add net sink */ + module_manager.add_module_net_sink(top_module, net, + child_sr_module, child_instance, child_blsr_head_port, sink_pin); + } + } + } + } + + 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(std::string(BL_SHIFT_REGISTER_CHAIN_TAIL_NAME), config_region)); + BasicPort blsr_tail_port_info = module_manager.module_port(top_module, blsr_tail_port); + + 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); + ModuleId child_sr_module = module_manager.find_module(sr_module_name); + ModulePortId child_blsr_tail_port = module_manager.find_module_port(child_sr_module, std::string(BL_SHIFT_REGISTER_CHAIN_TAIL_NAME)); + BasicPort child_blsr_tail_port_info = module_manager.module_port(child_sr_module, child_blsr_tail_port); + for (size_t child_instance = 0; child_instance < module_manager.num_instance(top_module, child_sr_module); ++child_instance) { + for (const size_t& sink_pin : child_blsr_tail_port_info.pins()) { + /* Create net */ + ModuleNetId net = create_module_source_pin_net(module_manager, top_module, + child_sr_module, child_instance, + child_blsr_tail_port, sink_pin); + 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()[sink_pin]); + } + } + } + } /* Create connections between BLs of top-level module and BLs of child modules for each region */ for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { @@ -1134,12 +1187,66 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(Module sr_module_name, wl_memory_model, sr_size); + /* Instanciate the shift register chains in the top-level module */ + module_manager.add_child_module(top_module, sr_bank_module); } - /* TODO: Instanciate the shift register chains in the top-level module */ - //module_manager.add_child_module(top_module, sr_bank_module); + /* TODO: create connections between top-level module and the WL 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 + */ + for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { + ModulePortId wlsr_head_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(WL_SHIFT_REGISTER_CHAIN_HEAD_NAME), config_region)); + BasicPort wlsr_head_port_info = module_manager.module_port(top_module, wlsr_head_port); + + for (const size_t& sr_size : unique_sr_sizes) { + std::string sr_module_name = generate_bl_shift_register_module_name(circuit_lib.model_name(wl_memory_model), sr_size); + ModuleId child_sr_module = module_manager.find_module(sr_module_name); + ModulePortId child_wlsr_head_port = module_manager.find_module_port(child_sr_module, std::string(WL_SHIFT_REGISTER_CHAIN_HEAD_NAME)); + BasicPort child_wlsr_head_port_info = module_manager.module_port(child_sr_module, child_wlsr_head_port); + for (size_t child_instance = 0; child_instance < module_manager.num_instance(top_module, child_sr_module); ++child_instance) { + for (const size_t& sink_pin : child_wlsr_head_port_info.pins()) { + /* Create net */ + ModuleNetId net = create_module_source_pin_net(module_manager, top_module, + top_module, 0, + wlsr_head_port, + wlsr_head_port_info.pins()[sink_pin]); + VTR_ASSERT(ModuleNetId::INVALID() != net); + + /* Add net sink */ + module_manager.add_module_net_sink(top_module, net, + child_sr_module, child_instance, child_wlsr_head_port, sink_pin); + } + } + } + } + + for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { + ModulePortId wlsr_tail_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(WL_SHIFT_REGISTER_CHAIN_TAIL_NAME), config_region)); + BasicPort wlsr_tail_port_info = module_manager.module_port(top_module, wlsr_tail_port); + + 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); + ModuleId child_sr_module = module_manager.find_module(sr_module_name); + ModulePortId child_wlsr_tail_port = module_manager.find_module_port(child_sr_module, std::string(WL_SHIFT_REGISTER_CHAIN_TAIL_NAME)); + BasicPort child_wlsr_tail_port_info = module_manager.module_port(child_sr_module, child_wlsr_tail_port); + for (size_t child_instance = 0; child_instance < module_manager.num_instance(top_module, child_sr_module); ++child_instance) { + for (const size_t& sink_pin : child_wlsr_tail_port_info.pins()) { + /* Create net */ + ModuleNetId net = create_module_source_pin_net(module_manager, top_module, + child_sr_module, child_instance, + child_wlsr_tail_port, sink_pin); + VTR_ASSERT(ModuleNetId::INVALID() != net); + + /* Add net sink */ + module_manager.add_module_net_sink(top_module, net, + top_module, 0, + wlsr_tail_port, wlsr_tail_port_info.pins()[sink_pin]); + } + } + } + } - /* TODO: create connections between top-level module and the BL shift register banks */ /* Create connections between WLs of top-level module and WLs of child modules for each region */ for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { From c5ae93f1778f1d3ffd28bc32e0b66fcef74565bd Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 29 Sep 2021 16:17:40 -0700 Subject: [PATCH 10/52] [Engine] Upgraded fabric generator to support shifter register banks in Quicklogic memory bank --- .../fabric/build_top_module_memory_bank.cpp | 662 +++++++++--------- .../memory_bank_shift_register_banks.cpp | 80 +++ .../fabric/memory_bank_shift_register_banks.h | 67 ++ 3 files changed, 468 insertions(+), 341 deletions(-) create mode 100644 openfpga/src/fabric/memory_bank_shift_register_banks.cpp create mode 100644 openfpga/src/fabric/memory_bank_shift_register_banks.h diff --git a/openfpga/src/fabric/build_top_module_memory_bank.cpp b/openfpga/src/fabric/build_top_module_memory_bank.cpp index 8b332e08d..a6a0ca564 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.cpp +++ b/openfpga/src/fabric/build_top_module_memory_bank.cpp @@ -26,6 +26,7 @@ #include "memory_bank_utils.h" #include "build_memory_modules.h" #include "build_decoder_modules.h" +#include "memory_bank_shift_register_banks.h" #include "build_top_module_memory_bank.h" /* begin namespace openfpga */ @@ -842,214 +843,6 @@ void add_top_module_nets_cmos_ql_memory_bank_bl_flatten_config_bus(ModuleManager } } -/********************************************************************* - * 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, - 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 */ - std::vector unique_sr_sizes; - for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { - /* TODO: Need to find how to cut the BLs when there are multiple banks for shift registers in a region */ - size_t num_bls = compute_memory_bank_regional_num_bls(module_manager, top_module, - config_region, - circuit_lib, sram_model); - unique_sr_sizes.push_back(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); - ModuleId sr_bank_module = 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 */ - module_manager.add_child_module(top_module, sr_bank_module); - } - - /* TODO: 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 - */ - 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(std::string(BL_SHIFT_REGISTER_CHAIN_HEAD_NAME), config_region)); - BasicPort blsr_head_port_info = module_manager.module_port(top_module, blsr_head_port); - - 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); - ModuleId child_sr_module = module_manager.find_module(sr_module_name); - ModulePortId child_blsr_head_port = module_manager.find_module_port(child_sr_module, std::string(BL_SHIFT_REGISTER_CHAIN_HEAD_NAME)); - BasicPort child_blsr_head_port_info = module_manager.module_port(child_sr_module, child_blsr_head_port); - for (size_t child_instance = 0; child_instance < module_manager.num_instance(top_module, child_sr_module); ++child_instance) { - for (const size_t& sink_pin : child_blsr_head_port_info.pins()) { - /* Create net */ - ModuleNetId net = create_module_source_pin_net(module_manager, top_module, - top_module, 0, - blsr_head_port, - blsr_head_port_info.pins()[sink_pin]); - VTR_ASSERT(ModuleNetId::INVALID() != net); - - /* Add net sink */ - module_manager.add_module_net_sink(top_module, net, - child_sr_module, child_instance, child_blsr_head_port, sink_pin); - } - } - } - } - - 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(std::string(BL_SHIFT_REGISTER_CHAIN_TAIL_NAME), config_region)); - BasicPort blsr_tail_port_info = module_manager.module_port(top_module, blsr_tail_port); - - 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); - ModuleId child_sr_module = module_manager.find_module(sr_module_name); - ModulePortId child_blsr_tail_port = module_manager.find_module_port(child_sr_module, std::string(BL_SHIFT_REGISTER_CHAIN_TAIL_NAME)); - BasicPort child_blsr_tail_port_info = module_manager.module_port(child_sr_module, child_blsr_tail_port); - for (size_t child_instance = 0; child_instance < module_manager.num_instance(top_module, child_sr_module); ++child_instance) { - for (const size_t& sink_pin : child_blsr_tail_port_info.pins()) { - /* Create net */ - ModuleNetId net = create_module_source_pin_net(module_manager, top_module, - child_sr_module, child_instance, - child_blsr_tail_port, sink_pin); - 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()[sink_pin]); - } - } - } - } - - /* Create connections between BLs of top-level module and BLs of child modules for each region */ - for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { - /************************************************************** - * Precompute the BLs and WLs distribution across the FPGA fabric - * The distribution is a matrix which contains the starting index of BL/WL for each column or row - */ - std::pair child_x_range = compute_memory_bank_regional_configurable_child_x_range(module_manager, top_module, config_region); - std::map num_bls_per_tile = compute_memory_bank_regional_bitline_numbers_per_tile(module_manager, top_module, - config_region, - circuit_lib, sram_model); - std::map bl_start_index_per_tile = compute_memory_bank_regional_blwl_start_index_per_tile(child_x_range, num_bls_per_tile); - - /************************************************************** - * Add BL nets from top module to each configurable child - * BL pins of top module are connected to the BL input pins of each PB/CB/SB - * For all the PB/CB/SB in the same column, they share the same set of BLs - * A quick example - * - * BL[i .. i + sqrt(N)] - * | - * | CLB[1][H] - * | +---------+ - * | | SRAM | - * +-->| [0..N] | - * | +---------+ - * | - * ... - * | CLB[1][1] - * | +---------+ - * | | SRAM | - * +-->| [0..N] | - * | +---------+ - * | - */ - ModulePortId top_module_bl_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_BL_PORT_NAME), config_region)); - BasicPort top_module_bl_port_info = module_manager.module_port(top_module, top_module_bl_port); - - for (size_t child_id = 0; child_id < module_manager.region_configurable_children(top_module, config_region).size(); ++child_id) { - ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id]; - vtr::Point coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id]; - - size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[child_id]; - - /* Find the BL port */ - ModulePortId child_bl_port = module_manager.find_module_port(child_module, std::string(MEMORY_BL_PORT_NAME)); - BasicPort child_bl_port_info = module_manager.module_port(child_module, child_bl_port); - - size_t cur_bl_index = 0; - - for (const size_t& sink_bl_pin : child_bl_port_info.pins()) { - size_t bl_pin_id = bl_start_index_per_tile[coord.x()] + cur_bl_index; - VTR_ASSERT(bl_pin_id < top_module_bl_port_info.pins().size()); - - /* Create net */ - ModuleNetId net = create_module_source_pin_net(module_manager, top_module, - top_module, 0, - top_module_bl_port, - top_module_bl_port_info.pins()[bl_pin_id]); - VTR_ASSERT(ModuleNetId::INVALID() != net); - - /* Add net sink */ - module_manager.add_module_net_sink(top_module, net, - child_module, child_instance, child_bl_port, sink_bl_pin); - - cur_bl_index++; - } - } - } -} - /********************************************************************* * Top-level function to add nets for quicklogic memory banks using flatten BL/WLs * Each configuration region has independent BL/WLs @@ -1155,6 +948,291 @@ 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& 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, blwl_port_name); + if (!sr_module_blwl_port && !optional_blwl) { + continue; + } else { + VTR_ASSERT(sr_module_blwl_port); + } + BasicPort sr_module_blwl_port_info = module_manager.module_port(sr_bank_module, sr_module_blwl_port); + + size_t cur_sr_module_blwl_pin_id = 0; + + 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, blwl_port_name); + BasicPort child_blwl_port_info = module_manager.module_port(child_module, child_blwl_port); + + /* 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); + + cur_sr_module_blwl_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, + 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 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); + } + + /* [config_region][(shift_register_module, shift_register_instance)][i] = (reconfigurable_child_id, blwl_port_pin_index)*/ + MemoryBankShiftRegisterBanks sr_banks; + /* 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 child_x_range = compute_memory_bank_regional_configurable_child_x_range(module_manager, top_module, config_region); + std::map num_bls_per_tile = compute_memory_bank_regional_bitline_numbers_per_tile(module_manager, top_module, + config_region, + circuit_lib, sram_model); + std::map 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]; + + /* 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); + + for (const size_t& sink_bl_pin : child_bl_port_info.pins()) { + sr_banks.add_shift_register_sink_nodes(config_region, sr_bank_module, cur_inst, child_id, sink_bl_pin); + } + } + } + + /* 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(MEMORY_BL_PORT_NAME)); +} + /********************************************************************* * Top-level function to add nets for quicklogic memory banks using shift registers to control BL/WLs * @@ -1170,7 +1248,7 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(Module CircuitModelId sram_model = config_protocol.memory_model(); CircuitModelId wl_memory_model = config_protocol.wl_memory_model(); /* Find out the unique shift register chain sizes */ - std::vector unique_sr_sizes; + vtr::vector unique_sr_sizes; for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { /* TODO: Need to find how to cut the BLs when there are multiple banks for shift registers in a region */ size_t num_wls = compute_memory_bank_regional_num_wls(module_manager, top_module, @@ -1182,74 +1260,27 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(Module /* 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); - ModuleId sr_bank_module = 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 */ + build_wl_shift_register_chain_module(module_manager, + circuit_lib, + sr_module_name, + wl_memory_model, + sr_size); + } + + /* [config_region][(shift_register_module, shift_register_instance)][i] = (reconfigurable_child_id, blwl_port_pin_index)*/ + MemoryBankShiftRegisterBanks sr_banks; + /* 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); - } - /* TODO: create connections between top-level module and the WL 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 - */ - for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { - ModulePortId wlsr_head_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(WL_SHIFT_REGISTER_CHAIN_HEAD_NAME), config_region)); - BasicPort wlsr_head_port_info = module_manager.module_port(top_module, wlsr_head_port); + sr_banks.add_shift_register_instance(config_region, sr_bank_module, cur_inst); - for (const size_t& sr_size : unique_sr_sizes) { - std::string sr_module_name = generate_bl_shift_register_module_name(circuit_lib.model_name(wl_memory_model), sr_size); - ModuleId child_sr_module = module_manager.find_module(sr_module_name); - ModulePortId child_wlsr_head_port = module_manager.find_module_port(child_sr_module, std::string(WL_SHIFT_REGISTER_CHAIN_HEAD_NAME)); - BasicPort child_wlsr_head_port_info = module_manager.module_port(child_sr_module, child_wlsr_head_port); - for (size_t child_instance = 0; child_instance < module_manager.num_instance(top_module, child_sr_module); ++child_instance) { - for (const size_t& sink_pin : child_wlsr_head_port_info.pins()) { - /* Create net */ - ModuleNetId net = create_module_source_pin_net(module_manager, top_module, - top_module, 0, - wlsr_head_port, - wlsr_head_port_info.pins()[sink_pin]); - VTR_ASSERT(ModuleNetId::INVALID() != net); - - /* Add net sink */ - module_manager.add_module_net_sink(top_module, net, - child_sr_module, child_instance, child_wlsr_head_port, sink_pin); - } - } - } - } - - for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { - ModulePortId wlsr_tail_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(WL_SHIFT_REGISTER_CHAIN_TAIL_NAME), config_region)); - BasicPort wlsr_tail_port_info = module_manager.module_port(top_module, wlsr_tail_port); - - 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); - ModuleId child_sr_module = module_manager.find_module(sr_module_name); - ModulePortId child_wlsr_tail_port = module_manager.find_module_port(child_sr_module, std::string(WL_SHIFT_REGISTER_CHAIN_TAIL_NAME)); - BasicPort child_wlsr_tail_port_info = module_manager.module_port(child_sr_module, child_wlsr_tail_port); - for (size_t child_instance = 0; child_instance < module_manager.num_instance(top_module, child_sr_module); ++child_instance) { - for (const size_t& sink_pin : child_wlsr_tail_port_info.pins()) { - /* Create net */ - ModuleNetId net = create_module_source_pin_net(module_manager, top_module, - child_sr_module, child_instance, - child_wlsr_tail_port, sink_pin); - VTR_ASSERT(ModuleNetId::INVALID() != net); - - /* Add net sink */ - module_manager.add_module_net_sink(top_module, net, - top_module, 0, - wlsr_tail_port, wlsr_tail_port_info.pins()[sink_pin]); - } - } - } - } - - - /* Create connections between WLs of top-level module and WLs of child modules for each region */ - for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { /************************************************************** * Precompute the BLs and WLs distribution across the FPGA fabric * The distribution is a matrix which contains the starting index of BL/WL for each column or row @@ -1260,84 +1291,33 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(Module circuit_lib, sram_model); std::map wl_start_index_per_tile = compute_memory_bank_regional_blwl_start_index_per_tile(child_y_range, num_wls_per_tile); - /************************************************************** - * Add WL nets from top module to each configurable child - */ - ModulePortId top_module_wl_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_WL_PORT_NAME), config_region)); - BasicPort top_module_wl_port_info = module_manager.module_port(top_module, top_module_wl_port); - for (size_t child_id = 0; child_id < module_manager.region_configurable_children(top_module, config_region).size(); ++child_id) { ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id]; - vtr::Point coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id]; - size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[child_id]; - - /* Find the WL port */ + /* Find the BL port */ ModulePortId child_wl_port = module_manager.find_module_port(child_module, std::string(MEMORY_WL_PORT_NAME)); BasicPort child_wl_port_info = module_manager.module_port(child_module, child_wl_port); - size_t cur_wl_index = 0; - for (const size_t& sink_wl_pin : child_wl_port_info.pins()) { - size_t wl_pin_id = wl_start_index_per_tile[coord.y()] + cur_wl_index; - VTR_ASSERT(wl_pin_id < top_module_wl_port_info.pins().size()); - - /* Create net */ - ModuleNetId net = create_module_source_pin_net(module_manager, top_module, - top_module, 0, - top_module_wl_port, - top_module_wl_port_info.pins()[wl_pin_id]); - VTR_ASSERT(ModuleNetId::INVALID() != net); - - /* Add net sink */ - module_manager.add_module_net_sink(top_module, net, - child_module, child_instance, child_wl_port, sink_wl_pin); - - cur_wl_index++; - } - } - - /************************************************************** - * Optional: Add WLR nets from top module to each configurable child - */ - ModulePortId top_module_wlr_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_WLR_PORT_NAME), config_region)); - BasicPort top_module_wlr_port_info; - if (top_module_wlr_port) { - top_module_wlr_port_info = module_manager.module_port(top_module, top_module_wlr_port); - for (size_t child_id = 0; child_id < module_manager.region_configurable_children(top_module, config_region).size(); ++child_id) { - ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id]; - vtr::Point coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id]; - - size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[child_id]; - - /* Find the WL port */ - ModulePortId child_wlr_port = module_manager.find_module_port(child_module, std::string(MEMORY_WLR_PORT_NAME)); - BasicPort child_wlr_port_info = module_manager.module_port(child_module, child_wlr_port); - - size_t cur_wlr_index = 0; - - for (const size_t& sink_wlr_pin : child_wlr_port_info.pins()) { - size_t wlr_pin_id = wl_start_index_per_tile[coord.y()] + cur_wlr_index; - VTR_ASSERT(wlr_pin_id < top_module_wlr_port_info.pins().size()); - - /* Create net */ - ModuleNetId net = create_module_source_pin_net(module_manager, top_module, - top_module, 0, - top_module_wlr_port, - top_module_wlr_port_info.pins()[wlr_pin_id]); - VTR_ASSERT(ModuleNetId::INVALID() != net); - - /* Add net sink */ - module_manager.add_module_net_sink(top_module, net, - child_module, child_instance, child_wlr_port, sink_wlr_pin); - - cur_wlr_index++; - } + sr_banks.add_shift_register_sink_nodes(config_region, sr_bank_module, cur_inst, child_id, sink_wl_pin); } } } -} + /* 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(MEMORY_WL_PORT_NAME)); + add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_blwls(module_manager, top_module, sr_banks, std::string(MEMORY_WLR_PORT_NAME), true); +} /********************************************************************* * Top-level function to add nets for quicklogic memory banks diff --git a/openfpga/src/fabric/memory_bank_shift_register_banks.cpp b/openfpga/src/fabric/memory_bank_shift_register_banks.cpp new file mode 100644 index 000000000..3b04dc330 --- /dev/null +++ b/openfpga/src/fabric/memory_bank_shift_register_banks.cpp @@ -0,0 +1,80 @@ +#include "memory_bank_shift_register_banks.h" + +/* begin namespace openfpga */ +namespace openfpga { + +std::vector MemoryBankShiftRegisterBanks::shift_register_bank_modules(const ConfigRegionId& region) const { + std::vector sr_bank_modules; + VTR_ASSERT(valid_region_id(region)); + for (const auto& pair : sr_instance_info_[region]) { + sr_bank_modules.push_back(pair.first); + } + return sr_bank_modules; +} + +std::vector MemoryBankShiftRegisterBanks::shift_register_bank_instances(const ConfigRegionId& region) const { + std::vector sr_bank_instances; + VTR_ASSERT(valid_region_id(region)); + for (const auto& pair : sr_instance_info_[region]) { + sr_bank_instances.push_back(pair.second); + } + return sr_bank_instances; +} + +std::vector MemoryBankShiftRegisterBanks::shift_register_bank_sink_child_ids(const ConfigRegionId& region, + const ModuleId& sr_module, + const size_t& sr_instance) const { + VTR_ASSERT(valid_region_id(region)); + std::vector sink_child_ids; + + auto result = sr_instance_info_[region].find(std::make_pair(sr_module, sr_instance)); + /* Return an empty vector if not found */ + if (result != sr_instance_info_[region].end()) { + for (const auto& sink_child : result->second) { + sink_child_ids.push_back(sink_child.first); + } + } + return sink_child_ids; +} + +std::vector MemoryBankShiftRegisterBanks::shift_register_bank_sink_child_pin_ids(const ConfigRegionId& region, + const ModuleId& sr_module, + const size_t& sr_instance) const { + VTR_ASSERT(valid_region_id(region)); + std::vector sink_child_pin_ids; + + auto result = sr_instance_info_[region].find(std::make_pair(sr_module, sr_instance)); + /* Return an empty vector if not found */ + if (result != sr_instance_info_[region].end()) { + for (const auto& sink_child : result->second) { + sink_child_pin_ids.push_back(sink_child.second); + } + } + return sink_child_pin_ids; +} + +void MemoryBankShiftRegisterBanks::resize_regions(const size_t& num_regions) { + sr_instance_info_.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_info_[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_info_[region][std::make_pair(sr_module, sr_instance)].push_back(std::make_pair(sink_child_id, sink_child_pin_id)); +} + +bool MemoryBankShiftRegisterBanks::valid_region_id(const ConfigRegionId& region) const { + return size_t(region) < sr_instance_info_.size(); +} + +} /* end namespace openfpga */ diff --git a/openfpga/src/fabric/memory_bank_shift_register_banks.h b/openfpga/src/fabric/memory_bank_shift_register_banks.h new file mode 100644 index 000000000..83d7c517d --- /dev/null +++ b/openfpga/src/fabric/memory_bank_shift_register_banks.h @@ -0,0 +1,67 @@ +#ifndef MEMORY_BANK_SHIFT_REGISTER_BANKS_H +#define MEMORY_BANK_SHIFT_REGISTER_BANKS_H + +#include +#include +#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 shift register banks under a specific configuration region of top-level module */ + std::vector shift_register_bank_modules(const ConfigRegionId& region) const; + + /* @brief Return a list of instances of shift register banks under a specific configuration region of top-level module */ + std::vector shift_register_bank_instances(const ConfigRegionId& region) const; + + /* @brief Return 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 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 shift_register_bank_sink_pin_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 module id and instance id of a shift register 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); + public: /* Validators */ + bool valid_region_id(const ConfigRegionId& region) const; + + private: /* Internal data */ + vtr::vector, std::vector>>> sr_instance_info_; +}; + +} /* end namespace openfpga */ + +#endif From ac6268d9aec616c642946313e5b929362a6fde88 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 29 Sep 2021 16:24:36 -0700 Subject: [PATCH 11/52] [Engine] Bug fix on compilation errors --- .../src/fabric/memory_bank_shift_register_banks.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/openfpga/src/fabric/memory_bank_shift_register_banks.cpp b/openfpga/src/fabric/memory_bank_shift_register_banks.cpp index 3b04dc330..6956b22d2 100644 --- a/openfpga/src/fabric/memory_bank_shift_register_banks.cpp +++ b/openfpga/src/fabric/memory_bank_shift_register_banks.cpp @@ -1,3 +1,4 @@ +#include "vtr_assert.h" #include "memory_bank_shift_register_banks.h" /* begin namespace openfpga */ @@ -7,7 +8,7 @@ std::vector MemoryBankShiftRegisterBanks::shift_register_bank_modules( std::vector sr_bank_modules; VTR_ASSERT(valid_region_id(region)); for (const auto& pair : sr_instance_info_[region]) { - sr_bank_modules.push_back(pair.first); + sr_bank_modules.push_back(pair.first.first); } return sr_bank_modules; } @@ -16,7 +17,7 @@ std::vector MemoryBankShiftRegisterBanks::shift_register_bank_instances( std::vector sr_bank_instances; VTR_ASSERT(valid_region_id(region)); for (const auto& pair : sr_instance_info_[region]) { - sr_bank_instances.push_back(pair.second); + sr_bank_instances.push_back(pair.first.second); } return sr_bank_instances; } @@ -37,9 +38,9 @@ std::vector MemoryBankShiftRegisterBanks::shift_register_bank_sink_child return sink_child_ids; } -std::vector MemoryBankShiftRegisterBanks::shift_register_bank_sink_child_pin_ids(const ConfigRegionId& region, - const ModuleId& sr_module, - const size_t& sr_instance) const { +std::vector MemoryBankShiftRegisterBanks::shift_register_bank_sink_pin_ids(const ConfigRegionId& region, + const ModuleId& sr_module, + const size_t& sr_instance) const { VTR_ASSERT(valid_region_id(region)); std::vector sink_child_pin_ids; From 89a97d83bd1143403eb66f347b985d92434f7608 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 29 Sep 2021 16:28:06 -0700 Subject: [PATCH 12/52] [Test] Added a new test case for the shift register banks in QuickLogic memory banks --- .../config/task.conf | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 openfpga_flow/tasks/basic_tests/full_testbench/ql_memory_bank_shift_register/config/task.conf diff --git a/openfpga_flow/tasks/basic_tests/full_testbench/ql_memory_bank_shift_register/config/task.conf b/openfpga_flow/tasks/basic_tests/full_testbench/ql_memory_bank_shift_register/config/task.conf new file mode 100644 index 000000000..ba36d7f4c --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/full_testbench/ql_memory_bank_shift_register/config/task.conf @@ -0,0 +1,44 @@ +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# Configuration file for running experiments +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = +# timeout_each_job : FPGA Task script splits fpga flow into multiple jobs +# Each job execute fpga_flow script on combination of architecture & benchmark +# timeout_each_job is timeout for each job +# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = + +[GENERAL] +run_engine=openfpga_shell +power_tech_file = ${PATH:OPENFPGA_PATH}/openfpga_flow/tech/PTM_45nm/45nm.xml +power_analysis = true +spice_output=false +verilog_output=true +timeout_each_job = 20*60 +fpga_flow=yosys_vpr + +[OpenFPGA_SHELL] +openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/write_full_testbench_example_script.openfpga +openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml +openfpga_vpr_device_layout= +openfpga_fast_configuration= + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v +bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/or2/or2.v +bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch/and2_latch.v + +[SYNTHESIS_PARAM] +bench0_top = and2 +bench0_chan_width = 300 + +bench1_top = or2 +bench1_chan_width = 300 + +bench2_top = and2_latch +bench2_chan_width = 300 + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= From 4926c323e72ec2713847e50eef3305b082a6e27d Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 29 Sep 2021 16:32:29 -0700 Subject: [PATCH 13/52] [Engine] Bug fix due to the optional syntax ``num_bank`` were required in XML --- libopenfpga/libarchopenfpga/src/read_xml_config_protocol.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libopenfpga/libarchopenfpga/src/read_xml_config_protocol.cpp b/libopenfpga/libarchopenfpga/src/read_xml_config_protocol.cpp index c84bbe93b..9a3a60336 100644 --- a/libopenfpga/libarchopenfpga/src/read_xml_config_protocol.cpp +++ b/libopenfpga/libarchopenfpga/src/read_xml_config_protocol.cpp @@ -74,7 +74,7 @@ void read_xml_bl_protocol(pugi::xml_node& xml_bl_protocol, */ if (BLWL_PROTOCOL_SHIFT_REGISTER == blwl_protocol_type) { config_protocol.set_bl_memory_model_name(get_attribute(xml_bl_protocol, "circuit_model_name", loc_data).as_string()); - config_protocol.set_bl_num_banks(get_attribute(xml_bl_protocol, "num_banks", loc_data).as_int(1)); + config_protocol.set_bl_num_banks(get_attribute(xml_bl_protocol, "num_banks", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(1)); } } @@ -104,7 +104,7 @@ void read_xml_wl_protocol(pugi::xml_node& xml_wl_protocol, */ if (BLWL_PROTOCOL_SHIFT_REGISTER == blwl_protocol_type) { config_protocol.set_wl_memory_model_name(get_attribute(xml_wl_protocol, "circuit_model_name", loc_data).as_string()); - config_protocol.set_wl_num_banks(get_attribute(xml_wl_protocol, "num_banks", loc_data).as_int(1)); + config_protocol.set_wl_num_banks(get_attribute(xml_wl_protocol, "num_banks", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(1)); } } From 41cc3757460820e4b889db4065caf03c837c25c8 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 29 Sep 2021 16:34:40 -0700 Subject: [PATCH 14/52] [Arch] define default CCFF model in ql bank example architecture that uses shift registers --- openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml index c07af9a10..25f5261d9 100644 --- a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml +++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml @@ -165,7 +165,7 @@ - + From 8f0ae937bc77e870cb07a29ab7da8457e6f74d6a Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 29 Sep 2021 16:57:49 -0700 Subject: [PATCH 15/52] [Engine] Upgraded fabric generator to support single shift register bank per configuration region for QuickLogic memory bank --- openfpga/src/fabric/build_memory_modules.cpp | 1 + openfpga/src/fabric/build_memory_modules.h | 7 - .../fabric/build_top_module_memory_bank.cpp | 149 ++++++++++++++++-- 3 files changed, 137 insertions(+), 20 deletions(-) diff --git a/openfpga/src/fabric/build_memory_modules.cpp b/openfpga/src/fabric/build_memory_modules.cpp index 844369fa9..fe6340a8f 100644 --- a/openfpga/src/fabric/build_memory_modules.cpp +++ b/openfpga/src/fabric/build_memory_modules.cpp @@ -161,6 +161,7 @@ void add_module_output_nets_to_mem_modules(ModuleManager& module_manager, * Do not use it to replace the * add_module_nets_cmos_memory_chain_config_bus() !!! *********************************************************************/ +static void add_module_nets_to_cmos_memory_config_chain_module(ModuleManager& module_manager, const ModuleId& parent_module, const CircuitLibrary& circuit_lib, diff --git a/openfpga/src/fabric/build_memory_modules.h b/openfpga/src/fabric/build_memory_modules.h index 6b6794d46..921b9fbd2 100644 --- a/openfpga/src/fabric/build_memory_modules.h +++ b/openfpga/src/fabric/build_memory_modules.h @@ -25,13 +25,6 @@ std::vector add_module_output_nets_to_chain_mem_modules(ModuleManag const size_t& child_index, const size_t& child_instance); -void add_module_nets_to_cmos_memory_config_chain_module(ModuleManager& module_manager, - const ModuleId& parent_module, - const CircuitLibrary& circuit_lib, - const CircuitPortId& model_input_port, - const CircuitPortId& model_output_port); - - void build_memory_modules(ModuleManager& module_manager, DecoderLibrary& arch_decoder_lib, const MuxLibrary& mux_lib, diff --git a/openfpga/src/fabric/build_top_module_memory_bank.cpp b/openfpga/src/fabric/build_top_module_memory_bank.cpp index a6a0ca564..db82870ad 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.cpp +++ b/openfpga/src/fabric/build_top_module_memory_bank.cpp @@ -32,6 +32,118 @@ /* begin 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 * @@ -114,8 +226,10 @@ ModuleId build_bl_shift_register_chain_module(ModuleManager& module_manager, } /* Build module nets to wire the configuration chain */ - add_module_nets_to_cmos_memory_config_chain_module(module_manager, mem_module, - circuit_lib, sram_input_ports[0], sram_output_ports[0]); + 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), @@ -221,8 +335,10 @@ ModuleId build_wl_shift_register_chain_module(ModuleManager& module_manager, } /* Build module nets to wire the configuration chain */ - add_module_nets_to_cmos_memory_config_chain_module(module_manager, mem_module, - circuit_lib, sram_input_ports[0], sram_output_ports[0]); + 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), @@ -1056,7 +1172,8 @@ 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& blwl_port_name, + 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) { @@ -1064,12 +1181,11 @@ void add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_blwls(ModuleMan 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, blwl_port_name); - if (!sr_module_blwl_port && !optional_blwl) { + 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; - } else { - VTR_ASSERT(sr_module_blwl_port); } + VTR_ASSERT(sr_module_blwl_port); BasicPort sr_module_blwl_port_info = module_manager.module_port(sr_bank_module, sr_module_blwl_port); size_t cur_sr_module_blwl_pin_id = 0; @@ -1080,7 +1196,7 @@ void add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_blwls(ModuleMan 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, blwl_port_name); + 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); /* Create net */ @@ -1230,7 +1346,9 @@ void add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(Module 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(MEMORY_BL_PORT_NAME)); + 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)); } /********************************************************************* @@ -1315,8 +1433,13 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(Module 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(MEMORY_WL_PORT_NAME)); - add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_blwls(module_manager, top_module, sr_banks, std::string(MEMORY_WLR_PORT_NAME), true); + 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); } /********************************************************************* From b87b7a99c5d706f5ff756744778e1725640ae334 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 29 Sep 2021 20:21:46 -0700 Subject: [PATCH 16/52] [Engine] Add MemoryBankShiftRegisterBanks to openfpga context because their contents are required by netlist writers as well as bitstream generators --- openfpga/src/base/openfpga_build_fabric.cpp | 1 + openfpga/src/base/openfpga_context.h | 8 ++++++++ openfpga/src/fabric/build_device_module.cpp | 2 ++ openfpga/src/fabric/build_device_module.h | 1 + openfpga/src/fabric/build_top_module.cpp | 3 ++- openfpga/src/fabric/build_top_module.h | 2 ++ openfpga/src/fabric/build_top_module_memory.cpp | 6 +++++- openfpga/src/fabric/build_top_module_memory.h | 2 ++ openfpga/src/fabric/build_top_module_memory_bank.cpp | 11 +++++------ openfpga/src/fabric/build_top_module_memory_bank.h | 3 +++ .../src/fabric/memory_bank_shift_register_banks.h | 1 + 11 files changed, 32 insertions(+), 8 deletions(-) diff --git a/openfpga/src/base/openfpga_build_fabric.cpp b/openfpga/src/base/openfpga_build_fabric.cpp index 146520624..1caac7342 100644 --- a/openfpga/src/base/openfpga_build_fabric.cpp +++ b/openfpga/src/base/openfpga_build_fabric.cpp @@ -103,6 +103,7 @@ int build_fabric(OpenfpgaContext& openfpga_ctx, curr_status = build_device_module_graph(openfpga_ctx.mutable_module_graph(), openfpga_ctx.mutable_decoder_lib(), + openfpga_ctx.mutable_blwl_shift_register_banks(), const_cast(openfpga_ctx), g_vpr_ctx.device(), cmd_context.option_enable(cmd, opt_frame_view), diff --git a/openfpga/src/base/openfpga_context.h b/openfpga/src/base/openfpga_context.h index c85bf8607..dbb611fe6 100644 --- a/openfpga/src/base/openfpga_context.h +++ b/openfpga/src/base/openfpga_context.h @@ -23,6 +23,7 @@ #include "device_rr_gsb.h" #include "io_location_map.h" #include "fabric_global_port_info.h" +#include "memory_bank_shift_register_banks.h" /******************************************************************** * 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::MuxLibrary& mux_lib() const { return mux_lib_; } const openfpga::DecoderLibrary& decoder_lib() const { return decoder_lib_; } + const std::array& blwl_shift_register_banks() { return blwl_sr_banks_; } const openfpga::TileDirect& tile_direct() const { return tile_direct_; } const openfpga::ModuleManager& module_graph() const { return module_graph_; } const openfpga::FlowManager& flow_manager() const { return flow_manager_; } @@ -87,6 +89,7 @@ class OpenfpgaContext : public Context { openfpga::DeviceRRGSB& mutable_device_rr_gsb() { return device_rr_gsb_; } openfpga::MuxLibrary& mutable_mux_lib() { return mux_lib_; } openfpga::DecoderLibrary& mutable_decoder_lib() { return decoder_lib_; } + std::array& mutable_blwl_shift_register_banks() { return blwl_sr_banks_; } openfpga::TileDirect& mutable_tile_direct() { return tile_direct_; } openfpga::ModuleManager& mutable_module_graph() { return module_graph_; } openfpga::FlowManager& mutable_flow_manager() { return flow_manager_; } @@ -132,6 +135,11 @@ class OpenfpgaContext : public Context { /* Inner/inter-column/row tile direct connections */ 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 blwl_sr_banks_; + /* Fabric module graph */ openfpga::ModuleManager module_graph_; openfpga::IoLocationMap io_location_map_; diff --git a/openfpga/src/fabric/build_device_module.cpp b/openfpga/src/fabric/build_device_module.cpp index 4b39a5cee..3541616fc 100644 --- a/openfpga/src/fabric/build_device_module.cpp +++ b/openfpga/src/fabric/build_device_module.cpp @@ -31,6 +31,7 @@ namespace openfpga { *******************************************************************/ int build_device_module_graph(ModuleManager& module_manager, DecoderLibrary& decoder_lib, + std::array& blwl_sr_banks, const OpenfpgaContext& openfpga_ctx, const DeviceContext& vpr_device_ctx, const bool& frame_view, @@ -112,6 +113,7 @@ int build_device_module_graph(ModuleManager& module_manager, /* Build FPGA fabric top-level module */ status = build_top_module(module_manager, decoder_lib, + blwl_sr_banks, openfpga_ctx.arch().circuit_lib, openfpga_ctx.vpr_device_annotation(), vpr_device_ctx.grid, diff --git a/openfpga/src/fabric/build_device_module.h b/openfpga/src/fabric/build_device_module.h index 5d3215bb4..1cde17ba7 100644 --- a/openfpga/src/fabric/build_device_module.h +++ b/openfpga/src/fabric/build_device_module.h @@ -17,6 +17,7 @@ namespace openfpga { int build_device_module_graph(ModuleManager& module_manager, DecoderLibrary& decoder_lib, + std::array& blwl_sr_banks, const OpenfpgaContext& openfpga_ctx, const DeviceContext& vpr_device_ctx, const bool& frame_view, diff --git a/openfpga/src/fabric/build_top_module.cpp b/openfpga/src/fabric/build_top_module.cpp index 4fc4c396f..c5b3aee45 100644 --- a/openfpga/src/fabric/build_top_module.cpp +++ b/openfpga/src/fabric/build_top_module.cpp @@ -283,6 +283,7 @@ vtr::Matrix add_top_module_connection_block_instances(ModuleManager& mod *******************************************************************/ int build_top_module(ModuleManager& module_manager, DecoderLibrary& decoder_lib, + std::array& blwl_sr_banks, const CircuitLibrary& circuit_lib, const VprDeviceAnnotation& vpr_device_annotation, const DeviceGrid& grids, @@ -414,7 +415,7 @@ int build_top_module(ModuleManager& module_manager, * 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()) { - 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, circuit_lib, config_protocol, circuit_lib.design_tech_type(sram_model), diff --git a/openfpga/src/fabric/build_top_module.h b/openfpga/src/fabric/build_top_module.h index d7e90a09f..3ddaea09a 100644 --- a/openfpga/src/fabric/build_top_module.h +++ b/openfpga/src/fabric/build_top_module.h @@ -19,6 +19,7 @@ #include "config_protocol.h" #include "module_manager.h" #include "fabric_key.h" +#include "memory_bank_shift_register_banks.h" /******************************************************************** * Function declaration @@ -29,6 +30,7 @@ namespace openfpga { int build_top_module(ModuleManager& module_manager, DecoderLibrary& decoder_lib, + std::array& blwl_sr_banks, const CircuitLibrary& circuit_lib, const VprDeviceAnnotation& vpr_device_annotation, const DeviceGrid& grids, diff --git a/openfpga/src/fabric/build_top_module_memory.cpp b/openfpga/src/fabric/build_top_module_memory.cpp index 42debe24f..e48167970 100644 --- a/openfpga/src/fabric/build_top_module_memory.cpp +++ b/openfpga/src/fabric/build_top_module_memory.cpp @@ -1735,6 +1735,7 @@ void add_top_module_nets_cmos_memory_frame_config_bus(ModuleManager& module_mana static void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager, DecoderLibrary& decoder_lib, + std::array& blwl_sr_banks, const ModuleId& parent_module, const CircuitLibrary& circuit_lib, 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); break; case CONFIG_MEM_QL_MEMORY_BANK: - add_top_module_nets_cmos_ql_memory_bank_config_bus(module_manager, decoder_lib, parent_module, circuit_lib, 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; case CONFIG_MEM_FRAME_BASED: 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, DecoderLibrary& decoder_lib, + std::array& blwl_sr_banks, const ModuleId& parent_module, const CircuitLibrary& circuit_lib, const ConfigProtocol& config_protocol, @@ -1811,6 +1814,7 @@ void add_top_module_nets_memory_config_bus(ModuleManager& module_manager, switch (mem_tech) { case CIRCUIT_MODEL_DESIGN_CMOS: add_top_module_nets_cmos_memory_config_bus(module_manager, decoder_lib, + blwl_sr_banks, parent_module, circuit_lib, config_protocol, diff --git a/openfpga/src/fabric/build_top_module_memory.h b/openfpga/src/fabric/build_top_module_memory.h index 7b6f9aa10..4819a56f6 100644 --- a/openfpga/src/fabric/build_top_module_memory.h +++ b/openfpga/src/fabric/build_top_module_memory.h @@ -18,6 +18,7 @@ #include "device_rr_gsb.h" #include "fabric_key.h" #include "config_protocol.h" +#include "memory_bank_shift_register_banks.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, DecoderLibrary& decoder_lib, + std::array& blwl_sr_banks, const ModuleId& parent_module, const CircuitLibrary& circuit_lib, const ConfigProtocol& config_protocol, diff --git a/openfpga/src/fabric/build_top_module_memory_bank.cpp b/openfpga/src/fabric/build_top_module_memory_bank.cpp index db82870ad..dd2bdf29b 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.cpp +++ b/openfpga/src/fabric/build_top_module_memory_bank.cpp @@ -1272,6 +1272,7 @@ void add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_blwls(ModuleMan **********************************************************************/ 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) { @@ -1298,8 +1299,6 @@ void add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(Module sr_size); } - /* [config_region][(shift_register_module, shift_register_instance)][i] = (reconfigurable_child_id, blwl_port_pin_index)*/ - MemoryBankShiftRegisterBanks sr_banks; /* 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)) { @@ -1360,6 +1359,7 @@ void add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(Module **********************************************************************/ 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) { @@ -1385,8 +1385,6 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(Module sr_size); } - /* [config_region][(shift_register_module, shift_register_instance)][i] = (reconfigurable_child_id, blwl_port_pin_index)*/ - MemoryBankShiftRegisterBanks sr_banks; /* 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)) { @@ -1458,6 +1456,7 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(Module ********************************************************************/ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_manager, DecoderLibrary& decoder_lib, + std::array& blwl_sr_banks, const ModuleId& top_module, const CircuitLibrary& circuit_lib, const ConfigProtocol& config_protocol, @@ -1475,7 +1474,7 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma break; } case BLWL_PROTOCOL_SHIFT_REGISTER: { - add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(module_manager, top_module, circuit_lib, config_protocol); + 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; } default: { @@ -1494,7 +1493,7 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma break; } case BLWL_PROTOCOL_SHIFT_REGISTER: { - add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(module_manager, top_module, circuit_lib, config_protocol); + 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; } default: { diff --git a/openfpga/src/fabric/build_top_module_memory_bank.h b/openfpga/src/fabric/build_top_module_memory_bank.h index 3d6acc255..d3a3d2f77 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.h +++ b/openfpga/src/fabric/build_top_module_memory_bank.h @@ -7,12 +7,14 @@ #include #include +#include #include "vtr_vector.h" #include "vtr_ndmatrix.h" #include "module_manager.h" #include "config_protocol.h" #include "circuit_library.h" #include "decoder_library.h" +#include "memory_bank_shift_register_banks.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, DecoderLibrary& decoder_lib, + std::array& blwl_sr_banks, const ModuleId& top_module, const CircuitLibrary& circuit_lib, const ConfigProtocol& config_protocol, diff --git a/openfpga/src/fabric/memory_bank_shift_register_banks.h b/openfpga/src/fabric/memory_bank_shift_register_banks.h index 83d7c517d..262508bad 100644 --- a/openfpga/src/fabric/memory_bank_shift_register_banks.h +++ b/openfpga/src/fabric/memory_bank_shift_register_banks.h @@ -59,6 +59,7 @@ class MemoryBankShiftRegisterBanks { 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, std::vector>>> sr_instance_info_; }; From f456c7e2360b6dd83a44c2dc2080399d4001e781 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 29 Sep 2021 20:34:25 -0700 Subject: [PATCH 17/52] [Engine] Add a new API to the MemoryBankShiftRegisterBank to access all the unique modules --- .../src/fabric/memory_bank_shift_register_banks.cpp | 13 +++++++++++++ .../src/fabric/memory_bank_shift_register_banks.h | 3 +++ 2 files changed, 16 insertions(+) diff --git a/openfpga/src/fabric/memory_bank_shift_register_banks.cpp b/openfpga/src/fabric/memory_bank_shift_register_banks.cpp index 6956b22d2..0d4902936 100644 --- a/openfpga/src/fabric/memory_bank_shift_register_banks.cpp +++ b/openfpga/src/fabric/memory_bank_shift_register_banks.cpp @@ -1,9 +1,22 @@ +#include #include "vtr_assert.h" #include "memory_bank_shift_register_banks.h" /* begin namespace openfpga */ namespace openfpga { +std::vector MemoryBankShiftRegisterBanks::shift_register_bank_unique_modules() const { + std::vector sr_bank_modules; + for (const auto& region : sr_instance_info_) { + 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 MemoryBankShiftRegisterBanks::shift_register_bank_modules(const ConfigRegionId& region) const { std::vector sr_bank_modules; VTR_ASSERT(valid_region_id(region)); diff --git a/openfpga/src/fabric/memory_bank_shift_register_banks.h b/openfpga/src/fabric/memory_bank_shift_register_banks.h index 262508bad..59c92fef7 100644 --- a/openfpga/src/fabric/memory_bank_shift_register_banks.h +++ b/openfpga/src/fabric/memory_bank_shift_register_banks.h @@ -22,6 +22,9 @@ namespace openfpga { ******************************************************************************/ class MemoryBankShiftRegisterBanks { public: /* Accessors */ + /* @brief Return a list of modules of unique shift register banks across all the regions */ + std::vector shift_register_bank_unique_modules() const; + /* @brief Return a list of modules of shift register banks under a specific configuration region of top-level module */ std::vector shift_register_bank_modules(const ConfigRegionId& region) const; From 2d4c200d58ca778bb1a401168c349830984efd0a Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 29 Sep 2021 20:56:02 -0700 Subject: [PATCH 18/52] [FPGA-Verilog] Now FPGA-Verilog can output shift register bank netlists --- openfpga/src/base/openfpga_verilog.cpp | 1 + openfpga/src/fpga_verilog/verilog_api.cpp | 2 + openfpga/src/fpga_verilog/verilog_api.h | 2 + openfpga/src/fpga_verilog/verilog_constants.h | 1 + .../verilog_shift_register_banks.cpp | 81 +++++++++++++++++++ .../verilog_shift_register_banks.h | 29 +++++++ .../src/fpga_verilog/verilog_submodule.cpp | 14 +++- openfpga/src/fpga_verilog/verilog_submodule.h | 2 + 8 files changed, 130 insertions(+), 2 deletions(-) create mode 100644 openfpga/src/fpga_verilog/verilog_shift_register_banks.cpp create mode 100644 openfpga/src/fpga_verilog/verilog_shift_register_banks.h diff --git a/openfpga/src/base/openfpga_verilog.cpp b/openfpga/src/base/openfpga_verilog.cpp index b912c518c..2f3dd892f 100644 --- a/openfpga/src/base/openfpga_verilog.cpp +++ b/openfpga/src/base/openfpga_verilog.cpp @@ -52,6 +52,7 @@ int write_fabric_verilog(OpenfpgaContext& openfpga_ctx, fpga_fabric_verilog(openfpga_ctx.mutable_module_graph(), openfpga_ctx.mutable_verilog_netlists(), + openfpga_ctx.blwl_shift_register_banks(), openfpga_ctx.arch().circuit_lib, openfpga_ctx.mux_lib(), openfpga_ctx.decoder_lib(), diff --git a/openfpga/src/fpga_verilog/verilog_api.cpp b/openfpga/src/fpga_verilog/verilog_api.cpp index b22de5920..8ac019781 100644 --- a/openfpga/src/fpga_verilog/verilog_api.cpp +++ b/openfpga/src/fpga_verilog/verilog_api.cpp @@ -55,6 +55,7 @@ namespace openfpga { ********************************************************************/ void fpga_fabric_verilog(ModuleManager &module_manager, NetlistManager &netlist_manager, + const std::array& blwl_sr_banks, const CircuitLibrary &circuit_lib, const MuxLibrary &mux_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!!! */ print_verilog_submodule(module_manager, netlist_manager, + blwl_sr_banks, mux_lib, decoder_lib, circuit_lib, submodule_dir_path, options); diff --git a/openfpga/src/fpga_verilog/verilog_api.h b/openfpga/src/fpga_verilog/verilog_api.h index 934dc08f7..ef550c76d 100644 --- a/openfpga/src/fpga_verilog/verilog_api.h +++ b/openfpga/src/fpga_verilog/verilog_api.h @@ -23,6 +23,7 @@ #include "io_location_map.h" #include "fabric_global_port_info.h" #include "vpr_netlist_annotation.h" +#include "memory_bank_shift_register_banks.h" #include "fabric_verilog_options.h" #include "verilog_testbench_options.h" @@ -35,6 +36,7 @@ namespace openfpga { void fpga_fabric_verilog(ModuleManager& module_manager, NetlistManager& netlist_manager, + const std::array& blwl_sr_banks, const CircuitLibrary& circuit_lib, const MuxLibrary& mux_lib, const DecoderLibrary& decoder_lib, diff --git a/openfpga/src/fpga_verilog/verilog_constants.h b/openfpga/src/fpga_verilog/verilog_constants.h index 639c1575a..3c164feee 100644 --- a/openfpga/src/fpga_verilog/verilog_constants.h +++ b/openfpga/src/fpga_verilog/verilog_constants.h @@ -26,6 +26,7 @@ constexpr char* MUXES_VERILOG_FILE_NAME = "muxes.v"; constexpr char* LOCAL_ENCODER_VERILOG_FILE_NAME = "local_encoder.v"; constexpr char* ARCH_ENCODER_VERILOG_FILE_NAME = "arch_encoder.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* ESSENTIALS_VERILOG_FILE_NAME = "inv_buf_passgate.v"; constexpr char* CONFIG_PERIPHERAL_VERILOG_FILE_NAME = "config_peripherals.v"; diff --git a/openfpga/src/fpga_verilog/verilog_shift_register_banks.cpp b/openfpga/src/fpga_verilog/verilog_shift_register_banks.cpp new file mode 100644 index 000000000..4d629a0cb --- /dev/null +++ b/openfpga/src/fpga_verilog/verilog_shift_register_banks.cpp @@ -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 +#include + +/* 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& 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 */ diff --git a/openfpga/src/fpga_verilog/verilog_shift_register_banks.h b/openfpga/src/fpga_verilog/verilog_shift_register_banks.h new file mode 100644 index 000000000..2de1bedee --- /dev/null +++ b/openfpga/src/fpga_verilog/verilog_shift_register_banks.h @@ -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 + +#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& blwl_sr_banks, + const std::string& submodule_dir, + const FabricVerilogOption& options); + +} /* end namespace openfpga */ + +#endif diff --git a/openfpga/src/fpga_verilog/verilog_submodule.cpp b/openfpga/src/fpga_verilog/verilog_submodule.cpp index d2bca2aa9..0cb2c97a4 100644 --- a/openfpga/src/fpga_verilog/verilog_submodule.cpp +++ b/openfpga/src/fpga_verilog/verilog_submodule.cpp @@ -14,6 +14,7 @@ #include "verilog_lut.h" #include "verilog_wire.h" #include "verilog_memory.h" +#include "verilog_shift_register_banks.h" #include "verilog_writer_utils.h" #include "verilog_constants.h" @@ -33,6 +34,7 @@ namespace openfpga { ********************************************************************/ void print_verilog_submodule(ModuleManager& module_manager, NetlistManager& netlist_manager, + const std::array& blwl_sr_banks, const MuxLibrary& mux_lib, const DecoderLibrary& decoder_lib, const CircuitLibrary& circuit_lib, @@ -84,14 +86,22 @@ void print_verilog_submodule(ModuleManager& module_manager, submodule_dir, fpga_verilog_opts.default_net_type()); - /* 4. Memories */ + /* Memories */ print_verilog_submodule_memories(const_cast(module_manager), netlist_manager, mux_lib, circuit_lib, submodule_dir, fpga_verilog_opts); - /* 5. Dump template for all the modules */ + /* Shift register banks */ + print_verilog_submodule_shift_register_banks(const_cast(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()) { print_verilog_submodule_templates(const_cast(module_manager), circuit_lib, diff --git a/openfpga/src/fpga_verilog/verilog_submodule.h b/openfpga/src/fpga_verilog/verilog_submodule.h index 27bf7fdba..d25ec4844 100644 --- a/openfpga/src/fpga_verilog/verilog_submodule.h +++ b/openfpga/src/fpga_verilog/verilog_submodule.h @@ -8,6 +8,7 @@ #include "netlist_manager.h" #include "mux_library.h" #include "decoder_library.h" +#include "memory_bank_shift_register_banks.h" #include "fabric_verilog_options.h" /******************************************************************** @@ -19,6 +20,7 @@ namespace openfpga { void print_verilog_submodule(ModuleManager& module_manager, NetlistManager& netlist_manager, + const std::array& blwl_sr_banks, const MuxLibrary& mux_lib, const DecoderLibrary& decoder_lib, const CircuitLibrary& circuit_lib, From 4d8019b7c1c1d4b5020570ce041d069e5cca23e6 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 29 Sep 2021 22:32:45 -0700 Subject: [PATCH 19/52] [FPGA-Bitstream] Bug fix in bitstream generator for shift-register-based memory bank --- .../build_fabric_bitstream_memory_bank.cpp | 24 ++++++++++++++----- openfpga/src/utils/memory_utils.cpp | 10 +++++--- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/openfpga/src/fpga_bitstream/build_fabric_bitstream_memory_bank.cpp b/openfpga/src/fpga_bitstream/build_fabric_bitstream_memory_bank.cpp index 998b3960b..7742b9bf9 100644 --- a/openfpga/src/fpga_bitstream/build_fabric_bitstream_memory_bank.cpp +++ b/openfpga/src/fpga_bitstream/build_fabric_bitstream_memory_bank.cpp @@ -249,8 +249,12 @@ void build_module_fabric_dependent_bitstream_ql_memory_bank(const ConfigProtocol } } } else { - /* TODO */ 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 @@ -275,8 +279,12 @@ void build_module_fabric_dependent_bitstream_ql_memory_bank(const ConfigProtocol } } } else { - /* TODO */ 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 */ @@ -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) */ ModulePortId cur_bl_addr_port; + BasicPort cur_bl_addr_port_info; 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_info = module_manager.module_port(top_module, cur_bl_addr_port); } 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_info = module_manager.module_port(top_module, cur_bl_addr_port); } else { - /* TODO */ 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; + BasicPort cur_wl_addr_port_info; 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_info = module_manager.module_port(top_module, cur_wl_addr_port); } 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_info = module_manager.module_port(top_module, cur_wl_addr_port); } else { - /* TODO */ 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 diff --git a/openfpga/src/utils/memory_utils.cpp b/openfpga/src/utils/memory_utils.cpp index 71c2c60ef..8da43d02b 100644 --- a/openfpga/src/utils/memory_utils.cpp +++ b/openfpga/src/utils/memory_utils.cpp @@ -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()) { VTR_ASSERT(2 <= curr_region_num_config_child); num_child_to_skip = 2; - /* If flatten bus is used, BL/WL may not need decoders */ - if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) { + /* - If flatten bus is used, BL/WL may not need decoders + * - 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--; } - 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--; } } From 43c569b612fb54a3f1784cfbedc3f90720184602 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 30 Sep 2021 14:47:21 -0700 Subject: [PATCH 20/52] [FPGA-Bitstream] Encapusulate the data structur storing memory bank fabric bitstream for flatten BL/WL into an object --- .../memory_bank_flatten_fabric_bitstream.cpp | 50 +++++++++++++ .../memory_bank_flatten_fabric_bitstream.h | 49 +++++++++++++ .../write_text_fabric_bitstream.cpp | 70 ++++++++++++++----- openfpga/src/utils/fabric_bitstream_utils.cpp | 2 +- openfpga/src/utils/fabric_bitstream_utils.h | 5 +- 5 files changed, 155 insertions(+), 21 deletions(-) create mode 100644 openfpga/src/fpga_bitstream/memory_bank_flatten_fabric_bitstream.cpp create mode 100644 openfpga/src/fpga_bitstream/memory_bank_flatten_fabric_bitstream.h diff --git a/openfpga/src/fpga_bitstream/memory_bank_flatten_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/memory_bank_flatten_fabric_bitstream.cpp new file mode 100644 index 000000000..110732b3d --- /dev/null +++ b/openfpga/src/fpga_bitstream/memory_bank_flatten_fabric_bitstream.cpp @@ -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 MemoryBankFlattenFabricBitstream::bl_vector(const std::vector& wl_vec) const { + return bitstream_.at(wl_vec); +} + +std::vector> MemoryBankFlattenFabricBitstream::wl_vectors() const { + std::vector> wl_vecs; + for (const auto& pair : bitstream_) { + wl_vecs.push_back(pair.first); + } + return wl_vecs; +} + +void MemoryBankFlattenFabricBitstream::add_blwl_vectors(const std::vector& bl_vec, + const std::vector& wl_vec) { + /* TODO: Add sanity check. Give a warning if the wl vector is already there */ + bitstream_[wl_vec] = bl_vec; +} + +} /* end namespace openfpga */ diff --git a/openfpga/src/fpga_bitstream/memory_bank_flatten_fabric_bitstream.h b/openfpga/src/fpga_bitstream/memory_bank_flatten_fabric_bitstream.h new file mode 100644 index 000000000..4c5cf27a9 --- /dev/null +++ b/openfpga/src/fpga_bitstream/memory_bank_flatten_fabric_bitstream.h @@ -0,0 +1,49 @@ +#ifndef MEMORY_BANK_FLATTEN_FABRIC_BITSTREAM_H +#define MEMORY_BANK_FLATTEN_FABRIC_BITSTREAM_H + +#include +#include +#include +#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 bl_vector(const std::vector& wl_vec) const; + + /* @brief Return all the WL vectors in a downloaded sequence */ + std::vector> wl_vectors() const; + + public: /* Mutators */ + /* @brief add a pair of BL/WL vectors to the bitstream database */ + void add_blwl_vectors(const std::vector& bl_vec, + const std::vector& 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> bitstream_; +}; + +} /* end namespace openfpga */ + +#endif diff --git a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp index ee1b3deda..a25b5ad02 100644 --- a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp @@ -199,14 +199,8 @@ int write_memory_bank_flatten_fabric_bitstream_to_text_file(std::fstream& fp, /* The address sizes and data input sizes are the same across any element, * just get it from the 1st element to save runtime */ - size_t bl_addr_size = 0; - for (const auto& bl_vec : fabric_bits.begin()->second) { - bl_addr_size += bl_vec.size(); - } - size_t wl_addr_size = 0; - for (const auto& wl_vec : fabric_bits.begin()->first) { - wl_addr_size += wl_vec.size(); - } + size_t bl_addr_size = fabric_bits.bl_vector_size(); + size_t wl_addr_size = fabric_bits.wl_vector_size(); /* Output information about how to intepret the bitstream */ fp << "// Bitstream length: " << fabric_bits.size() << std::endl; @@ -215,14 +209,55 @@ int write_memory_bank_flatten_fabric_bitstream_to_text_file(std::fstream& fp, fp << ""; fp << std::endl; - for (const auto& addr_pair : fabric_bits) { + for (const auto& wl_vec : fabric_bits.wl_vectors()) { /* Write BL address code */ - for (const auto& bl_vec : addr_pair.second) { - fp << bl_vec; + for (const auto& bl_unit : fabric_bits.bl_vector(wl_vec)) { + fp << bl_unit; } /* Write WL address code */ - for (const auto& wl_vec : addr_pair.first) { - fp << wl_vec; + for (const auto& wl_unit : wl_vec) { + fp << wl_unit; + } + fp << std::endl; + } + + 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& bit_value_to_skip, + const FabricBitstream& fabric_bitstream) { + int status = 0; + + MemoryBankFlattenFabricBitstream fabric_bits = build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, bit_value_to_skip); + + size_t bl_addr_size = fabric_bits.bl_vector_size(); + size_t wl_addr_size = fabric_bits.wl_vector_size(); + + /* Output information about how to intepret the bitstream */ + fp << "// Bitstream length: " << fabric_bits.size() << std::endl; + fp << "// Bitstream width (LSB -> MSB): "; + fp << ""; + fp << ""; + fp << std::endl; + + for (const auto& wl_vec : fabric_bits.wl_vectors()) { + /* Write BL address code */ + for (const auto& bl_unit : fabric_bits.bl_vector(wl_vec)) { + fp << bl_unit; + } + /* Write WL address code */ + for (const auto& wl_unit : wl_vec) { + fp << wl_unit; } fp << std::endl; } @@ -369,12 +404,15 @@ int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manage apply_fast_configuration, bit_value_to_skip, fabric_bitstream); - } else { - VTR_ASSERT(BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type() - || BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()); + } else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) { status = write_memory_bank_flatten_fabric_bitstream_to_text_file(fp, 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, + bit_value_to_skip, + fabric_bitstream); } break; } diff --git a/openfpga/src/utils/fabric_bitstream_utils.cpp b/openfpga/src/utils/fabric_bitstream_utils.cpp index 2df7bcb23..b300919a4 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.cpp +++ b/openfpga/src/utils/fabric_bitstream_utils.cpp @@ -313,7 +313,7 @@ MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(cons } } /* 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; diff --git a/openfpga/src/utils/fabric_bitstream_utils.h b/openfpga/src/utils/fabric_bitstream_utils.h index ad14aef74..d21c9c12e 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.h +++ b/openfpga/src/utils/fabric_bitstream_utils.h @@ -10,6 +10,7 @@ #include #include #include "bitstream_manager.h" +#include "memory_bank_flatten_fabric_bitstream.h" #include "fabric_bitstream.h" /******************************************************************** @@ -37,10 +38,6 @@ FrameFabricBitstream build_frame_based_fabric_bitstream_by_address(const FabricB size_t find_frame_based_fast_configuration_fabric_bitstream_size(const FabricBitstream& fabric_bitstream, const bool& bit_value_to_skip); -/* Must use (WL, BL) as pairs in the map!!! - * This is because BL data may not be unique while WL must be unique - */ -typedef std::map, std::vector> MemoryBankFlattenFabricBitstream; /******************************************************************** * @ brief Reorganize the fabric bitstream for memory banks which use flatten or shift register to manipulate BL and WLs * For each configuration region, we will merge BL address (which are 1-hot codes) under the same WL address From 4526133089e99694980c4c7fed040fdb9683ee1a Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 30 Sep 2021 17:01:02 -0700 Subject: [PATCH 21/52] [FPGA-Bitstream] Add a new data structure that stores fabric bitstream for memory bank using shift registers --- ...y_bank_shift_register_fabric_bitstream.cpp | 77 +++++++++++++++ ...ory_bank_shift_register_fabric_bitstream.h | 93 +++++++++++++++++++ ...bank_shift_register_fabric_bitstream_fwd.h | 23 +++++ 3 files changed, 193 insertions(+) create mode 100644 openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.cpp create mode 100644 openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.h create mode 100644 openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream_fwd.h diff --git a/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.cpp new file mode 100644 index 000000000..06c3c4aea --- /dev/null +++ b/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.cpp @@ -0,0 +1,77 @@ +#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::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::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 MemoryBankShiftRegisterFabricBitstream::bl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const { + VTR_ASSERT(valid_word_id(word_id)); + return bitstream_word_bls_[word_id]; +} + +std::vector 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)); + VTR_ASSERT(bl_vec.size() == bl_width()); + 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)); + VTR_ASSERT(wl_vec.size() == wl_width()); + 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 */ diff --git a/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.h b/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.h new file mode 100644 index 000000000..b6355ccad --- /dev/null +++ b/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.h @@ -0,0 +1,93 @@ +#ifndef MEMORY_BANK_SHIFT_REGISTER_FABRIC_BITSTREAM_H +#define MEMORY_BANK_SHIFT_REGISTER_FABRIC_BITSTREAM_H + +#include +#include +#include +#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::const_iterator word_iterator; + /* Create range */ + typedef vtr::Range 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 each word. All the word should have a uniform size */ + size_t 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 bl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const; + + /* @brief Return the WL vectors in a given word id */ + std::vector 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 bitstream_word_ids_; + vtr::vector> bitstream_word_bls_; + vtr::vector> bitstream_word_wls_; +}; + +} /* end namespace openfpga */ + +#endif diff --git a/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream_fwd.h b/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream_fwd.h new file mode 100644 index 000000000..87c1ebad2 --- /dev/null +++ b/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream_fwd.h @@ -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 MemoryBankShiftRegisterFabricBitstreamWordId; + +class MemoryBankShiftRegisterFabricBitstream; + +} /* end namespace openfpga */ + +#endif From 33972fc0ec11d73ec892ff852bd9f0ebfb98d8af Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 30 Sep 2021 21:05:41 -0700 Subject: [PATCH 22/52] [FPGA-Bitstream] Upgraded bitstream writer to support QuickLogic memory bank using shift registers --- .../fabric/build_top_module_memory_bank.cpp | 13 ++++- .../memory_bank_shift_register_banks.cpp | 49 ++++++++++------- .../fabric/memory_bank_shift_register_banks.h | 12 +++- ...y_bank_shift_register_fabric_bitstream.cpp | 12 +++- ...ory_bank_shift_register_fabric_bitstream.h | 3 + .../write_text_fabric_bitstream.cpp | 27 ++++----- openfpga/src/utils/fabric_bitstream_utils.cpp | 55 +++++++++++++++++++ openfpga/src/utils/fabric_bitstream_utils.h | 37 ++++++++++++- 8 files changed, 166 insertions(+), 42 deletions(-) diff --git a/openfpga/src/fabric/build_top_module_memory_bank.cpp b/openfpga/src/fabric/build_top_module_memory_bank.cpp index dd2bdf29b..206a70728 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.cpp +++ b/openfpga/src/fabric/build_top_module_memory_bank.cpp @@ -1323,13 +1323,19 @@ void add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(Module 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 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_sink_blwls(config_region, sr_bank_module, cur_inst, bl_pin_id); } } } @@ -1409,13 +1415,18 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(Module 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 coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id]; - /* Find the BL port */ + 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_sink_blwls(config_region, sr_bank_module, cur_inst, wl_pin_id); } } } diff --git a/openfpga/src/fabric/memory_bank_shift_register_banks.cpp b/openfpga/src/fabric/memory_bank_shift_register_banks.cpp index 0d4902936..aac8989fe 100644 --- a/openfpga/src/fabric/memory_bank_shift_register_banks.cpp +++ b/openfpga/src/fabric/memory_bank_shift_register_banks.cpp @@ -7,7 +7,7 @@ namespace openfpga { std::vector MemoryBankShiftRegisterBanks::shift_register_bank_unique_modules() const { std::vector sr_bank_modules; - for (const auto& region : sr_instance_info_) { + 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); @@ -20,7 +20,7 @@ std::vector MemoryBankShiftRegisterBanks::shift_register_bank_unique_m std::vector MemoryBankShiftRegisterBanks::shift_register_bank_modules(const ConfigRegionId& region) const { std::vector sr_bank_modules; VTR_ASSERT(valid_region_id(region)); - for (const auto& pair : sr_instance_info_[region]) { + for (const auto& pair : sr_instance_sink_child_ids_[region]) { sr_bank_modules.push_back(pair.first.first); } return sr_bank_modules; @@ -29,7 +29,7 @@ std::vector MemoryBankShiftRegisterBanks::shift_register_bank_modules( std::vector MemoryBankShiftRegisterBanks::shift_register_bank_instances(const ConfigRegionId& region) const { std::vector sr_bank_instances; VTR_ASSERT(valid_region_id(region)); - for (const auto& pair : sr_instance_info_[region]) { + for (const auto& pair : sr_instance_sink_child_ids_[region]) { sr_bank_instances.push_back(pair.first.second); } return sr_bank_instances; @@ -39,43 +39,41 @@ std::vector MemoryBankShiftRegisterBanks::shift_register_bank_sink_child const ModuleId& sr_module, const size_t& sr_instance) const { VTR_ASSERT(valid_region_id(region)); - std::vector sink_child_ids; - auto result = sr_instance_info_[region].find(std::make_pair(sr_module, sr_instance)); + 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_info_[region].end()) { - for (const auto& sink_child : result->second) { - sink_child_ids.push_back(sink_child.first); - } + if (result != sr_instance_sink_child_ids_[region].end()) { + return result->second; } - return sink_child_ids; + return std::vector(); } std::vector MemoryBankShiftRegisterBanks::shift_register_bank_sink_pin_ids(const ConfigRegionId& region, const ModuleId& sr_module, const size_t& sr_instance) const { VTR_ASSERT(valid_region_id(region)); - std::vector sink_child_pin_ids; - auto result = sr_instance_info_[region].find(std::make_pair(sr_module, sr_instance)); + 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_info_[region].end()) { - for (const auto& sink_child : result->second) { - sink_child_pin_ids.push_back(sink_child.second); - } + if (result != sr_instance_sink_child_pin_ids_[region].end()) { + return result->second; } - return sink_child_pin_ids; + return std::vector(); } void MemoryBankShiftRegisterBanks::resize_regions(const size_t& num_regions) { - sr_instance_info_.resize(num_regions); + sr_instance_sink_child_ids_.resize(num_regions); + sr_instance_sink_child_pin_ids_.resize(num_regions); + sr_instance_sink_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_info_[region][std::make_pair(sr_module, sr_instance)]; + 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_sink_blwl_ids_[region][std::make_pair(sr_module, sr_instance)]; } void MemoryBankShiftRegisterBanks::add_shift_register_sink_nodes(const ConfigRegionId& region, @@ -84,11 +82,20 @@ void MemoryBankShiftRegisterBanks::add_shift_register_sink_nodes(const ConfigReg const size_t& sink_child_id, const size_t& sink_child_pin_id) { VTR_ASSERT(valid_region_id(region)); - sr_instance_info_[region][std::make_pair(sr_module, sr_instance)].push_back(std::make_pair(sink_child_id, sink_child_pin_id)); + 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_sink_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_sink_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_info_.size(); + return size_t(region) < sr_instance_sink_child_ids_.size(); } } /* end namespace openfpga */ diff --git a/openfpga/src/fabric/memory_bank_shift_register_banks.h b/openfpga/src/fabric/memory_bank_shift_register_banks.h index 59c92fef7..a145aca5e 100644 --- a/openfpga/src/fabric/memory_bank_shift_register_banks.h +++ b/openfpga/src/fabric/memory_bank_shift_register_banks.h @@ -52,18 +52,26 @@ class MemoryBankShiftRegisterBanks { const ModuleId& sr_module, const size_t& sr_instance); - /* @brief Add the module id and instance id of a shift register under a specific configuration region of top-level module */ + /* @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_sink_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, std::vector>>> sr_instance_info_; + vtr::vector, std::vector>> sr_instance_sink_child_ids_; + vtr::vector, std::vector>> sr_instance_sink_child_pin_ids_; + vtr::vector, std::vector>> sr_instance_sink_blwl_ids_; }; } /* end namespace openfpga */ diff --git a/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.cpp index 06c3c4aea..9d5f5fe63 100644 --- a/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.cpp @@ -43,6 +43,16 @@ std::vector MemoryBankShiftRegisterFabricBitstream::wl_vectors(cons return bitstream_word_wls_[word_id]; } +std::vector MemoryBankShiftRegisterFabricBitstream::blwl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const { + VTR_ASSERT(valid_word_id(word_id)); + std::vector blwl_vec = bitstream_word_bls_[word_id]; + VTR_ASSERT(blwl_vec.size() == bitstream_word_wls_[word_id].size()); + for (size_t iwl = 0; iwl < bitstream_word_wls_[word_id].size(); ++iwl) { + blwl_vec[iwl] += bitstream_word_wls_[word_id][iwl]; + } + return blwl_vec; +} + MemoryBankShiftRegisterFabricBitstreamWordId MemoryBankShiftRegisterFabricBitstream::create_word() { /* Create a new id*/ MemoryBankShiftRegisterFabricBitstreamWordId word_id = MemoryBankShiftRegisterFabricBitstreamWordId(bitstream_word_ids_.size()); @@ -59,14 +69,12 @@ MemoryBankShiftRegisterFabricBitstreamWordId MemoryBankShiftRegisterFabricBitstr void MemoryBankShiftRegisterFabricBitstream::add_bl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id, const std::string& bl_vec) { VTR_ASSERT(valid_word_id(word_id)); - VTR_ASSERT(bl_vec.size() == bl_width()); 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)); - VTR_ASSERT(wl_vec.size() == wl_width()); return bitstream_word_wls_[word_id].push_back(wl_vec); } diff --git a/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.h b/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.h index b6355ccad..1355a8274 100644 --- a/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.h +++ b/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.h @@ -43,6 +43,9 @@ class MemoryBankShiftRegisterFabricBitstream { /* @brief Return the WL vectors in a given word id */ std::vector wl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const; + /* @brief Return the pair of BL and WL vectors in a given word id */ + std::vector blwl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const; + public: /* Mutators */ /* @brief Create a new word */ MemoryBankShiftRegisterFabricBitstreamWordId create_word(); diff --git a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp index a25b5ad02..3c6de650f 100644 --- a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp @@ -238,26 +238,23 @@ int write_memory_bank_shift_register_fabric_bitstream_to_text_file(std::fstream& const FabricBitstream& fabric_bitstream) { int status = 0; - MemoryBankFlattenFabricBitstream fabric_bits = build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, bit_value_to_skip); - - size_t bl_addr_size = fabric_bits.bl_vector_size(); - size_t wl_addr_size = fabric_bits.wl_vector_size(); + MemoryBankShiftRegisterFabricBitstream fabric_bits = build_memory_bank_shift_register_fabric_bitstream(fabric_bitstream, bit_value_to_skip); /* Output information about how to intepret the bitstream */ - fp << "// Bitstream length: " << fabric_bits.size() << std::endl; + fp << "// Bitstream word count: " << fabric_bits.num_words() << std::endl; + fp << "// Bitstream word size: " << fabric_bits.word_size() << std::endl; fp << "// Bitstream width (LSB -> MSB): "; - fp << ""; - fp << ""; + fp << ""; + fp << ""; fp << std::endl; - for (const auto& wl_vec : fabric_bits.wl_vectors()) { - /* Write BL address code */ - for (const auto& bl_unit : fabric_bits.bl_vector(wl_vec)) { - fp << bl_unit; - } - /* Write WL address code */ - for (const auto& wl_unit : wl_vec) { - fp << wl_unit; + size_t word_cnt = 0; + + for (const auto& word : fabric_bits.words()) { + fp << "// Word " << word_cnt << std::endl; + /* Write BL/WL address code */ + for (const auto& blwl_vec : fabric_bits.blwl_vectors(word)) { + fp << blwl_vec; } fp << std::endl; } diff --git a/openfpga/src/utils/fabric_bitstream_utils.cpp b/openfpga/src/utils/fabric_bitstream_utils.cpp index b300919a4..6ad0017a7 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.cpp +++ b/openfpga/src/utils/fabric_bitstream_utils.cpp @@ -319,6 +319,61 @@ MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(cons return fabric_bits; } +MemoryBankShiftRegisterFabricBitstream build_memory_bank_shift_register_fabric_bitstream(const FabricBitstream& fabric_bitstream, + //const std::array& blwl_sr_banks, + const bool& bit_value_to_skip) { + MemoryBankFlattenFabricBitstream raw_fabric_bits = build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, bit_value_to_skip); + MemoryBankShiftRegisterFabricBitstream fabric_bits; + + /* Iterate over each word */ + for (const auto& wl_vec : raw_fabric_bits.wl_vectors()) { + std::vector bl_vec = raw_fabric_bits.bl_vector(wl_vec); + /* Find the max sizes of BL/WL bits, this determines the size of shift register chain */ + size_t max_blwl_sizes = 0; + for (const auto& bl_bits : bl_vec) { + max_blwl_sizes = std::max(max_blwl_sizes, bl_bits.size()); + } + for (const auto& wl_bits : wl_vec) { + max_blwl_sizes = std::max(max_blwl_sizes, wl_bits.size()); + } + /* Reshape the BL and WL vectors */ + std::vector reshaped_blwls(bl_vec.size() + wl_vec.size(), std::string(max_blwl_sizes, '0')); + size_t blwl_col_cnt = 0; + for (const auto& bl_bits : bl_vec) { + size_t offset = max_blwl_sizes - bl_vec.size(); + for (const char& bl_bit : bl_bits) { + reshaped_blwls[blwl_col_cnt][offset] = bl_bit; + offset++; + } + blwl_col_cnt++; + } + for (const auto& wl_bits : wl_vec) { + size_t offset = max_blwl_sizes - wl_vec.size(); + for (const char& wl_bit : wl_bits) { + reshaped_blwls[blwl_col_cnt][offset] = wl_bit; + offset++; + } + blwl_col_cnt++; + } + /* Add the word to final bitstream */ + MemoryBankShiftRegisterFabricBitstreamWordId word_id = fabric_bits.create_word(); + for (size_t irow = 0; irow < max_blwl_sizes; ++irow) { + std::string cur_bl_vec; + for (size_t icol = 0; icol < bl_vec.size(); ++icol) { + cur_bl_vec.push_back(reshaped_blwls[icol][irow]); + } + fabric_bits.add_bl_vectors(word_id, cur_bl_vec); + + std::string cur_wl_vec; + for (size_t icol = bl_vec.size(); icol < bl_vec.size() + wl_vec.size(); ++icol) { + cur_wl_vec.push_back(reshaped_blwls[icol][irow]); + } + fabric_bits.add_wl_vectors(word_id, cur_wl_vec); + } + } + + return fabric_bits; +} /******************************************************************** * For fast configuration, the number of bits to be skipped diff --git a/openfpga/src/utils/fabric_bitstream_utils.h b/openfpga/src/utils/fabric_bitstream_utils.h index d21c9c12e..9a97a078b 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.h +++ b/openfpga/src/utils/fabric_bitstream_utils.h @@ -9,8 +9,11 @@ *******************************************************************/ #include #include +#include #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" /******************************************************************** @@ -39,7 +42,7 @@ size_t find_frame_based_fast_configuration_fabric_bitstream_size(const FabricBit const bool& bit_value_to_skip); /******************************************************************** - * @ 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 * * Quick Example @@ -61,6 +64,38 @@ size_t find_frame_based_fast_configuration_fabric_bitstream_size(const FabricBit MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream, 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 + * _ _ + * An example: + * 010_111 000_101 + * + * Note that all the BL/WLs across configuration regions are independent. We will combine them together + * Quick Example + * _ _ + * 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: + * + * _ _ + * 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 std::array& blwl_sr_banks, + const bool& bit_value_to_skip); + /* Alias to a specific organization of bitstreams for memory bank configuration protocol */ typedef std::map, std::vector> MemoryBankFabricBitstream; MemoryBankFabricBitstream build_memory_bank_fabric_bitstream_by_address(const FabricBitstream& fabric_bitstream); From 4bdff1554d182b8bffef546eea494dab91dce1d5 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 30 Sep 2021 21:20:56 -0700 Subject: [PATCH 23/52] [Engine] Fixed a critical bug which cause BL/WL sharing in shift-register-based memory bank broken --- .../src/fabric/build_top_module_memory_bank.cpp | 4 ++-- openfpga/src/utils/memory_bank_utils.cpp | 17 ++++++++--------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/openfpga/src/fabric/build_top_module_memory_bank.cpp b/openfpga/src/fabric/build_top_module_memory_bank.cpp index 206a70728..0c646fa55 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.cpp +++ b/openfpga/src/fabric/build_top_module_memory_bank.cpp @@ -1199,6 +1199,8 @@ void add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_blwls(ModuleMan 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); + cur_sr_module_blwl_pin_id = cur_sr_module_blwl_pin_id % sr_module_blwl_port_info.get_width(); + /* Create net */ ModuleNetId net = create_module_source_pin_net(module_manager, top_module, sr_bank_module, sr_bank_instance, @@ -1210,8 +1212,6 @@ void add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_blwls(ModuleMan 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); - - cur_sr_module_blwl_pin_id++; } } } diff --git a/openfpga/src/utils/memory_bank_utils.cpp b/openfpga/src/utils/memory_bank_utils.cpp index dcb224fc6..98f0ffca6 100644 --- a/openfpga/src/utils/memory_bank_utils.cpp +++ b/openfpga/src/utils/memory_bank_utils.cpp @@ -90,11 +90,10 @@ size_t compute_memory_bank_regional_num_bls(const ModuleManager& module_manager, const CircuitLibrary& circuit_lib, const CircuitModelId& sram_model) { size_t num_bls = 0; - - 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 coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id]; - num_bls += find_module_ql_memory_bank_num_blwls(module_manager, child_module, circuit_lib, sram_model, CONFIG_MEM_QL_MEMORY_BANK, CIRCUIT_MODEL_PORT_BL); + std::map 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; @@ -123,10 +122,10 @@ size_t compute_memory_bank_regional_num_wls(const ModuleManager& module_manager, const CircuitModelId& sram_model) { size_t num_wls = 0; - 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 coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id]; - num_wls += find_module_ql_memory_bank_num_blwls(module_manager, child_module, circuit_lib, sram_model, CONFIG_MEM_QL_MEMORY_BANK, CIRCUIT_MODEL_PORT_WL); + std::map 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; From 96828e456a5c4acdf32492462ec8501835462e58 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 30 Sep 2021 22:07:46 -0700 Subject: [PATCH 24/52] [FPGA-Bitstream] Fixed a critical bug which cause reshaping bitstream wrong --- .../write_text_fabric_bitstream.cpp | 5 +++-- openfpga/src/utils/fabric_bitstream_utils.cpp | 18 ++++++------------ 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp index 3c6de650f..58e5fd5bb 100644 --- a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp @@ -244,7 +244,7 @@ int write_memory_bank_shift_register_fabric_bitstream_to_text_file(std::fstream& fp << "// Bitstream word count: " << fabric_bits.num_words() << std::endl; fp << "// Bitstream word size: " << fabric_bits.word_size() << std::endl; fp << "// Bitstream width (LSB -> MSB): "; - fp << ""; + fp << ""; fp << ""; fp << std::endl; @@ -255,8 +255,9 @@ int write_memory_bank_shift_register_fabric_bitstream_to_text_file(std::fstream& /* Write BL/WL address code */ for (const auto& blwl_vec : fabric_bits.blwl_vectors(word)) { fp << blwl_vec; + fp << std::endl; } - fp << std::endl; + word_cnt++; } return status; diff --git a/openfpga/src/utils/fabric_bitstream_utils.cpp b/openfpga/src/utils/fabric_bitstream_utils.cpp index 6ad0017a7..d82d09ded 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.cpp +++ b/openfpga/src/utils/fabric_bitstream_utils.cpp @@ -337,22 +337,16 @@ MemoryBankShiftRegisterFabricBitstream build_memory_bank_shift_register_fabric_b max_blwl_sizes = std::max(max_blwl_sizes, wl_bits.size()); } /* Reshape the BL and WL vectors */ - std::vector reshaped_blwls(bl_vec.size() + wl_vec.size(), std::string(max_blwl_sizes, '0')); + std::vector reshaped_blwls(bl_vec.size() + wl_vec.size(), std::string()); size_t blwl_col_cnt = 0; for (const auto& bl_bits : bl_vec) { - size_t offset = max_blwl_sizes - bl_vec.size(); - for (const char& bl_bit : bl_bits) { - reshaped_blwls[blwl_col_cnt][offset] = bl_bit; - offset++; - } + reshaped_blwls[blwl_col_cnt].resize(max_blwl_sizes - bl_bits.size(), '0'); + reshaped_blwls[blwl_col_cnt] += bl_bits; blwl_col_cnt++; } for (const auto& wl_bits : wl_vec) { - size_t offset = max_blwl_sizes - wl_vec.size(); - for (const char& wl_bit : wl_bits) { - reshaped_blwls[blwl_col_cnt][offset] = wl_bit; - offset++; - } + reshaped_blwls[blwl_col_cnt].resize(max_blwl_sizes - wl_bits.size(), '0'); + reshaped_blwls[blwl_col_cnt] += wl_bits; blwl_col_cnt++; } /* Add the word to final bitstream */ @@ -362,7 +356,7 @@ MemoryBankShiftRegisterFabricBitstream build_memory_bank_shift_register_fabric_b for (size_t icol = 0; icol < bl_vec.size(); ++icol) { cur_bl_vec.push_back(reshaped_blwls[icol][irow]); } - fabric_bits.add_bl_vectors(word_id, cur_bl_vec); + fabric_bits.add_bl_vectors(word_id, cur_bl_vec); std::string cur_wl_vec; for (size_t icol = bl_vec.size(); icol < bl_vec.size() + wl_vec.size(); ++icol) { From fa57117f5045ca19c5464303b8ffed55aeb1f887 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 1 Oct 2021 10:19:51 -0700 Subject: [PATCH 25/52] [Arch] Update openfpga architecture examples by adding syntax to identify clocks used by shift registers --- .../openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml | 4 ++-- .../openfpga_arch/k4_N4_40nm_qlbanksr_wlr_openfpga.xml | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml index 25f5261d9..ce848d2e7 100644 --- a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml +++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml @@ -173,7 +173,7 @@ - + @@ -184,7 +184,7 @@ - + diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_wlr_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_wlr_openfpga.xml index 9c8e0964c..43d716222 100644 --- a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_wlr_openfpga.xml +++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_wlr_openfpga.xml @@ -170,23 +170,23 @@ - + - + - + - + From 7b010ba0f4ebc713f3403876a58eacaf4bfd556f Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 1 Oct 2021 11:00:38 -0700 Subject: [PATCH 26/52] [Engine] Support programming shift register clock in XML syntax --- .../libarchopenfpga/src/circuit_library.cpp | 18 ++++++- .../libarchopenfpga/src/circuit_library.h | 4 ++ .../src/read_xml_circuit_library.cpp | 3 ++ .../src/read_xml_simulation_setting.cpp | 45 +++++++++++++++- .../src/simulation_setting.cpp | 54 +++++++++++++++++++ .../libarchopenfpga/src/simulation_setting.h | 11 ++++ .../src/write_xml_circuit_library.cpp | 4 ++ .../src/write_xml_simulation_setting.cpp | 19 +++++-- .../src/fabric/fabric_global_port_info.cpp | 12 +++++ openfpga/src/fabric/fabric_global_port_info.h | 4 ++ openfpga/src/fpga_sdc/pnr_sdc_global_port.cpp | 2 +- .../fpga_verilog/verilog_testbench_utils.cpp | 2 +- .../fpga_verilog/verilog_top_testbench.cpp | 10 ++-- .../auto_shift_register_sim_openfpga.xml | 41 ++++++++++++++ 14 files changed, 217 insertions(+), 12 deletions(-) create mode 100644 openfpga_flow/openfpga_simulation_settings/auto_shift_register_sim_openfpga.xml diff --git a/libopenfpga/libarchopenfpga/src/circuit_library.cpp b/libopenfpga/libarchopenfpga/src/circuit_library.cpp index 4195158d4..e6b1f248e 100644 --- a/libopenfpga/libarchopenfpga/src/circuit_library.cpp +++ b/libopenfpga/libarchopenfpga/src/circuit_library.cpp @@ -949,7 +949,6 @@ bool CircuitLibrary::port_is_config_enable(const CircuitPortId& 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 */ bool CircuitLibrary::port_is_prog(const CircuitPortId& circuit_port_id) const { /* 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 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 */ size_t CircuitLibrary::port_lut_frac_level(const CircuitPortId& circuit_port_id) const { /* 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_config_enable_.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_ids_.push_back(CircuitModelId::INVALID()); port_inv_model_names_.emplace_back(); @@ -1538,6 +1545,15 @@ void CircuitLibrary::set_port_is_prog(const CircuitPortId& circuit_port_id, 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 */ void CircuitLibrary::set_port_tri_state_model_name(const CircuitPortId& circuit_port_id, const std::string& model_name) { diff --git a/libopenfpga/libarchopenfpga/src/circuit_library.h b/libopenfpga/libarchopenfpga/src/circuit_library.h index d2feee52b..ffd2f1661 100644 --- a/libopenfpga/libarchopenfpga/src/circuit_library.h +++ b/libopenfpga/libarchopenfpga/src/circuit_library.h @@ -288,6 +288,7 @@ class CircuitLibrary { bool port_is_set(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_shift_register(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; std::vector port_lut_output_mask(const CircuitPortId& circuit_port_id) const; @@ -372,6 +373,8 @@ class CircuitLibrary { const bool& is_config_enable); void set_port_is_prog(const CircuitPortId& circuit_port_id, 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, const std::string& model_name); void set_port_tri_state_model_id(const CircuitPortId& circuit_port_id, @@ -560,6 +563,7 @@ class CircuitLibrary { vtr::vector port_is_set_; vtr::vector port_is_config_enable_; vtr::vector port_is_prog_; + vtr::vector port_is_shift_register_; vtr::vector port_tri_state_model_names_; vtr::vector port_tri_state_model_ids_; vtr::vector port_inv_model_names_; diff --git a/libopenfpga/libarchopenfpga/src/read_xml_circuit_library.cpp b/libopenfpga/libarchopenfpga/src/read_xml_circuit_library.cpp index 4fc3ddbb4..0137f961b 100644 --- a/libopenfpga/libarchopenfpga/src/read_xml_circuit_library.cpp +++ b/libopenfpga/libarchopenfpga/src/read_xml_circuit_library.cpp @@ -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 */ 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 */ circuit_lib.set_port_is_config_enable(port, get_attribute(xml_port, "is_config_enable", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false)); diff --git a/libopenfpga/libarchopenfpga/src/read_xml_simulation_setting.cpp b/libopenfpga/libarchopenfpga/src/read_xml_simulation_setting.cpp index b9ea51859..a76f2f2ff 100644 --- a/libopenfpga/libarchopenfpga/src/read_xml_simulation_setting.cpp +++ b/libopenfpga/libarchopenfpga/src/read_xml_simulation_setting.cpp @@ -36,7 +36,7 @@ e_sim_accuracy_type string_to_sim_accuracy_type(const std::string& type_string) } /******************************************************************** - * Parse XML codes of a line to an object of simulation setting + * Parse XML codes of a line under to an object of simulation setting *******************************************************************/ static 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.)); } +/******************************************************************** + * Parse XML codes of a line under 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 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); 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); + } } /******************************************************************** diff --git a/libopenfpga/libarchopenfpga/src/simulation_setting.cpp b/libopenfpga/libarchopenfpga/src/simulation_setting.cpp index 88b398441..92296fe8f 100644 --- a/libopenfpga/libarchopenfpga/src/simulation_setting.cpp +++ b/libopenfpga/libarchopenfpga/src/simulation_setting.cpp @@ -16,6 +16,36 @@ SimulationSetting::simulation_clock_range SimulationSetting::clocks() const { return vtr::make_range(clock_ids_.begin(), clock_ids_.end()); } +std::vector SimulationSetting::operating_clocks() const { + std::vector op_clks; + for (const SimulationClockId& clk : clocks()) { + if (!clock_is_programming(clk)) { + op_clks.push_back(clk); + } + } + return op_clks; +} + +std::vector SimulationSetting::programming_clocks() const { + std::vector prog_clks; + for (const SimulationClockId& clk : clocks()) { + if (clock_is_programming(clk)) { + prog_clks.push_back(clk); + } + } + return prog_clks; +} + +std::vector SimulationSetting::programming_shift_register_clocks() const { + std::vector 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 ***********************************************************************/ @@ -53,6 +83,16 @@ float SimulationSetting::clock_frequency(const SimulationClockId& clock_id) cons 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 { return 0 == num_clock_cycles_; } @@ -157,6 +197,8 @@ SimulationClockId SimulationSetting::create_clock(const std::string& name) { clock_names_.push_back(name); clock_ports_.emplace_back(); 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 */ clock_name2ids_[name] = clock_id; @@ -176,6 +218,18 @@ void SimulationSetting::set_clock_frequency(const SimulationClockId& clock_id, 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) { num_clock_cycles_ = num_clk_cycles; } diff --git a/libopenfpga/libarchopenfpga/src/simulation_setting.h b/libopenfpga/libarchopenfpga/src/simulation_setting.h index 2447cfd3d..5625acdea 100644 --- a/libopenfpga/libarchopenfpga/src/simulation_setting.h +++ b/libopenfpga/libarchopenfpga/src/simulation_setting.h @@ -62,6 +62,9 @@ class SimulationSetting { SimulationSetting(); public: /* Accessors: aggregates */ simulation_clock_range clocks() const; + std::vector operating_clocks() const; + std::vector programming_clocks() const; + std::vector programming_shift_register_clocks() const; public: /* Public Accessors */ float default_operating_clock_frequency() const; float programming_clock_frequency() const; @@ -69,6 +72,8 @@ class SimulationSetting { std::string clock_name(const SimulationClockId& clock_id) const; BasicPort clock_port(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; size_t num_clock_cycles() const; float operating_clock_frequency_slack() const; @@ -102,6 +107,10 @@ class SimulationSetting { const BasicPort& port); void set_clock_frequency(const SimulationClockId& clock_id, 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_operating_clock_frequency_slack(const float& op_clk_freq_slack); void set_simulation_temperature(const float& sim_temp); @@ -150,6 +159,8 @@ class SimulationSetting { vtr::vector clock_names_; vtr::vector clock_ports_; vtr::vector clock_frequencies_; + vtr::vector clock_is_programming_; + vtr::vector clock_is_shift_register_; /* Fast name-to-id lookup */ std::map clock_name2ids_; diff --git a/libopenfpga/libarchopenfpga/src/write_xml_circuit_library.cpp b/libopenfpga/libarchopenfpga/src/write_xml_circuit_library.cpp index f96780a92..a9314713d 100644 --- a/libopenfpga/libarchopenfpga/src/write_xml_circuit_library.cpp +++ b/libopenfpga/libarchopenfpga/src/write_xml_circuit_library.cpp @@ -220,6 +220,10 @@ void write_xml_circuit_port(std::fstream& fp, 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)) { write_xml_attribute(fp, "is_config_enable", "true"); } diff --git a/libopenfpga/libarchopenfpga/src/write_xml_simulation_setting.cpp b/libopenfpga/libarchopenfpga/src/write_xml_simulation_setting.cpp index dc68f1924..3f8129908 100644 --- a/libopenfpga/libarchopenfpga/src/write_xml_simulation_setting.cpp +++ b/libopenfpga/libarchopenfpga/src/write_xml_simulation_setting.cpp @@ -41,7 +41,7 @@ void write_xml_clock_setting(std::fstream& fp, fp << ">" << "\n"; /* 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" << "" << "\n"; - fp << "\t\t" << "" << "\n"; + fp << ">" << "\n"; + + /* Output clock information one by one */ + for (const SimulationClockId& clock_id : sim_setting.programming_clocks()) { + fp << "\t\t\t" << "" << "\n"; + } + + fp << "\t\t" << "" << "\n"; fp << "\t" << "" << "\n"; } diff --git a/openfpga/src/fabric/fabric_global_port_info.cpp b/openfpga/src/fabric/fabric_global_port_info.cpp index 08ea8444d..60ef72d94 100644 --- a/openfpga/src/fabric/fabric_global_port_info.cpp +++ b/openfpga/src/fabric/fabric_global_port_info.cpp @@ -50,6 +50,11 @@ bool FabricGlobalPortInfo::global_port_is_prog(const FabricGlobalPortId& global_ 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_config_enable(const FabricGlobalPortId& global_port_id) const { VTR_ASSERT(valid_global_port_id(global_port_id)); return global_port_is_config_enable_[global_port_id]; @@ -77,6 +82,7 @@ FabricGlobalPortId FabricGlobalPortInfo::create_global_port(const ModulePortId& global_port_is_set_.push_back(false); global_port_is_reset_.push_back(false); global_port_is_prog_.push_back(false); + global_port_is_shift_register_.push_back(false); global_port_is_io_.push_back(false); global_port_is_config_enable_.push_back(false); global_port_default_values_.push_back(0); @@ -108,6 +114,12 @@ void FabricGlobalPortInfo::set_global_port_is_prog(const FabricGlobalPortId& glo 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_config_enable(const FabricGlobalPortId& global_port_id, const bool& is_config_enable) { VTR_ASSERT(valid_global_port_id(global_port_id)); diff --git a/openfpga/src/fabric/fabric_global_port_info.h b/openfpga/src/fabric/fabric_global_port_info.h index 31c67583e..2521308d1 100644 --- a/openfpga/src/fabric/fabric_global_port_info.h +++ b/openfpga/src/fabric/fabric_global_port_info.h @@ -36,6 +36,7 @@ class FabricGlobalPortInfo { 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_prog(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_io(const FabricGlobalPortId& global_port_id) const; size_t global_port_default_value(const FabricGlobalPortId& global_port_id) const; @@ -52,6 +53,8 @@ class FabricGlobalPortInfo { const bool& is_reset); void set_global_port_is_prog(const FabricGlobalPortId& global_port_id, 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_config_enable(const FabricGlobalPortId& global_port_id, const bool& is_config_enable); void set_global_port_is_io(const FabricGlobalPortId& global_port_id, @@ -68,6 +71,7 @@ class FabricGlobalPortInfo { vtr::vector global_port_is_reset_; vtr::vector global_port_is_set_; vtr::vector global_port_is_prog_; + vtr::vector global_port_is_shift_register_; vtr::vector global_port_is_config_enable_; vtr::vector global_port_is_io_; vtr::vector global_port_default_values_; diff --git a/openfpga/src/fpga_sdc/pnr_sdc_global_port.cpp b/openfpga/src/fpga_sdc/pnr_sdc_global_port.cpp index 156f78ff1..28f0b9bbd 100644 --- a/openfpga/src/fpga_sdc/pnr_sdc_global_port.cpp +++ b/openfpga/src/fpga_sdc/pnr_sdc_global_port.cpp @@ -97,7 +97,7 @@ void print_pnr_sdc_global_clock_ports(std::fstream& fp, /* Should try to find a port defintion from simulation parameters * 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)) { clock_period = 1./sim_setting.clock_frequency(sim_clock); } diff --git a/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp b/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp index 3542cdcfc..b47d06d1d 100644 --- a/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp +++ b/openfpga/src/fpga_verilog/verilog_testbench_utils.cpp @@ -515,7 +515,7 @@ void print_verilog_testbench_clock_stimuli(std::fstream& fp, /* Skip all the unrelated pin constraints */ 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 */ - 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)) { clk_freq_to_use = (0.5 / simulation_parameters.clock_frequency(sim_clock_id)) / VERILOG_SIM_TIMESCALE; } diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp index 4b0524308..f3c9fcc54 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp @@ -290,7 +290,7 @@ void print_verilog_top_testbench_global_clock_ports_stimuli(std::fstream& fp, /* Should try to find a port defintion from simulation parameters * 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)) { stimuli_clock_port.set_name(generate_top_testbench_clock_name(std::string(TOP_TB_OP_CLOCK_PORT_PREFIX), simulation_parameters.clock_name(sim_clock))); } @@ -640,7 +640,7 @@ void print_verilog_top_testbench_benchmark_clock_ports(std::fstream& fp, /* Skip all the unrelated pin constraints */ VTR_ASSERT(clock_port_name == pin_constraints.net(pin_constraint)); /* 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)) { 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); @@ -742,7 +742,7 @@ void print_verilog_top_testbench_ports(std::fstream& fp, fp << generate_verilog_port(VERILOG_PORT_REG, prog_clock_register_port) << ";" << std::endl; /* 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)); BasicPort sim_clock_port(sim_clock_port_name, 1); fp << generate_verilog_port(VERILOG_PORT_WIRE, sim_clock_port) << ";" << std::endl; @@ -1010,7 +1010,7 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp, fp << std::endl; /* 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 -----"); 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); @@ -1935,7 +1935,7 @@ int print_verilog_full_testbench(const ModuleManager& module_manager, float prog_clock_period = (1./simulation_parameters.programming_clock_frequency()); float default_op_clock_period = (1./simulation_parameters.default_operating_clock_frequency()); 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))); } diff --git a/openfpga_flow/openfpga_simulation_settings/auto_shift_register_sim_openfpga.xml b/openfpga_flow/openfpga_simulation_settings/auto_shift_register_sim_openfpga.xml new file mode 100644 index 000000000..9b7ffa365 --- /dev/null +++ b/openfpga_flow/openfpga_simulation_settings/auto_shift_register_sim_openfpga.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From dda147e234e45121490ad21de9aa3f61a8d0e891 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 1 Oct 2021 11:04:23 -0700 Subject: [PATCH 27/52] [Flow] Add an example simulation setting file for defining programming shift register clocks --- .../ql_memory_bank_shift_register/config/task.conf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openfpga_flow/tasks/basic_tests/full_testbench/ql_memory_bank_shift_register/config/task.conf b/openfpga_flow/tasks/basic_tests/full_testbench/ql_memory_bank_shift_register/config/task.conf index ba36d7f4c..0e611c666 100644 --- a/openfpga_flow/tasks/basic_tests/full_testbench/ql_memory_bank_shift_register/config/task.conf +++ b/openfpga_flow/tasks/basic_tests/full_testbench/ql_memory_bank_shift_register/config/task.conf @@ -18,7 +18,8 @@ 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_sim_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= From cf96d9ff01061bde5721b2623da20d7efe31858e Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 1 Oct 2021 11:05:31 -0700 Subject: [PATCH 28/52] [Engine] Add programming shift register clock to internal global port data structure --- openfpga/src/fabric/build_fabric_global_port_info.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/openfpga/src/fabric/build_fabric_global_port_info.cpp b/openfpga/src/fabric/build_fabric_global_port_info.cpp index 44a09d199..2c745493a 100644 --- a/openfpga/src/fabric/build_fabric_global_port_info.cpp +++ b/openfpga/src/fabric/build_fabric_global_port_info.cpp @@ -53,6 +53,7 @@ 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_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_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_default_value(fabric_port, circuit_lib.port_default_value(global_port)); } From 2bd2788e775cd30db3ab27393d8e293c17a00e46 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 1 Oct 2021 11:23:40 -0700 Subject: [PATCH 29/52] [Engine] Upgrading testbench generator to support QuickLogic memory bank with shift registers --- .../verilog_top_testbench_memory_bank.cpp | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp index b39f8b1c1..22c135743 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp @@ -61,7 +61,18 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp, } } else { 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; + } } /* Print the address port for the Word-Line decoder here */ @@ -82,7 +93,18 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp, } } else { 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; + } } /* Print the data-input port: only available when BL has a decoder */ From 4f7ab01bf51ffe6889f86b1e001aa126c1fbd78c Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 1 Oct 2021 15:47:13 -0700 Subject: [PATCH 30/52] [FPGA-Bitstream] Reworked the bitstream writer to dump BL/WL words separately --- ...y_bank_shift_register_fabric_bitstream.cpp | 19 ++-- ...ory_bank_shift_register_fabric_bitstream.h | 10 +- .../write_text_fabric_bitstream.cpp | 19 +++- openfpga/src/utils/fabric_bitstream_utils.cpp | 100 ++++++++++++------ 4 files changed, 94 insertions(+), 54 deletions(-) diff --git a/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.cpp index 9d5f5fe63..d758a9141 100644 --- a/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.cpp @@ -12,13 +12,20 @@ size_t MemoryBankShiftRegisterFabricBitstream::num_words() const { return bitstream_word_ids_.size(); } -size_t MemoryBankShiftRegisterFabricBitstream::word_size() const { +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 @@ -43,16 +50,6 @@ std::vector MemoryBankShiftRegisterFabricBitstream::wl_vectors(cons return bitstream_word_wls_[word_id]; } -std::vector MemoryBankShiftRegisterFabricBitstream::blwl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const { - VTR_ASSERT(valid_word_id(word_id)); - std::vector blwl_vec = bitstream_word_bls_[word_id]; - VTR_ASSERT(blwl_vec.size() == bitstream_word_wls_[word_id].size()); - for (size_t iwl = 0; iwl < bitstream_word_wls_[word_id].size(); ++iwl) { - blwl_vec[iwl] += bitstream_word_wls_[word_id][iwl]; - } - return blwl_vec; -} - MemoryBankShiftRegisterFabricBitstreamWordId MemoryBankShiftRegisterFabricBitstream::create_word() { /* Create a new id*/ MemoryBankShiftRegisterFabricBitstreamWordId word_id = MemoryBankShiftRegisterFabricBitstreamWordId(bitstream_word_ids_.size()); diff --git a/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.h b/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.h index 1355a8274..6016da15e 100644 --- a/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.h +++ b/openfpga/src/fpga_bitstream/memory_bank_shift_register_fabric_bitstream.h @@ -28,8 +28,11 @@ class MemoryBankShiftRegisterFabricBitstream { /* @brief Return the length of bitstream */ size_t num_words() const; - /* @brief Return the length of each word. All the word should have a uniform size */ - size_t word_size() 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; @@ -43,9 +46,6 @@ class MemoryBankShiftRegisterFabricBitstream { /* @brief Return the WL vectors in a given word id */ std::vector wl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const; - /* @brief Return the pair of BL and WL vectors in a given word id */ - std::vector blwl_vectors(const MemoryBankShiftRegisterFabricBitstreamWordId& word_id) const; - public: /* Mutators */ /* @brief Create a new word */ MemoryBankShiftRegisterFabricBitstreamWordId create_word(); diff --git a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp index 58e5fd5bb..399abbf28 100644 --- a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp @@ -242,7 +242,8 @@ int write_memory_bank_shift_register_fabric_bitstream_to_text_file(std::fstream& /* Output information about how to intepret the bitstream */ fp << "// Bitstream word count: " << fabric_bits.num_words() << std::endl; - fp << "// Bitstream word size: " << fabric_bits.word_size() << 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 << ""; fp << ""; @@ -252,11 +253,21 @@ int write_memory_bank_shift_register_fabric_bitstream_to_text_file(std::fstream& for (const auto& word : fabric_bits.words()) { fp << "// Word " << word_cnt << std::endl; - /* Write BL/WL address code */ - for (const auto& blwl_vec : fabric_bits.blwl_vectors(word)) { - fp << blwl_vec; + + /* 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++; } diff --git a/openfpga/src/utils/fabric_bitstream_utils.cpp b/openfpga/src/utils/fabric_bitstream_utils.cpp index d82d09ded..448dc02ba 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.cpp +++ b/openfpga/src/utils/fabric_bitstream_utils.cpp @@ -319,6 +319,60 @@ MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(cons 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 reshape_bitstream_vectors_to_last_element(const std::vector& 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 reshaped_vectors(bitstream_vectors.size(), std::string()); + size_t col_cnt = 0; + for (const auto& vec : bitstream_vectors) { + reshaped_vectors[col_cnt].resize(max_vec_size - vec.size(), default_bit_to_fill); + reshaped_vectors[col_cnt] += vec; + col_cnt++; + } + + /* Add the BL word to final bitstream */ + std::vector 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 std::array& blwl_sr_banks, const bool& bit_value_to_skip) { @@ -328,41 +382,19 @@ MemoryBankShiftRegisterFabricBitstream build_memory_bank_shift_register_fabric_b /* Iterate over each word */ for (const auto& wl_vec : raw_fabric_bits.wl_vectors()) { std::vector bl_vec = raw_fabric_bits.bl_vector(wl_vec); - /* Find the max sizes of BL/WL bits, this determines the size of shift register chain */ - size_t max_blwl_sizes = 0; - for (const auto& bl_bits : bl_vec) { - max_blwl_sizes = std::max(max_blwl_sizes, bl_bits.size()); - } - for (const auto& wl_bits : wl_vec) { - max_blwl_sizes = std::max(max_blwl_sizes, wl_bits.size()); - } - /* Reshape the BL and WL vectors */ - std::vector reshaped_blwls(bl_vec.size() + wl_vec.size(), std::string()); - size_t blwl_col_cnt = 0; - for (const auto& bl_bits : bl_vec) { - reshaped_blwls[blwl_col_cnt].resize(max_blwl_sizes - bl_bits.size(), '0'); - reshaped_blwls[blwl_col_cnt] += bl_bits; - blwl_col_cnt++; - } - for (const auto& wl_bits : wl_vec) { - reshaped_blwls[blwl_col_cnt].resize(max_blwl_sizes - wl_bits.size(), '0'); - reshaped_blwls[blwl_col_cnt] += wl_bits; - blwl_col_cnt++; - } - /* Add the word to final bitstream */ - MemoryBankShiftRegisterFabricBitstreamWordId word_id = fabric_bits.create_word(); - for (size_t irow = 0; irow < max_blwl_sizes; ++irow) { - std::string cur_bl_vec; - for (size_t icol = 0; icol < bl_vec.size(); ++icol) { - cur_bl_vec.push_back(reshaped_blwls[icol][irow]); - } - fabric_bits.add_bl_vectors(word_id, cur_bl_vec); - std::string cur_wl_vec; - for (size_t icol = bl_vec.size(); icol < bl_vec.size() + wl_vec.size(); ++icol) { - cur_wl_vec.push_back(reshaped_blwls[icol][irow]); - } - fabric_bits.add_wl_vectors(word_id, cur_wl_vec); + MemoryBankShiftRegisterFabricBitstreamWordId word_id = fabric_bits.create_word(); + + std::vector reshaped_bl_vectors = reshape_bitstream_vectors_to_last_element(bl_vec, '0'); + /* 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 reshaped_wl_vectors = reshape_bitstream_vectors_to_last_element(wl_vec, '0'); + /* 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); } } From 9e5debabe1782a5c343b131c1b20e33243a4efd5 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 1 Oct 2021 16:23:38 -0700 Subject: [PATCH 31/52] [FPGA-Bitstream] Enable fast configuration for QuickLogic memory banks --- .../src/fpga_bitstream/write_text_fabric_bitstream.cpp | 8 ++++++-- openfpga/src/fpga_verilog/verilog_top_testbench.cpp | 2 +- .../fpga_verilog/verilog_top_testbench_memory_bank.cpp | 1 + openfpga/src/utils/fabric_bitstream_utils.cpp | 8 +++++--- openfpga/src/utils/fabric_bitstream_utils.h | 2 ++ 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp index 399abbf28..257cb0e5b 100644 --- a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp @@ -190,11 +190,12 @@ int write_memory_bank_fabric_bitstream_to_text_file(std::fstream& fp, *******************************************************************/ static int write_memory_bank_flatten_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; - 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, * just get it from the 1st element to save runtime @@ -234,11 +235,12 @@ int write_memory_bank_flatten_fabric_bitstream_to_text_file(std::fstream& fp, *******************************************************************/ 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, bit_value_to_skip); + 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; @@ -415,11 +417,13 @@ int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manage fabric_bitstream); } else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) { 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, fabric_bitstream); } diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp index f3c9fcc54..0ef3eebcb 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp @@ -862,7 +862,7 @@ size_t calculate_num_config_clock_cycles(const ConfigProtocol& config_protocol, 100. * ((float)num_config_clock_cycles / (float)full_num_config_clock_cycles - 1.)); } } else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) { - num_config_clock_cycles = 1 + build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, bit_value_to_skip).size(); + 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()) { /* TODO */ } diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp index 22c135743..7618cd510 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp @@ -187,6 +187,7 @@ void print_verilog_full_testbench_ql_memory_bank_flatten_bitstream(std::fstream& /* Reorganize the fabric bitstream by the same address across regions */ MemoryBankFlattenFabricBitstream fabric_bits_by_addr = build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, + fast_configuration, bit_value_to_skip); /* Feed address and data input pair one by one diff --git a/openfpga/src/utils/fabric_bitstream_utils.cpp b/openfpga/src/utils/fabric_bitstream_utils.cpp index 448dc02ba..e09a99672 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.cpp +++ b/openfpga/src/utils/fabric_bitstream_utils.cpp @@ -233,14 +233,15 @@ MemoryBankFabricBitstream build_memory_bank_fabric_bitstream_by_address(const Fa } MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream, + const bool& fast_configuration, const bool& bit_value_to_skip) { /* Build the bitstream by each region, here we use (WL, BL) pairs when storing bitstreams */ vtr::vector> fabric_bits_per_region; fabric_bits_per_region.resize(fabric_bitstream.num_regions()); for (const FabricBitRegionId& region : fabric_bitstream.regions()) { for (const FabricBitId& bit_id : fabric_bitstream.region_bits(region)) { - /* Skip din because they should be pre-configured through programming reset/set */ - if (fabric_bitstream.bit_din(bit_id) == bit_value_to_skip) { + /* Only when fast configuration is required, skip din because they should be pre-configured through programming reset/set */ + if (fast_configuration && fabric_bitstream.bit_din(bit_id) == bit_value_to_skip) { continue; } /* Create string for BL address */ @@ -374,9 +375,10 @@ std::vector reshape_bitstream_vectors_to_last_element(const std::ve } MemoryBankShiftRegisterFabricBitstream build_memory_bank_shift_register_fabric_bitstream(const FabricBitstream& fabric_bitstream, + const bool& fast_configuration, //const std::array& blwl_sr_banks, const bool& bit_value_to_skip) { - MemoryBankFlattenFabricBitstream raw_fabric_bits = build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, 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 */ diff --git a/openfpga/src/utils/fabric_bitstream_utils.h b/openfpga/src/utils/fabric_bitstream_utils.h index 9a97a078b..b45db0c0d 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.h +++ b/openfpga/src/utils/fabric_bitstream_utils.h @@ -62,6 +62,7 @@ size_t find_frame_based_fast_configuration_fabric_bitstream_size(const FabricBit * @note the std::map may cause large memory footprint for large bitstream databases! *******************************************************************/ MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream, + const bool& fast_configuration, const bool& bit_value_to_skip); /******************************************************************** @@ -93,6 +94,7 @@ MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(cons * @note the std::map may cause large memory footprint for large bitstream databases! *******************************************************************/ MemoryBankShiftRegisterFabricBitstream build_memory_bank_shift_register_fabric_bitstream(const FabricBitstream& fabric_bitstream, + const bool& fast_configuration, //const std::array& blwl_sr_banks, const bool& bit_value_to_skip); From ff6f7e80f6c19a0a4d0b9c23252b668019fc6d00 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 1 Oct 2021 16:52:06 -0700 Subject: [PATCH 32/52] [Flow] Modify simulation setting example for QuickLogic memory bank using separated clks for BL and WL shift registers --- .../auto_shift_register_sim_openfpga.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openfpga_flow/openfpga_simulation_settings/auto_shift_register_sim_openfpga.xml b/openfpga_flow/openfpga_simulation_settings/auto_shift_register_sim_openfpga.xml index 9b7ffa365..0f5c417ec 100644 --- a/openfpga_flow/openfpga_simulation_settings/auto_shift_register_sim_openfpga.xml +++ b/openfpga_flow/openfpga_simulation_settings/auto_shift_register_sim_openfpga.xml @@ -8,7 +8,8 @@ - + + From 7ba5d27ea7cb260ac383ca57ae72f727d68cbdda Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 1 Oct 2021 17:02:35 -0700 Subject: [PATCH 33/52] [Arch] Reworked example architectures for QuickLogic memory bank using shift registers: Add write-enable signal to WL CCFF model --- openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml | 5 +++-- .../openfpga_arch/k4_N4_40nm_qlbanksr_wlr_openfpga.xml | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml index ce848d2e7..a21c0e522 100644 --- a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml +++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml @@ -173,7 +173,7 @@ - + @@ -184,7 +184,8 @@ - + + diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_wlr_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_wlr_openfpga.xml index 43d716222..da0e46ded 100644 --- a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_wlr_openfpga.xml +++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_wlr_openfpga.xml @@ -174,7 +174,7 @@ - + @@ -186,7 +186,8 @@ - + + From 0b068201774ccec39ba1608fb1bee3995a2fc23a Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 1 Oct 2021 17:06:35 -0700 Subject: [PATCH 34/52] [HDL] Update the WL CCFF HDL modeling by adding Write-Enable signals --- openfpga_flow/openfpga_cell_library/verilog/dff.v | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/openfpga_flow/openfpga_cell_library/verilog/dff.v b/openfpga_flow/openfpga_cell_library/verilog/dff.v index da641d785..b03b2ba2d 100644 --- a/openfpga_flow/openfpga_cell_library/verilog/dff.v +++ b/openfpga_flow/openfpga_cell_library/verilog/dff.v @@ -475,6 +475,7 @@ 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 ); @@ -490,7 +491,7 @@ end else begin end assign SOUT = q_reg; -assign WLW = q_reg; +assign WLW = WEN ? q_reg : 1'b0; endmodule //End Of Module @@ -503,6 +504,7 @@ 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 @@ -519,7 +521,7 @@ end else begin end assign SOUT = q_reg; -assign WLW = 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 From 977d81679dbf11c31639b52fc84b7c027bc88e73 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 1 Oct 2021 17:23:10 -0700 Subject: [PATCH 35/52] [Engine] Upgrade check codes for WL CCFF --- .../src/check_circuit_library.cpp | 4 ++-- openfpga/src/base/openfpga_build_fabric.cpp | 1 + .../fabric/build_fabric_global_port_info.cpp | 10 ++++++++ .../fabric/build_fabric_global_port_info.h | 1 + .../src/fabric/fabric_global_port_info.cpp | 24 +++++++++++++++++++ openfpga/src/fabric/fabric_global_port_info.h | 8 +++++++ 6 files changed, 46 insertions(+), 2 deletions(-) diff --git a/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp b/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp index 1a7eb60ed..0964cc10a 100644 --- a/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp +++ b/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp @@ -400,10 +400,10 @@ size_t check_wl_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib, 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 */ + /* 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, - 1, 1, true); + 2, 1, true); /* Check if we have 1 output*/ diff --git a/openfpga/src/base/openfpga_build_fabric.cpp b/openfpga/src/base/openfpga_build_fabric.cpp index 1caac7342..211048eb3 100644 --- a/openfpga/src/base/openfpga_build_fabric.cpp +++ b/openfpga/src/base/openfpga_build_fabric.cpp @@ -124,6 +124,7 @@ int build_fabric(OpenfpgaContext& openfpga_ctx, /* Build fabric global port information */ 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().circuit_lib); diff --git a/openfpga/src/fabric/build_fabric_global_port_info.cpp b/openfpga/src/fabric/build_fabric_global_port_info.cpp index 2c745493a..d439a7fdf 100644 --- a/openfpga/src/fabric/build_fabric_global_port_info.cpp +++ b/openfpga/src/fabric/build_fabric_global_port_info.cpp @@ -24,6 +24,7 @@ namespace openfpga { * and cache their port/pin index in the top-level module *******************************************************************/ FabricGlobalPortInfo build_fabric_global_port_info(const ModuleManager& module_manager, + const ConfigProtocol& config_protocol, const TileAnnotation& tile_annotation, const CircuitLibrary& circuit_lib) { vtr::ScopedStartFinishTimer timer("Create global port info for top module"); @@ -56,6 +57,15 @@ FabricGlobalPortInfo build_fabric_global_port_info(const ModuleManager& module_m 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_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 */ diff --git a/openfpga/src/fabric/build_fabric_global_port_info.h b/openfpga/src/fabric/build_fabric_global_port_info.h index 5625d379f..6852a0249 100644 --- a/openfpga/src/fabric/build_fabric_global_port_info.h +++ b/openfpga/src/fabric/build_fabric_global_port_info.h @@ -19,6 +19,7 @@ namespace openfpga { FabricGlobalPortInfo build_fabric_global_port_info(const ModuleManager& module_manager, + const ConfigProtocol& config_protocol, const TileAnnotation& tile_annotation, const CircuitLibrary& circuit_lib); diff --git a/openfpga/src/fabric/fabric_global_port_info.cpp b/openfpga/src/fabric/fabric_global_port_info.cpp index 60ef72d94..18108597d 100644 --- a/openfpga/src/fabric/fabric_global_port_info.cpp +++ b/openfpga/src/fabric/fabric_global_port_info.cpp @@ -55,6 +55,16 @@ bool FabricGlobalPortInfo::global_port_is_shift_register(const FabricGlobalPortI 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 { VTR_ASSERT(valid_global_port_id(global_port_id)); return global_port_is_config_enable_[global_port_id]; @@ -83,6 +93,8 @@ FabricGlobalPortId FabricGlobalPortInfo::create_global_port(const ModulePortId& global_port_is_reset_.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_config_enable_.push_back(false); global_port_default_values_.push_back(0); @@ -120,6 +132,18 @@ void FabricGlobalPortInfo::set_global_port_is_shift_register(const FabricGlobalP 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, const bool& is_config_enable) { VTR_ASSERT(valid_global_port_id(global_port_id)); diff --git a/openfpga/src/fabric/fabric_global_port_info.h b/openfpga/src/fabric/fabric_global_port_info.h index 2521308d1..45f8f41cc 100644 --- a/openfpga/src/fabric/fabric_global_port_info.h +++ b/openfpga/src/fabric/fabric_global_port_info.h @@ -36,6 +36,8 @@ class FabricGlobalPortInfo { 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_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_io(const FabricGlobalPortId& global_port_id) const; @@ -55,6 +57,10 @@ class FabricGlobalPortInfo { 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, const bool& is_config_enable); void set_global_port_is_io(const FabricGlobalPortId& global_port_id, @@ -72,6 +78,8 @@ class FabricGlobalPortInfo { vtr::vector global_port_is_set_; vtr::vector global_port_is_prog_; vtr::vector global_port_is_shift_register_; + vtr::vector global_port_is_bl_; + vtr::vector global_port_is_wl_; vtr::vector global_port_is_config_enable_; vtr::vector global_port_is_io_; vtr::vector global_port_default_values_; From 477c1cd062015244ee7f4b6b02b7c324fc2ca941 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 1 Oct 2021 17:38:26 -0700 Subject: [PATCH 36/52] [Engine] Fixed a critical bug which causes undriven BL/WLs between shift register banks and child modules at the top-level module --- .../fabric/build_top_module_memory_bank.cpp | 11 +++++--- .../memory_bank_shift_register_banks.cpp | 27 ++++++++++++++----- .../fabric/memory_bank_shift_register_banks.h | 18 +++++++++---- 3 files changed, 40 insertions(+), 16 deletions(-) diff --git a/openfpga/src/fabric/build_top_module_memory_bank.cpp b/openfpga/src/fabric/build_top_module_memory_bank.cpp index 0c646fa55..031e0a8aa 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.cpp +++ b/openfpga/src/fabric/build_top_module_memory_bank.cpp @@ -1188,7 +1188,6 @@ void add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_blwls(ModuleMan VTR_ASSERT(sr_module_blwl_port); BasicPort sr_module_blwl_port_info = module_manager.module_port(sr_bank_module, sr_module_blwl_port); - size_t cur_sr_module_blwl_pin_id = 0; 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]; @@ -1199,7 +1198,7 @@ void add_top_module_nets_cmos_ql_memory_bank_shift_register_bank_blwls(ModuleMan 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); - cur_sr_module_blwl_pin_id = cur_sr_module_blwl_pin_id % sr_module_blwl_port_info.get_width(); + 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, @@ -1335,7 +1334,9 @@ void add_top_module_nets_cmos_ql_memory_bank_bl_shift_register_config_bus(Module 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_sink_blwls(config_region, sr_bank_module, cur_inst, bl_pin_id); + sr_banks.add_shift_register_source_blwls(config_region, sr_bank_module, cur_inst, bl_pin_id); + + cur_bl_index++; } } } @@ -1426,7 +1427,9 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_shift_register_config_bus(Module for (const size_t& sink_wl_pin : child_wl_port_info.pins()) { size_t wl_pin_id = wl_start_index_per_tile[coord.y()] + cur_wl_index; sr_banks.add_shift_register_sink_nodes(config_region, sr_bank_module, cur_inst, child_id, sink_wl_pin); - sr_banks.add_shift_register_sink_blwls(config_region, sr_bank_module, cur_inst, wl_pin_id); + sr_banks.add_shift_register_source_blwls(config_region, sr_bank_module, cur_inst, wl_pin_id); + + cur_wl_index++; } } } diff --git a/openfpga/src/fabric/memory_bank_shift_register_banks.cpp b/openfpga/src/fabric/memory_bank_shift_register_banks.cpp index aac8989fe..9dcd98cf3 100644 --- a/openfpga/src/fabric/memory_bank_shift_register_banks.cpp +++ b/openfpga/src/fabric/memory_bank_shift_register_banks.cpp @@ -61,10 +61,23 @@ std::vector MemoryBankShiftRegisterBanks::shift_register_bank_sink_pin_i return std::vector(); } +std::vector MemoryBankShiftRegisterBanks::shift_register_bank_source_blwl_ids(const ConfigRegionId& region, + const ModuleId& sr_module, + const size_t& sr_instance) const { + VTR_ASSERT(valid_region_id(region)); + + auto result = sr_instance_source_blwl_ids_[region].find(std::make_pair(sr_module, sr_instance)); + /* Return an empty vector if not found */ + if (result != sr_instance_source_blwl_ids_[region].end()) { + return result->second; + } + return std::vector(); +} + 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_sink_blwl_ids_.resize(num_regions); + sr_instance_source_blwl_ids_.resize(num_regions); } void MemoryBankShiftRegisterBanks::add_shift_register_instance(const ConfigRegionId& region, @@ -73,7 +86,7 @@ void MemoryBankShiftRegisterBanks::add_shift_register_instance(const ConfigRegio 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_sink_blwl_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, @@ -86,12 +99,12 @@ void MemoryBankShiftRegisterBanks::add_shift_register_sink_nodes(const ConfigReg 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_sink_blwls(const ConfigRegionId& region, - const ModuleId& sr_module, - const size_t& sr_instance, - const size_t& sink_blwl_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_sink_blwl_ids_[region][std::make_pair(sr_module, sr_instance)].push_back(sink_blwl_id); + 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 { diff --git a/openfpga/src/fabric/memory_bank_shift_register_banks.h b/openfpga/src/fabric/memory_bank_shift_register_banks.h index a145aca5e..6114f93d8 100644 --- a/openfpga/src/fabric/memory_bank_shift_register_banks.h +++ b/openfpga/src/fabric/memory_bank_shift_register_banks.h @@ -44,6 +44,14 @@ class MemoryBankShiftRegisterBanks { std::vector 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 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); @@ -60,10 +68,10 @@ class MemoryBankShiftRegisterBanks { 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_sink_blwls(const ConfigRegionId& region, - const ModuleId& sr_module, - const size_t& sr_instance, - const size_t& sink_blwl_id); + 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; @@ -71,7 +79,7 @@ class MemoryBankShiftRegisterBanks { /* [config_region][(shift_register_module, shift_register_instance)][i] = (reconfigurable_child_id, blwl_port_pin_index)*/ vtr::vector, std::vector>> sr_instance_sink_child_ids_; vtr::vector, std::vector>> sr_instance_sink_child_pin_ids_; - vtr::vector, std::vector>> sr_instance_sink_blwl_ids_; + vtr::vector, std::vector>> sr_instance_source_blwl_ids_; }; } /* end namespace openfpga */ From 2de6be44d6edaff8d5efd020057fc2dc7ad183d8 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 1 Oct 2021 18:27:42 -0700 Subject: [PATCH 37/52] [Engine] Fixed a critical bug which causes bitstream wrong for QuickLogic memory bank when fast configuration is enabled --- openfpga/src/utils/fabric_bitstream_utils.cpp | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/openfpga/src/utils/fabric_bitstream_utils.cpp b/openfpga/src/utils/fabric_bitstream_utils.cpp index e09a99672..8d66f300f 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.cpp +++ b/openfpga/src/utils/fabric_bitstream_utils.cpp @@ -235,13 +235,34 @@ MemoryBankFabricBitstream build_memory_bank_fabric_bitstream_by_address(const Fa MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream, const bool& fast_configuration, 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> 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 */ vtr::vector> 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)) { - /* Only when fast configuration is required, skip din because they should be pre-configured through programming reset/set */ - if (fast_configuration && fabric_bitstream.bit_din(bit_id) == bit_value_to_skip) { + /* Skip din because they should be pre-configured through programming reset/set */ + if (fabric_bitstream.bit_din(bit_id) == bit_value_to_skip) { continue; } /* Create string for BL address */ From 198517a898447d8952ec1bed5c4b763d54188431 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 1 Oct 2021 19:59:50 -0700 Subject: [PATCH 38/52] [FPGA-Bitstream] Bug fix on bitstream sequence for QuickLogic memory bank using shift registers --- openfpga/src/utils/fabric_bitstream_utils.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openfpga/src/utils/fabric_bitstream_utils.cpp b/openfpga/src/utils/fabric_bitstream_utils.cpp index 8d66f300f..d888b378b 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.cpp +++ b/openfpga/src/utils/fabric_bitstream_utils.cpp @@ -409,12 +409,16 @@ MemoryBankShiftRegisterFabricBitstream build_memory_bank_shift_register_fabric_b MemoryBankShiftRegisterFabricBitstreamWordId word_id = fabric_bits.create_word(); std::vector reshaped_bl_vectors = reshape_bitstream_vectors_to_last_element(bl_vec, '0'); + /* Reverse the vector due to shift register 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 reshaped_wl_vectors = reshape_bitstream_vectors_to_last_element(wl_vec, '0'); + /* Reverse the vector due to shift register 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); From f686dd1f60f50af3c9f0504e2c98b8c8df676d2c Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 1 Oct 2021 23:12:38 -0700 Subject: [PATCH 39/52] [FPGA-Bitstream] Do not reverse for now. Previous solution looks correct --- openfpga/src/utils/fabric_bitstream_utils.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/openfpga/src/utils/fabric_bitstream_utils.cpp b/openfpga/src/utils/fabric_bitstream_utils.cpp index d888b378b..8d66f300f 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.cpp +++ b/openfpga/src/utils/fabric_bitstream_utils.cpp @@ -409,16 +409,12 @@ MemoryBankShiftRegisterFabricBitstream build_memory_bank_shift_register_fabric_b MemoryBankShiftRegisterFabricBitstreamWordId word_id = fabric_bits.create_word(); std::vector reshaped_bl_vectors = reshape_bitstream_vectors_to_last_element(bl_vec, '0'); - /* Reverse the vector due to shift register 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 reshaped_wl_vectors = reshape_bitstream_vectors_to_last_element(wl_vec, '0'); - /* Reverse the vector due to shift register 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); From 32fc0a1692c89273c7c9907b8b92fbe3951a8612 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Oct 2021 17:25:27 -0700 Subject: [PATCH 40/52] [FPGA-Verilog] Upgrading verilog testbench generator for QuickLogic memory bank using BL/WL shift register --- .../verilog_top_testbench_memory_bank.cpp | 319 +++++++++++++++++- .../verilog_top_testbench_memory_bank.h | 9 + 2 files changed, 323 insertions(+), 5 deletions(-) diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp index 7618cd510..b2fa8277b 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp @@ -36,6 +36,17 @@ /* begin 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, const ModuleManager& module_manager, const ModuleId& top_module, @@ -73,6 +84,12 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp, 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_WIRE, sr_clock_port) << ";" << std::endl; + BasicPort sr_clock_register_port(std::string(std::string(TOP_TB_BL_SHIFT_REGISTER_CLOCK_PORT_NAME) + std::string(TOP_TB_CLOCK_REG_POSTFIX)), 1); + fp << generate_verilog_port(VERILOG_PORT_REG, sr_clock_register_port) << ";" << std::endl; } /* Print the address port for the Word-Line decoder here */ @@ -105,6 +122,12 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp, 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_WIRE, sr_clock_port) << ";" << std::endl; + BasicPort sr_clock_register_port(std::string(std::string(TOP_TB_WL_SHIFT_REGISTER_CLOCK_PORT_NAME) + std::string(TOP_TB_CLOCK_REG_POSTFIX)), 1); + fp << generate_verilog_port(VERILOG_PORT_REG, sr_clock_register_port) << ";" << std::endl; } /* Print the data-input port: only available when BL has a decoder */ @@ -180,11 +203,6 @@ void print_verilog_full_testbench_ql_memory_bank_flatten_bitstream(std::fstream& /* Validate the file stream */ valid_file_stream(fp); - /* No fast configuration available in this configuration protocol. Give a warning */ - if (true == fast_configuration) { - VTR_LOG_WARN("Fast configuration is not available for flatten BL protocol"); - } - /* Reorganize the fabric bitstream by the same address across regions */ MemoryBankFlattenFabricBitstream fabric_bits_by_addr = build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, fast_configuration, @@ -308,6 +326,290 @@ void print_verilog_full_testbench_ql_memory_bank_flatten_bitstream(std::fstream& 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 */ +void print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(std::fstream& fp, + const BasicPort& prog_clock_port, + const BasicPort& start_sr_port, + const BasicPort& sr_clock_port) { + /* Validate the file stream */ + valid_file_stream(fp); + + fp << "always"; + fp << " @(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ")"; + fp << " begin"; + fp << std::endl; + + fp << "\t"; + fp << generate_verilog_port_constant_values(sr_clock_port, std::vector(sr_clock_port.get_width(), 0), true); + fp << ";" << std::endl; + + fp << "\t"; + fp << "while (" << generate_verilog_port(VERILOG_PORT_CONKT, start_sr_port) << ") begin"; + fp << std::endl; + + fp << "\t\t"; + fp << "#0.05 "; + print_verilog_register_connection(fp, sr_clock_port, sr_clock_port, true); + fp << ";" << std::endl; + + fp << "\t"; + fp << "end"; + fp << std::endl; + + fp << "\t"; + fp << generate_verilog_port_constant_values(sr_clock_port, std::vector(sr_clock_port.get_width(), 0), true); + fp << ";" << std::endl; +} + +/* 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 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 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 initial_bl_head_values(bl_head_port_width, 0); + std::vector 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; + + /* 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; + 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_BL_SHIFT_REGISTER_COUNT_PORT_NAME << ";" << std::endl; + fp << "integer " << TOP_TB_WL_SHIFT_REGISTER_COUNT_PORT_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; + + fp << "\t"; + fp << generate_verilog_port_constant_values(start_bl_sr_port, std::vector(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(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, "----- BL Shift register clock generator -----"); + print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(fp, prog_clock_port, start_bl_sr_port, bl_sr_clock_port); + + print_verilog_comment(fp, "----- WL Shift register clock generator -----"); + print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(fp, prog_clock_port, start_wl_sr_port, wl_sr_clock_port); + + 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 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(start_bl_sr_port.get_width(), 0), true); + fp << ";"; + fp << std::endl; + + fp << "\t\t"; + fp << generate_verilog_port_constant_values(start_wl_sr_port, std::vector(start_wl_sr_port.get_width(), 0), 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\t"; + fp << generate_verilog_port_constant_values(start_bl_sr_port, std::vector(start_bl_sr_port.get_width(), 0), true); + fp << std::endl; + + fp << "\t\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 << "*(`" << TOP_TB_BITSTREAM_BL_WORD_SIZE_VARIABLE << "+ `" << TOP_TB_BITSTREAM_BL_WORD_SIZE_VARIABLE << ") + " << TOP_TB_BL_SHIFT_REGISTER_COUNT_PORT_NAME; + 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\t"; + fp << generate_verilog_port_constant_values(start_wl_sr_port, std::vector(start_wl_sr_port.get_width(), 0), true); + fp << std::endl; + + fp << "\t\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 << "*(`" << TOP_TB_BITSTREAM_WL_WORD_SIZE_VARIABLE << "+ `" << TOP_TB_BITSTREAM_WL_WORD_SIZE_VARIABLE << ") + `" << TOP_TB_BITSTREAM_WL_WORD_SIZE_VARIABLE << " + " << TOP_TB_WL_SHIFT_REGISTER_COUNT_PORT_NAME; + fp << "];" << std::endl; + + fp << "\t"; + fp << "end"; + fp << std::endl; + + fp << "end"; + fp << std::endl; + + print_verilog_comment(fp, "----- End bitstream loading during configuration phase -----"); +} + + /* Verilog codes to load bitstream from a bit file for memory bank using BL/WL decoders */ static void print_verilog_full_testbench_ql_memory_bank_decoder_bitstream(std::fstream& fp, @@ -468,6 +770,13 @@ void print_verilog_full_testbench_ql_memory_bank_bitstream(std::fstream& fp, bit_value_to_skip, module_manager, top_module, 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); } } diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h index 87ddf3ac5..194f0b86f 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h @@ -34,6 +34,15 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp, const ModuleId& top_module, const ConfigProtocol& config_protocol); +/** + * @brief Generate the Verilog codes for a shift register clocks that controls BL/WL protocols + */ +void print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(std::fstream& fp, + const BasicPort& prog_clock_port, + const BasicPort& start_sr_port, + const BasicPort& sr_clock_port); + + /** * @brief Print stimulus for a FPGA fabric with a memory bank configuration protocol * where configuration bits are programming in serial (one by one) From 54ec74d8d29f285f10f7c54e35914dcec46d9d40 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Oct 2021 17:31:37 -0700 Subject: [PATCH 41/52] [FPGA-Verilog] Bug fix in code generator --- .../src/fpga_verilog/verilog_top_testbench_memory_bank.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp index b2fa8277b..346f3b34b 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp @@ -350,7 +350,6 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator( fp << "\t\t"; fp << "#0.05 "; print_verilog_register_connection(fp, sr_clock_port, sr_clock_port, true); - fp << ";" << std::endl; fp << "\t"; fp << "end"; @@ -552,7 +551,7 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f fp << "\t\t"; fp << generate_verilog_port_constant_values(start_bl_sr_port, std::vector(start_bl_sr_port.get_width(), 0), true); - fp << std::endl; + fp << ";" << std::endl; fp << "\t\t"; fp << TOP_TB_BL_SHIFT_REGISTER_COUNT_PORT_NAME << " = 0;"; @@ -583,7 +582,7 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f fp << "\t\t"; fp << generate_verilog_port_constant_values(start_wl_sr_port, std::vector(start_wl_sr_port.get_width(), 0), true); - fp << std::endl; + fp << ";" << std::endl; fp << "\t\t"; fp << TOP_TB_WL_SHIFT_REGISTER_COUNT_PORT_NAME << " = 0;"; From 76d58ebaa0177169006f55d96897363e2bf80f34 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Oct 2021 21:48:10 -0700 Subject: [PATCH 42/52] [FPGA-Verilog] Move clock generator to generic stimuli and shift register clock period is auto tuned by programming clock period --- .../fpga_verilog/verilog_top_testbench.cpp | 16 +- .../verilog_top_testbench_memory_bank.cpp | 161 ++++++++++++------ .../verilog_top_testbench_memory_bank.h | 16 +- 3 files changed, 128 insertions(+), 65 deletions(-) diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp index 0ef3eebcb..3a09db525 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp @@ -1112,21 +1112,30 @@ void print_verilog_top_testbench_generic_stimulus(std::fstream& fp, *******************************************************************/ static 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 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) { /* Validate the file stream */ valid_file_stream(fp); /* Branch on the type of configuration protocol */ - switch (config_protocol_type) { + switch (config_protocol.type()) { case CONFIG_MEM_STANDALONE: break; case CONFIG_MEM_SCAN_CHAIN: break; 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_FRAME_BASED: { ModulePortId en_port_id = module_manager.find_module_port(top_module, @@ -1956,8 +1965,9 @@ int print_verilog_full_testbench(const ModuleManager& module_manager, /* Generate stimuli for programming interface */ print_verilog_top_testbench_configuration_protocol_stimulus(fp, - config_protocol.type(), + config_protocol, module_manager, top_module, + fast_configuration, bit_value_to_skip, fabric_bitstream, prog_clock_period, VERILOG_SIM_TIMESCALE); diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp index 346f3b34b..607ad9d0e 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp @@ -87,9 +87,13 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp, /* 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_WIRE, sr_clock_port) << ";" << std::endl; - BasicPort sr_clock_register_port(std::string(std::string(TOP_TB_BL_SHIFT_REGISTER_CLOCK_PORT_NAME) + std::string(TOP_TB_CLOCK_REG_POSTFIX)), 1); - fp << generate_verilog_port(VERILOG_PORT_REG, sr_clock_register_port) << ";" << std::endl; + 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 */ @@ -125,9 +129,13 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp, /* 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_WIRE, sr_clock_port) << ";" << std::endl; - BasicPort sr_clock_register_port(std::string(std::string(TOP_TB_WL_SHIFT_REGISTER_CLOCK_PORT_NAME) + std::string(TOP_TB_CLOCK_REG_POSTFIX)), 1); - fp << generate_verilog_port(VERILOG_PORT_REG, sr_clock_register_port) << ";" << std::endl; + 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 */ @@ -191,6 +199,94 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp, fp << ";" << std::endl; } +/** + * @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& prog_clock_port, + 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 << " @(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ")"; + fp << " begin"; + fp << std::endl; + + fp << "\t"; + fp << generate_verilog_port_constant_values(sr_clock_port, std::vector(sr_clock_port.get_width(), 0), true); + fp << ";" << std::endl; + + fp << "\t"; + fp << "while (" << generate_verilog_port(VERILOG_PORT_CONKT, start_sr_port) << ") begin"; + fp << std::endl; + + fp << "\t\t"; + fp << "#" << sr_clock_period << " "; + print_verilog_register_connection(fp, sr_clock_port, sr_clock_port, true); + + fp << "\t"; + fp << "end"; + fp << std::endl; + + fp << "\t"; + fp << generate_verilog_port_constant_values(sr_clock_port, std::vector(sr_clock_port.get_width(), 0), true); + fp << ";" << std::endl; +} + +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 */ + float bl_sr_clock_period = prog_clock_period / fabric_bits_by_addr.bl_width() / timescale; + float wl_sr_clock_period = prog_clock_period / fabric_bits_by_addr.wl_width() / 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, prog_clock_port, start_bl_sr_port, bl_sr_clock_port, 0.5 * 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, prog_clock_port, start_wl_sr_port, wl_sr_clock_port, 0.5 * wl_sr_clock_period); + } + } +} + /* Verilog codes to load bitstream from a bit file for memory bank using flatten BL/WLs */ static void print_verilog_full_testbench_ql_memory_bank_flatten_bitstream(std::fstream& fp, @@ -326,40 +422,6 @@ void print_verilog_full_testbench_ql_memory_bank_flatten_bitstream(std::fstream& 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 */ -void print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(std::fstream& fp, - const BasicPort& prog_clock_port, - const BasicPort& start_sr_port, - const BasicPort& sr_clock_port) { - /* Validate the file stream */ - valid_file_stream(fp); - - fp << "always"; - fp << " @(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ")"; - fp << " begin"; - fp << std::endl; - - fp << "\t"; - fp << generate_verilog_port_constant_values(sr_clock_port, std::vector(sr_clock_port.get_width(), 0), true); - fp << ";" << std::endl; - - fp << "\t"; - fp << "while (" << generate_verilog_port(VERILOG_PORT_CONKT, start_sr_port) << ") begin"; - fp << std::endl; - - fp << "\t\t"; - fp << "#0.05 "; - print_verilog_register_connection(fp, sr_clock_port, sr_clock_port, true); - - fp << "\t"; - fp << "end"; - fp << std::endl; - - fp << "\t"; - fp << generate_verilog_port_constant_values(sr_clock_port, std::vector(sr_clock_port.get_width(), 0), true); - fp << ";" << std::endl; -} - /* 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, @@ -429,16 +491,6 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f fp << "reg [$clog2(`" << TOP_TB_BITSTREAM_LENGTH_VARIABLE << "):0] " << TOP_TB_BITSTREAM_INDEX_REG_NAME << ";" << 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; - 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_BL_SHIFT_REGISTER_COUNT_PORT_NAME << ";" << std::endl; - fp << "integer " << TOP_TB_WL_SHIFT_REGISTER_COUNT_PORT_NAME << ";" << std::endl; - print_verilog_comment(fp, "----- Preload bitstream file to a virtual memory -----"); fp << "initial begin" << std::endl; fp << "\t"; @@ -462,6 +514,9 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f 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(start_bl_sr_port.get_width(), 0), true); fp << ";"; @@ -480,12 +535,6 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f 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, "----- BL Shift register clock generator -----"); - print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(fp, prog_clock_port, start_bl_sr_port, bl_sr_clock_port); - - print_verilog_comment(fp, "----- WL Shift register clock generator -----"); - print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(fp, prog_clock_port, start_wl_sr_port, wl_sr_clock_port); - print_verilog_comment(fp, "----- Begin bitstream loading during configuration phase -----"); fp << "always"; fp << " @(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ")"; diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h index 194f0b86f..78e364a4c 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h @@ -35,13 +35,17 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp, const ConfigProtocol& config_protocol); /** - * @brief Generate the Verilog codes for a shift register clocks that controls BL/WL protocols + * @brief Generate the Verilog codes that generate stimuli waveforms for BL/WL protocols */ -void print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(std::fstream& fp, - const BasicPort& prog_clock_port, - const BasicPort& start_sr_port, - const BasicPort& sr_clock_port); - +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 From fa7e1681371779551034c3f8cafe9a2d1aa424bf Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Oct 2021 22:08:14 -0700 Subject: [PATCH 43/52] [FPGA-Verilog] Now testbench generator connects global shift register clocks to FPGA ports --- .../fpga_verilog/verilog_top_testbench.cpp | 10 +++++ .../verilog_top_testbench_memory_bank.cpp | 40 +++++++++++++++++++ .../verilog_top_testbench_memory_bank.h | 8 ++++ 3 files changed, 58 insertions(+) diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp index 3a09db525..f3832fdc3 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp @@ -271,6 +271,11 @@ void print_verilog_top_testbench_global_clock_ports_stimuli(std::fstream& fp, /* 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)); + + /* 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; if (true == fabric_global_port_info.global_port_is_prog(fabric_global_port)) { @@ -563,6 +568,11 @@ void print_verilog_top_testbench_global_ports_stimuli(std::fstream& fp, fabric_global_port_info, 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, module_manager, top_module, diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp index 607ad9d0e..816b7aebb 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp @@ -199,6 +199,46 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp, 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_BL_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 */ diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h index 78e364a4c..d4ebf3264 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h @@ -34,6 +34,14 @@ void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp, const ModuleId& top_module, 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 */ From 02af633acdc9158e7a24f1da486a831aa88250b7 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Oct 2021 22:14:15 -0700 Subject: [PATCH 44/52] [FPGA-Verilog] Fixed several bugs in testbench generator which caused iVerilog errors --- .../verilog_top_testbench_memory_bank.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp index 816b7aebb..1b00795cb 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp @@ -275,6 +275,9 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator( fp << "\t"; fp << generate_verilog_port_constant_values(sr_clock_port, std::vector(sr_clock_port.get_width(), 0), true); fp << ";" << std::endl; + + fp << "end"; + fp << std::endl; } void print_verilog_top_testbench_configuration_protocol_ql_memory_bank_stimulus(std::fstream& fp, @@ -638,6 +641,14 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f 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; + fp << ") begin"; + fp << std::endl; + fp << "\t\t"; fp << generate_verilog_port_constant_values(start_bl_sr_port, std::vector(start_bl_sr_port.get_width(), 0), true); fp << ";" << std::endl; @@ -669,6 +680,14 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f 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; + fp << ") begin"; + fp << std::endl; + fp << "\t\t"; fp << generate_verilog_port_constant_values(start_wl_sr_port, std::vector(start_wl_sr_port.get_width(), 0), true); fp << ";" << std::endl; From 86e7c963f889e7f269feade7e5f955d034f6771a Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Oct 2021 22:19:20 -0700 Subject: [PATCH 45/52] [Arch] Bug fix for wrong XML syntax in QuickLogic memory bank example architecture files --- openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml index a21c0e522..803512e5d 100644 --- a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml +++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml @@ -173,7 +173,7 @@ - + @@ -185,7 +185,7 @@ - + From d453e6477dafc3befc9fc1216e5ba3a7d76c63ee Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Oct 2021 22:32:57 -0700 Subject: [PATCH 46/52] [FPGA-Verilog] Bug fix --- .../verilog_top_testbench_memory_bank.cpp | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp index 1b00795cb..76151a8b2 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp @@ -315,8 +315,8 @@ void print_verilog_top_testbench_configuration_protocol_ql_memory_bank_stimulus( bit_value_to_skip); /* TODO: Consider auto-tuned clock period for now */ - float bl_sr_clock_period = prog_clock_period / fabric_bits_by_addr.bl_width() / timescale; - float wl_sr_clock_period = prog_clock_period / fabric_bits_by_addr.wl_width() / timescale; + float bl_sr_clock_period = prog_clock_period / fabric_bits_by_addr.bl_word_size() / timescale; + float wl_sr_clock_period = prog_clock_period / fabric_bits_by_addr.wl_word_size() / timescale; if (BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()) { print_verilog_comment(fp, "----- BL Shift register clock generator -----"); @@ -605,12 +605,12 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f /* 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(start_bl_sr_port.get_width(), 0), true); + fp << generate_verilog_port_constant_values(start_bl_sr_port, std::vector(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(start_wl_sr_port.get_width(), 0), true); + fp << generate_verilog_port_constant_values(start_wl_sr_port, std::vector(start_wl_sr_port.get_width(), 1), true); fp << ";"; fp << std::endl; @@ -664,9 +664,14 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f fp << generate_verilog_ports(bl_head_ports); fp << " <= "; fp << TOP_TB_BITSTREAM_MEM_REG_NAME << "["; - fp << TOP_TB_BITSTREAM_INDEX_REG_NAME << "*(`" << TOP_TB_BITSTREAM_BL_WORD_SIZE_VARIABLE << "+ `" << TOP_TB_BITSTREAM_BL_WORD_SIZE_VARIABLE << ") + " << TOP_TB_BL_SHIFT_REGISTER_COUNT_PORT_NAME; + fp << TOP_TB_BITSTREAM_INDEX_REG_NAME << "*(`" << 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; @@ -703,9 +708,14 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f fp << generate_verilog_ports(wl_head_ports); fp << " <= "; fp << TOP_TB_BITSTREAM_MEM_REG_NAME << "["; - fp << TOP_TB_BITSTREAM_INDEX_REG_NAME << "*(`" << TOP_TB_BITSTREAM_WL_WORD_SIZE_VARIABLE << "+ `" << TOP_TB_BITSTREAM_WL_WORD_SIZE_VARIABLE << ") + `" << TOP_TB_BITSTREAM_WL_WORD_SIZE_VARIABLE << " + " << TOP_TB_WL_SHIFT_REGISTER_COUNT_PORT_NAME; + fp << TOP_TB_BITSTREAM_INDEX_REG_NAME << "*(`" << TOP_TB_BITSTREAM_BL_WORD_SIZE_VARIABLE << " + `" << TOP_TB_BITSTREAM_WL_WORD_SIZE_VARIABLE << ") + `" << TOP_TB_BITSTREAM_WL_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; From 3eb601531a4f4712f9a7ce2955600b58e9ca9cca Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 2 Oct 2021 23:39:53 -0700 Subject: [PATCH 47/52] [FPGA-Verilog] Many bug fixes --- .../verilog_top_testbench_memory_bank.cpp | 26 ++++++++++--------- openfpga/src/utils/fabric_bitstream_utils.cpp | 14 ++++++---- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp index 76151a8b2..a750ff68b 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp @@ -226,7 +226,7 @@ void print_verilog_top_testbench_global_shift_register_clock_ports_stimuli(std:: 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_BL_SHIFT_REGISTER_CLOCK_PORT_NAME)); + stimuli_clock_port.set_name(std::string(TOP_TB_WL_SHIFT_REGISTER_CLOCK_PORT_NAME)); stimuli_clock_port.set_width(1); } @@ -244,7 +244,6 @@ void print_verilog_top_testbench_global_shift_register_clock_ports_stimuli(std:: */ static void print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(std::fstream& fp, - const BasicPort& prog_clock_port, const BasicPort& start_sr_port, const BasicPort& sr_clock_port, const float& sr_clock_period) { @@ -252,7 +251,7 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator( valid_file_stream(fp); fp << "always"; - fp << " @(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ")"; + fp << " @(posedge " << generate_verilog_port(VERILOG_PORT_CONKT, start_sr_port) << ")"; fp << " begin"; fp << std::endl; @@ -314,18 +313,21 @@ void print_verilog_top_testbench_configuration_protocol_ql_memory_bank_stimulus( fast_configuration, bit_value_to_skip); - /* TODO: Consider auto-tuned clock period for now */ - float bl_sr_clock_period = prog_clock_period / fabric_bits_by_addr.bl_word_size() / timescale; - float wl_sr_clock_period = prog_clock_period / fabric_bits_by_addr.wl_word_size() / timescale; + /* 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, prog_clock_port, start_bl_sr_port, bl_sr_clock_port, 0.5 * bl_sr_clock_period); + 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, prog_clock_port, start_wl_sr_port, wl_sr_clock_port, 0.5 * wl_sr_clock_period); + print_verilog_full_testbench_ql_memory_bank_shift_register_clock_generator(fp, start_wl_sr_port, wl_sr_clock_port, wl_sr_clock_period); } } } @@ -663,8 +665,8 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f 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 << "*(`" << TOP_TB_BITSTREAM_BL_WORD_SIZE_VARIABLE << " + `" << TOP_TB_BITSTREAM_WL_WORD_SIZE_VARIABLE << ") + " << TOP_TB_BL_SHIFT_REGISTER_COUNT_PORT_NAME; + 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"; @@ -707,8 +709,8 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f 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 << "*(`" << TOP_TB_BITSTREAM_BL_WORD_SIZE_VARIABLE << " + `" << TOP_TB_BITSTREAM_WL_WORD_SIZE_VARIABLE << ") + `" << TOP_TB_BITSTREAM_WL_WORD_SIZE_VARIABLE << " + " << TOP_TB_WL_SHIFT_REGISTER_COUNT_PORT_NAME; + 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"; diff --git a/openfpga/src/utils/fabric_bitstream_utils.cpp b/openfpga/src/utils/fabric_bitstream_utils.cpp index 8d66f300f..31163efcc 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.cpp +++ b/openfpga/src/utils/fabric_bitstream_utils.cpp @@ -366,8 +366,8 @@ MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(cons * *******************************************************************/ static -std::vector reshape_bitstream_vectors_to_last_element(const std::vector& bitstream_vectors, - const char& default_bit_to_fill) { +std::vector reshape_bitstream_vectors_to_first_element(const std::vector& 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) { @@ -377,8 +377,8 @@ std::vector reshape_bitstream_vectors_to_last_element(const std::ve std::vector reshaped_vectors(bitstream_vectors.size(), std::string()); size_t col_cnt = 0; for (const auto& vec : bitstream_vectors) { - reshaped_vectors[col_cnt].resize(max_vec_size - vec.size(), default_bit_to_fill); reshaped_vectors[col_cnt] += vec; + reshaped_vectors[col_cnt] += std::string(max_vec_size - vec.size(), default_bit_to_fill); col_cnt++; } @@ -408,13 +408,17 @@ MemoryBankShiftRegisterFabricBitstream build_memory_bank_shift_register_fabric_b MemoryBankShiftRegisterFabricBitstreamWordId word_id = fabric_bits.create_word(); - std::vector reshaped_bl_vectors = reshape_bitstream_vectors_to_last_element(bl_vec, '0'); + std::vector 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 reshaped_wl_vectors = reshape_bitstream_vectors_to_last_element(wl_vec, '0'); + std::vector 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); From 756b4c7dc8b574416b884c18fd0bb53f887b3a5c Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 3 Oct 2021 12:11:20 -0700 Subject: [PATCH 48/52] [FPGA-Verilog] Bug fix in estimating the simulation period for QuickLogic memory bank using BL/WL shift registers --- openfpga/src/fpga_verilog/verilog_top_testbench.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp index f3832fdc3..f8477df5f 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp @@ -874,7 +874,7 @@ size_t calculate_num_config_clock_cycles(const ConfigProtocol& config_protocol, } else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) { 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()) { - /* TODO */ + num_config_clock_cycles = 1 + build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, fast_configuration, bit_value_to_skip).size(); } break; } From 28904ff526e2b73fae3d74fa3b745fd97831d451 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 3 Oct 2021 12:31:58 -0700 Subject: [PATCH 49/52] [Engine] Bug fix on wrong port type for shift register chains --- openfpga/src/fabric/build_top_module_memory_bank.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfpga/src/fabric/build_top_module_memory_bank.cpp b/openfpga/src/fabric/build_top_module_memory_bank.cpp index 031e0a8aa..dd3dceafb 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.cpp +++ b/openfpga/src/fabric/build_top_module_memory_bank.cpp @@ -1588,7 +1588,7 @@ void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager, 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_INPUT_PORT); + module_manager.add_port(module_id, blsr_tail_port, ModuleManager::MODULE_OUTPUT_PORT); } break; } @@ -1637,7 +1637,7 @@ void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager, 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_INPUT_PORT); + module_manager.add_port(module_id, wlsr_tail_port, ModuleManager::MODULE_OUTPUT_PORT); } break; } From 2badcb58f2d9090331b8d19d1abfa3f093cbcca7 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 3 Oct 2021 16:04:47 -0700 Subject: [PATCH 50/52] [FPGA-Verilog] Fixed a critical bug in verilog testbench generator for QL memory bank using BL/WL register which causes misalignment in shift register loading --- .../src/fpga_verilog/verilog_top_testbench_memory_bank.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp index a750ff68b..5482b0454 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp @@ -647,7 +647,7 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f fp << "if ("; fp << TOP_TB_BL_SHIFT_REGISTER_COUNT_PORT_NAME; fp << " >= "; - fp << "`" << TOP_TB_BITSTREAM_BL_WORD_SIZE_VARIABLE; + fp << "`" << TOP_TB_BITSTREAM_BL_WORD_SIZE_VARIABLE << " - 1"; fp << ") begin"; fp << std::endl; @@ -691,7 +691,7 @@ void print_verilog_full_testbench_ql_memory_bank_shift_register_bitstream(std::f fp << "if ("; fp << TOP_TB_WL_SHIFT_REGISTER_COUNT_PORT_NAME; fp << " >= "; - fp << "`" << TOP_TB_BITSTREAM_WL_WORD_SIZE_VARIABLE; + fp << "`" << TOP_TB_BITSTREAM_WL_WORD_SIZE_VARIABLE << " - 1"; fp << ") begin"; fp << std::endl; From 06b018cfe7f15b3200ece0d653abf5c2c4f22f89 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 3 Oct 2021 16:05:33 -0700 Subject: [PATCH 51/52] [FPGA-Bitstream] Reverse bitstream for shift register due to its FIFO nature --- openfpga/src/utils/fabric_bitstream_utils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/openfpga/src/utils/fabric_bitstream_utils.cpp b/openfpga/src/utils/fabric_bitstream_utils.cpp index 31163efcc..cc14dfe84 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.cpp +++ b/openfpga/src/utils/fabric_bitstream_utils.cpp @@ -410,7 +410,7 @@ MemoryBankShiftRegisterFabricBitstream build_memory_bank_shift_register_fabric_b std::vector 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()); + 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); @@ -418,7 +418,7 @@ MemoryBankShiftRegisterFabricBitstream build_memory_bank_shift_register_fabric_b std::vector 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()); + 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); From 7f75c2b619e80a2328d6c1a856a1174c29033209 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sun, 3 Oct 2021 16:06:44 -0700 Subject: [PATCH 52/52] [Test] Deploy shift register -based QL memory bank test case to basic regression test --- openfpga_flow/regression_test_scripts/basic_reg_test.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/openfpga_flow/regression_test_scripts/basic_reg_test.sh b/openfpga_flow/regression_test_scripts/basic_reg_test.sh index b9067ce78..09c4d7f10 100755 --- a/openfpga_flow/regression_test_scripts/basic_reg_test.sh +++ b/openfpga_flow/regression_test_scripts/basic_reg_test.sh @@ -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/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_shift_register --debug --show_thread_logs echo -e "Testing testbenches without self checking features"; run-task basic_tests/full_testbench/full_testbench_without_self_checking --debug --show_thread_logs