From 212c5bd642249dae85f458fa1398318b23413c31 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 22 Sep 2021 15:04:19 -0700 Subject: [PATCH 01/28] [Arch] Add an example architecture which uses flatten BL/WL for QL memory bank organization --- .../k4_N4_40nm_qlbankflatten_openfpga.xml | 201 ++++++++++++++++++ 1 file changed, 201 insertions(+) create mode 100644 openfpga_flow/openfpga_arch/k4_N4_40nm_qlbankflatten_openfpga.xml diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbankflatten_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbankflatten_openfpga.xml new file mode 100644 index 000000000..00cd1a519 --- /dev/null +++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbankflatten_openfpga.xml @@ -0,0 +1,201 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 3cfd5c3531c6a8941f21f3d25ebd60bbbe8b1710 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 22 Sep 2021 15:04:59 -0700 Subject: [PATCH 02/28] [Arch] Added an example architecture which uses shift-registers to configure BL/WLs for QL memory banks --- .../k4_N4_40nm_qlbanksr_openfpga.xml | 212 ++++++++++++++++++ 1 file changed, 212 insertions(+) create mode 100644 openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml new file mode 100644 index 000000000..68c4921a2 --- /dev/null +++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml @@ -0,0 +1,212 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 53da5d49feeee01fd7cac32855ee43b2aad963be Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 22 Sep 2021 15:48:14 -0700 Subject: [PATCH 03/28] [Arch] Correct XML syntax errors --- .../openfpga_arch/k4_N4_40nm_qlbankflatten_openfpga.xml | 2 +- openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbankflatten_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbankflatten_openfpga.xml index 00cd1a519..f5d450cac 100644 --- a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbankflatten_openfpga.xml +++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbankflatten_openfpga.xml @@ -166,7 +166,7 @@ - + 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 68c4921a2..f91f65468 100644 --- a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml +++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml @@ -177,7 +177,7 @@ - + From a98df811ed216384a15df3edfab38e04cbf8ad7e Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 22 Sep 2021 15:50:47 -0700 Subject: [PATCH 04/28] [Arch] Bug fix: wrong circuit model name was used for CCFF --- 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 f91f65468..3e04af1c3 100644 --- a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml +++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbanksr_openfpga.xml @@ -178,8 +178,8 @@ - - + + From 655b195d8bda5f954124b46847cc273521c22c96 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 22 Sep 2021 15:56:44 -0700 Subject: [PATCH 05/28] [Test] Added a test case to validate the correctness of QL memory bank where BL/WL are flatten on the top level --- .../ql_memory_bank_flatten/config/task.conf | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 openfpga_flow/tasks/basic_tests/full_testbench/ql_memory_bank_flatten/config/task.conf diff --git a/openfpga_flow/tasks/basic_tests/full_testbench/ql_memory_bank_flatten/config/task.conf b/openfpga_flow/tasks/basic_tests/full_testbench/ql_memory_bank_flatten/config/task.conf new file mode 100644 index 000000000..1263c9211 --- /dev/null +++ b/openfpga_flow/tasks/basic_tests/full_testbench/ql_memory_bank_flatten/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_qlbankflatten_openfpga.xml +openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml +openfpga_vpr_device_layout= +openfpga_fast_configuration= + +[ARCHITECTURES] +arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml + +[BENCHMARKS] +bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v +bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/or2/or2.v +bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch/and2_latch.v + +[SYNTHESIS_PARAM] +bench0_top = and2 +bench0_chan_width = 300 + +bench1_top = or2 +bench1_chan_width = 300 + +bench2_top = and2_latch +bench2_chan_width = 300 + +[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH] +end_flow_with_test= From 1ca1b0f3e92e2de9491762a4ac1bf8315cc7700b Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 22 Sep 2021 15:58:05 -0700 Subject: [PATCH 06/28] [Test] Deploy the new test case (flatten BL/WL for QL memory bank) to basic regression tests --- 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 ba0171d2e..cc74b9a4a 100755 --- a/openfpga_flow/regression_test_scripts/basic_reg_test.sh +++ b/openfpga_flow/regression_test_scripts/basic_reg_test.sh @@ -57,6 +57,7 @@ echo -e "Testing physical design friendly memory bank configuration protocol of run-task basic_tests/full_testbench/ql_memory_bank --debug --show_thread_logs run-task basic_tests/full_testbench/ql_memory_bank_use_wlr --debug --show_thread_logs run-task basic_tests/full_testbench/multi_region_ql_memory_bank --debug --show_thread_logs +run-task basic_tests/full_testbench/ql_memory_bank_flatten --debug --show_thread_logs echo -e "Testing testbenches without self checking features"; run-task basic_tests/full_testbench/full_testbench_without_self_checking --debug --show_thread_logs From d4e3445153db13606d3ee7b015c01f01a038bbbd Mon Sep 17 00:00:00 2001 From: tangxifan Date: Wed, 22 Sep 2021 17:32:45 -0700 Subject: [PATCH 07/28] [Engine] update internal data structure for new syntax in configuration protocol --- libopenfpga/libarchopenfpga/src/config_protocol.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libopenfpga/libarchopenfpga/src/config_protocol.h b/libopenfpga/libarchopenfpga/src/config_protocol.h index 550401098..034805c65 100644 --- a/libopenfpga/libarchopenfpga/src/config_protocol.h +++ b/libopenfpga/libarchopenfpga/src/config_protocol.h @@ -5,6 +5,15 @@ #include "circuit_types.h" #include "circuit_library_fwd.h" +/* Data type to define the protocol through which BL/WL can be manipulated */ +enum e_blwl_protocol_type { + BLWL_PROTOCOL_FLATTEN, + BLWL_PROTOCOL_DECODER, + BLWL_PROTOCOL_SHIFT_REGISTER, + NUM_BLWL_PROTOCOLS_TYPES +}; +constexpr std::array BLWL_PROTOCOL_TYPE_STRING = {{"flatten", "decoder", "shift_register"}}; + /******************************************************************** * A data structure to store configuration protocol information *******************************************************************/ From 6645b70ae3604c56510c602788d597fd0e57630e Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 23 Sep 2021 14:25:25 -0700 Subject: [PATCH 08/28] [Engine] Upgrade parser to support BL/WL protocols --- .../libarchopenfpga/src/config_protocol.cpp | 73 ++++++++++++++++++ .../libarchopenfpga/src/config_protocol.h | 29 ++++++- .../src/openfpga_arch_linker.cpp | 23 ++++++ .../src/read_xml_config_protocol.cpp | 76 +++++++++++++++++++ 4 files changed, 200 insertions(+), 1 deletion(-) diff --git a/libopenfpga/libarchopenfpga/src/config_protocol.cpp b/libopenfpga/libarchopenfpga/src/config_protocol.cpp index 1499a4baf..948046493 100644 --- a/libopenfpga/libarchopenfpga/src/config_protocol.cpp +++ b/libopenfpga/libarchopenfpga/src/config_protocol.cpp @@ -1,4 +1,5 @@ #include "vtr_assert.h" +#include "vtr_log.h" #include "config_protocol.h" @@ -32,6 +33,30 @@ int ConfigProtocol::num_regions() const { return num_regions_; } +e_blwl_protocol_type ConfigProtocol::bl_protocol_type() const { + return bl_protocol_type_; +} + +std::string ConfigProtocol::bl_memory_model_name() const { + return bl_memory_model_name_; +} + +CircuitModelId ConfigProtocol::bl_memory_model() const { + return bl_memory_model_; +} + +e_blwl_protocol_type ConfigProtocol::wl_protocol_type() const { + return wl_protocol_type_; +} + +std::string ConfigProtocol::wl_memory_model_name() const { + return wl_memory_model_name_; +} + +CircuitModelId ConfigProtocol::wl_memory_model() const { + return wl_memory_model_; +} + /************************************************************************ * Public Mutators ***********************************************************************/ @@ -50,3 +75,51 @@ void ConfigProtocol::set_memory_model(const CircuitModelId& memory_model) { void ConfigProtocol::set_num_regions(const int& num_regions) { num_regions_ = num_regions; } + +void ConfigProtocol::set_bl_protocol_type(const e_blwl_protocol_type& type) { + if (CONFIG_MEM_QL_MEMORY_BANK != type_) { + VTR_LOG_ERROR("BL protocol type is only applicable for configuration protocol '%d'", CONFIG_PROTOCOL_TYPE_STRING[type_]); + return; + } + bl_protocol_type_ = type; +} + +void ConfigProtocol::set_bl_memory_model_name(const std::string& memory_model_name) { + if (BLWL_PROTOCOL_SHIFT_REGISTER != bl_protocol_type_) { + VTR_LOG_ERROR("BL protocol memory model is only applicable when '%d' is defined", BLWL_PROTOCOL_TYPE_STRING[bl_protocol_type_]); + return; + } + bl_memory_model_name_ = memory_model_name; +} + +void ConfigProtocol::set_bl_memory_model(const CircuitModelId& memory_model) { + if (BLWL_PROTOCOL_SHIFT_REGISTER != bl_protocol_type_) { + VTR_LOG_ERROR("BL protocol memory model is only applicable when '%d' is defined", BLWL_PROTOCOL_TYPE_STRING[bl_protocol_type_]); + return; + } + bl_memory_model_ = memory_model; +} + +void ConfigProtocol::set_wl_protocol_type(const e_blwl_protocol_type& type) { + if (CONFIG_MEM_QL_MEMORY_BANK != type_) { + VTR_LOG_ERROR("WL protocol type is only applicable for configuration protocol '%d'", CONFIG_PROTOCOL_TYPE_STRING[type_]); + return; + } + wl_protocol_type_ = type; +} + +void ConfigProtocol::set_wl_memory_model_name(const std::string& memory_model_name) { + if (BLWL_PROTOCOL_SHIFT_REGISTER != wl_protocol_type_) { + VTR_LOG_ERROR("WL protocol memory model is only applicable when '%d' is defined", BLWL_PROTOCOL_TYPE_STRING[wl_protocol_type_]); + return; + } + wl_memory_model_name_ = memory_model_name; +} + +void ConfigProtocol::set_wl_memory_model(const CircuitModelId& memory_model) { + if (BLWL_PROTOCOL_SHIFT_REGISTER != wl_protocol_type_) { + VTR_LOG_ERROR("WL protocol memory model is only applicable when '%d' is defined", BLWL_PROTOCOL_TYPE_STRING[wl_protocol_type_]); + return; + } + wl_memory_model_ = memory_model; +} diff --git a/libopenfpga/libarchopenfpga/src/config_protocol.h b/libopenfpga/libarchopenfpga/src/config_protocol.h index 034805c65..24de1ff47 100644 --- a/libopenfpga/libarchopenfpga/src/config_protocol.h +++ b/libopenfpga/libarchopenfpga/src/config_protocol.h @@ -10,7 +10,7 @@ enum e_blwl_protocol_type { BLWL_PROTOCOL_FLATTEN, BLWL_PROTOCOL_DECODER, BLWL_PROTOCOL_SHIFT_REGISTER, - NUM_BLWL_PROTOCOLS_TYPES + NUM_BLWL_PROTOCOL_TYPES }; constexpr std::array BLWL_PROTOCOL_TYPE_STRING = {{"flatten", "decoder", "shift_register"}}; @@ -25,11 +25,25 @@ class ConfigProtocol { std::string memory_model_name() const; CircuitModelId memory_model() const; int num_regions() const; + + e_blwl_protocol_type bl_protocol_type() const; + std::string bl_memory_model_name() const; + CircuitModelId bl_memory_model() const; + e_blwl_protocol_type wl_protocol_type() const; + std::string wl_memory_model_name() const; + CircuitModelId wl_memory_model() const; public: /* Public Mutators */ void set_type(const e_config_protocol_type& type); void set_memory_model_name(const std::string& memory_model_name); void set_memory_model(const CircuitModelId& memory_model); void set_num_regions(const int& num_regions); + + void set_bl_protocol_type(const e_blwl_protocol_type& type); + void set_bl_memory_model_name(const std::string& memory_model_name); + void set_bl_memory_model(const CircuitModelId& memory_model); + void set_wl_protocol_type(const e_blwl_protocol_type& type); + void set_wl_memory_model_name(const std::string& memory_model_name); + void set_wl_memory_model(const CircuitModelId& memory_model); private: /* Internal data */ /* The type of configuration protocol. * In other words, it is about how to organize and access each configurable memory @@ -42,6 +56,19 @@ class ConfigProtocol { /* Number of configurable regions */ int num_regions_; + + /* BL & WL protocol: This is only applicable to memory-bank configuration protocols + * - type: defines which protocol to be used. By default, we consider decoders + * - bl/wl_memory_model: defines the circuit model to be used when building shift register chains for BL/WL configuration. + * It must be a valid CCFF circuit model. This is only applicable when shift-register protocol is selected + * for BL or WL. + */ + e_blwl_protocol_type bl_protocol_type_ = BLWL_PROTOCOL_DECODER; + std::string bl_memory_model_name_; + CircuitModelId bl_memory_model_; + e_blwl_protocol_type wl_protocol_type_ = BLWL_PROTOCOL_DECODER; + std::string wl_memory_model_name_; + CircuitModelId wl_memory_model_; }; #endif diff --git a/libopenfpga/libarchopenfpga/src/openfpga_arch_linker.cpp b/libopenfpga/libarchopenfpga/src/openfpga_arch_linker.cpp index eab105ec3..33009f537 100644 --- a/libopenfpga/libarchopenfpga/src/openfpga_arch_linker.cpp +++ b/libopenfpga/libarchopenfpga/src/openfpga_arch_linker.cpp @@ -22,6 +22,29 @@ void link_config_protocol_to_circuit_library(openfpga::Arch& openfpga_arch) { } openfpga_arch.config_protocol.set_memory_model(config_memory_model); + + /* Optional: we need to bind the memory model for BL/WL protocols */ + if (!openfpga_arch.config_protocol.bl_memory_model_name().empty()) { + CircuitModelId bl_memory_model = openfpga_arch.circuit_lib.model(openfpga_arch.config_protocol.bl_memory_model_name()); + /* Error out if the circuit model id is invalid */ + if (CircuitModelId::INVALID() == bl_memory_model) { + VTR_LOG("Invalid bl memory model name '%s' defined in !", + openfpga_arch.config_protocol.bl_memory_model_name().c_str()); + exit(1); + } + openfpga_arch.config_protocol.set_bl_memory_model(bl_memory_model); + } + + if (!openfpga_arch.config_protocol.wl_memory_model_name().empty()) { + CircuitModelId wl_memory_model = openfpga_arch.circuit_lib.model(openfpga_arch.config_protocol.wl_memory_model_name()); + /* Error out if the circuit model id is invalid */ + if (CircuitModelId::INVALID() == wl_memory_model) { + VTR_LOG("Invalid wl memory model name '%s' defined in !", + openfpga_arch.config_protocol.wl_memory_model_name().c_str()); + exit(1); + } + openfpga_arch.config_protocol.set_wl_memory_model(wl_memory_model); + } } /******************************************************************** diff --git a/libopenfpga/libarchopenfpga/src/read_xml_config_protocol.cpp b/libopenfpga/libarchopenfpga/src/read_xml_config_protocol.cpp index 1cbbb40c0..44edcbfc0 100644 --- a/libopenfpga/libarchopenfpga/src/read_xml_config_protocol.cpp +++ b/libopenfpga/libarchopenfpga/src/read_xml_config_protocol.cpp @@ -33,6 +33,73 @@ e_config_protocol_type string_to_config_protocol_type(const std::string& type_st return NUM_CONFIG_PROTOCOL_TYPES; } +/******************************************************************** + * Convert string to the enumerate of BL/WL protocol type + *******************************************************************/ +static +e_blwl_protocol_type string_to_blwl_protocol_type(const std::string& type_string) { + + for (size_t itype = 0; itype < NUM_BLWL_PROTOCOL_TYPES; ++itype) { + if (std::string(BLWL_PROTOCOL_TYPE_STRING[itype]) == type_string) { + return static_cast(itype); + } + } + + return NUM_BLWL_PROTOCOL_TYPES; +} + +/******************************************************************** + * Parse XML codes of a to an object of configuration protocol + *******************************************************************/ +static +void read_xml_bl_protocol(pugi::xml_node& xml_bl_protocol, + const pugiutil::loc_data& loc_data, + ConfigProtocol& config_protocol) { + /* Find the type of configuration protocol */ + const char* type_attr = get_attribute(xml_bl_protocol, "protocol", loc_data).value(); + /* Translate the type of design technology to enumerate */ + e_blwl_protocol_type blwl_protocol_type = string_to_blwl_protocol_type(std::string(type_attr)); + + if (NUM_BLWL_PROTOCOL_TYPES == blwl_protocol_type) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_bl_protocol), + "Invalid 'protocol' attribute '%s'\n", + type_attr); + } + + config_protocol.set_bl_protocol_type(blwl_protocol_type); + + /* Find the memory model, only applicable to shift-registor protocol */ + if (BLWL_PROTOCOL_SHIFT_REGISTER == blwl_protocol_type) { + config_protocol.set_bl_memory_model_name(get_attribute(xml_bl_protocol, "circuit_model_name", loc_data).as_string()); + } +} + +/******************************************************************** + * Parse XML codes of a to an object of configuration protocol + *******************************************************************/ +static +void read_xml_wl_protocol(pugi::xml_node& xml_wl_protocol, + const pugiutil::loc_data& loc_data, + ConfigProtocol& config_protocol) { + /* Find the type of configuration protocol */ + const char* type_attr = get_attribute(xml_wl_protocol, "protocol", loc_data).value(); + /* Translate the type of design technology to enumerate */ + e_blwl_protocol_type blwl_protocol_type = string_to_blwl_protocol_type(std::string(type_attr)); + + if (NUM_BLWL_PROTOCOL_TYPES == blwl_protocol_type) { + archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_wl_protocol), + "Invalid 'protocol' attribute '%s'\n", + type_attr); + } + + config_protocol.set_wl_protocol_type(blwl_protocol_type); + + /* Find the memory model, only applicable to shift-registor protocol */ + if (BLWL_PROTOCOL_SHIFT_REGISTER == blwl_protocol_type) { + config_protocol.set_wl_memory_model_name(get_attribute(xml_wl_protocol, "circuit_model_name", loc_data).as_string()); + } +} + /******************************************************************** * Parse XML codes of a to an object of configuration protocol *******************************************************************/ @@ -65,6 +132,15 @@ void read_xml_config_organization(pugi::xml_node& xml_config_orgz, "Invalid 'num_region=%d' definition. At least 1 region should be defined!\n", config_protocol.num_regions()); } + + /* Parse BL & WL protocols */ + if (config_protocol.type() == CONFIG_MEM_QL_MEMORY_BANK) { + pugi::xml_node xml_bl_protocol = get_single_child(xml_config_orgz, "bl", loc_data); + read_xml_bl_protocol(xml_bl_protocol, loc_data, config_protocol); + + pugi::xml_node xml_wl_protocol = get_single_child(xml_config_orgz, "wl", loc_data); + read_xml_wl_protocol(xml_wl_protocol, loc_data, config_protocol); + } } /******************************************************************** From 8c281a22b09a8ab2ef410147acc4afb727420a74 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 23 Sep 2021 14:39:16 -0700 Subject: [PATCH 09/28] [Engine] Add check codes to validate circuit models for BL/WL protocols --- openfpga/src/base/openfpga_read_arch.cpp | 5 +-- openfpga/src/utils/circuit_library_utils.cpp | 42 ++++++++++++++++---- openfpga/src/utils/circuit_library_utils.h | 7 ++-- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/openfpga/src/base/openfpga_read_arch.cpp b/openfpga/src/base/openfpga_read_arch.cpp index 25bfc3831..56d96f740 100644 --- a/openfpga/src/base/openfpga_read_arch.cpp +++ b/openfpga/src/base/openfpga_read_arch.cpp @@ -56,9 +56,8 @@ int read_arch(OpenfpgaContext& openfpga_context, return CMD_EXEC_FATAL_ERROR; } - if (false == check_configurable_memory_circuit_model(openfpga_context.arch().config_protocol.type(), - openfpga_context.arch().circuit_lib, - openfpga_context.arch().config_protocol.memory_model())) { + if (false == check_configurable_memory_circuit_model(openfpga_context.arch().config_protocol, + openfpga_context.arch().circuit_lib)) { return CMD_EXEC_FATAL_ERROR; } diff --git a/openfpga/src/utils/circuit_library_utils.cpp b/openfpga/src/utils/circuit_library_utils.cpp index fabdc05da..bb59a0601 100644 --- a/openfpga/src/utils/circuit_library_utils.cpp +++ b/openfpga/src/utils/circuit_library_utils.cpp @@ -280,22 +280,50 @@ std::vector find_circuit_library_unique_spice_netlists(const Circui * Advanced check if the circuit model of configurable memory * satisfy the needs of configuration protocol * - Configuration chain -based: we check if we have a CCFF model - * - Frame -based: we check if we have a SRAM model which has BL and WL - * + * - Flatten/Frame -based: we check if we have a SRAM model which has BL and WL + * - Memory bank: we check if we have a SRAM model. Also we need to check if we have valid CCFF models for BL/WL models (if selected) ***********************************************************************/ -bool check_configurable_memory_circuit_model(const e_config_protocol_type& config_protocol_type, - const CircuitLibrary& circuit_lib, - const CircuitModelId& config_mem_circuit_model) { +bool check_configurable_memory_circuit_model(const ConfigProtocol& config_protocol, + const CircuitLibrary& circuit_lib) { size_t num_err = 0; + CircuitModelId config_mem_circuit_model = config_protocol.memory_model(); - switch (config_protocol_type) { + switch (config_protocol.type()) { case CONFIG_MEM_SCAN_CHAIN: num_err = check_ccff_circuit_model_ports(circuit_lib, config_mem_circuit_model); break; + case CONFIG_MEM_QL_MEMORY_BANK: { + num_err = check_sram_circuit_model_ports(circuit_lib, + config_mem_circuit_model, + true); + /* Check circuit model for BL protocol */ + CircuitModelId bl_memory_model = config_protocol.bl_memory_model(); + if ( BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type() + && CircuitModelId::INVALID() == bl_memory_model) { + VTR_LOG_ERROR("Expect a valid CCFF circuit model for BL protocol"); + num_err++; + } + if (bl_memory_model) { + num_err += check_ccff_circuit_model_ports(circuit_lib, + bl_memory_model); + } + + /* Check circuit model for WL protocol */ + CircuitModelId wl_memory_model = config_protocol.wl_memory_model(); + if ( BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type() + && CircuitModelId::INVALID() == wl_memory_model) { + VTR_LOG_ERROR("Expect a valid CCFF circuit model for WL protocol"); + num_err++; + } + if (wl_memory_model) { + num_err += check_ccff_circuit_model_ports(circuit_lib, + wl_memory_model); + } + break; + } case CONFIG_MEM_STANDALONE: case CONFIG_MEM_MEMORY_BANK: - case CONFIG_MEM_QL_MEMORY_BANK: case CONFIG_MEM_FRAME_BASED: num_err = check_sram_circuit_model_ports(circuit_lib, config_mem_circuit_model, diff --git a/openfpga/src/utils/circuit_library_utils.h b/openfpga/src/utils/circuit_library_utils.h index 758af9689..fe5fb03f7 100644 --- a/openfpga/src/utils/circuit_library_utils.h +++ b/openfpga/src/utils/circuit_library_utils.h @@ -8,8 +8,8 @@ * Include header files that are required by function declaration *******************************************************************/ #include -#include "circuit_types.h" #include "circuit_library.h" +#include "config_protocol.h" /******************************************************************** * Function declaration @@ -41,9 +41,8 @@ std::vector find_circuit_library_unique_verilog_netlists(const Circ std::vector find_circuit_library_unique_spice_netlists(const CircuitLibrary& circuit_lib); -bool check_configurable_memory_circuit_model(const e_config_protocol_type& config_protocol_type, - const CircuitLibrary& circuit_lib, - const CircuitModelId& config_mem_circuit_model); +bool check_configurable_memory_circuit_model(const ConfigProtocol& config_protocol, + const CircuitLibrary& circuit_lib); CircuitPortId find_circuit_model_power_gate_en_port(const CircuitLibrary& circuit_lib, const CircuitModelId& circuit_model); From 7e27c0caf3945b86b69893567755118a7f47b714 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Thu, 23 Sep 2021 16:16:39 -0700 Subject: [PATCH 10/28] [Engine] Upgrading top-module fabric generation to support QL memory bank with flatten BL/WLs --- .../src/fabric/build_top_module_memory.cpp | 30 +---- .../fabric/build_top_module_memory_bank.cpp | 113 ++++++++++++++++++ .../src/fabric/build_top_module_memory_bank.h | 8 ++ 3 files changed, 122 insertions(+), 29 deletions(-) diff --git a/openfpga/src/fabric/build_top_module_memory.cpp b/openfpga/src/fabric/build_top_module_memory.cpp index ca78f8e88..7c2252883 100644 --- a/openfpga/src/fabric/build_top_module_memory.cpp +++ b/openfpga/src/fabric/build_top_module_memory.cpp @@ -852,35 +852,7 @@ void add_top_module_sram_ports(ModuleManager& module_manager, break; } case CONFIG_MEM_QL_MEMORY_BANK: { - BasicPort en_port(std::string(DECODER_ENABLE_PORT_NAME), 1); - module_manager.add_port(module_id, en_port, ModuleManager::MODULE_INPUT_PORT); - - /* BL address size is the largest among all the regions */ - size_t bl_addr_size = 0; - for (const ConfigRegionId& config_region : module_manager.regions(module_id)) { - bl_addr_size = std::max(bl_addr_size, find_mux_local_decoder_addr_size(num_config_bits[config_region].first)); - } - BasicPort bl_addr_port(std::string(DECODER_BL_ADDRESS_PORT_NAME), bl_addr_size); - module_manager.add_port(module_id, bl_addr_port, ModuleManager::MODULE_INPUT_PORT); - - /* WL address size is the largest among all the regions */ - size_t wl_addr_size = 0; - for (const ConfigRegionId& config_region : module_manager.regions(module_id)) { - wl_addr_size = std::max(wl_addr_size, find_mux_local_decoder_addr_size(num_config_bits[config_region].second)); - } - BasicPort wl_addr_port(std::string(DECODER_WL_ADDRESS_PORT_NAME), wl_addr_size); - module_manager.add_port(module_id, wl_addr_port, ModuleManager::MODULE_INPUT_PORT); - - /* Optional: If we have WLR port, we should add a read-back port */ - if (!circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_WLR).empty()) { - BasicPort readback_port(std::string(DECODER_READBACK_PORT_NAME), config_protocol.num_regions()); - module_manager.add_port(module_id, readback_port, ModuleManager::MODULE_INPUT_PORT); - } - - /* Data input should be dependent on the number of configuration regions*/ - BasicPort din_port(std::string(DECODER_DATA_IN_PORT_NAME), config_protocol.num_regions()); - module_manager.add_port(module_id, din_port, ModuleManager::MODULE_INPUT_PORT); - + add_top_module_ql_memory_bank_sram_ports(module_manager, module_id, circuit_lib, config_protocol, num_config_bits); break; } case CONFIG_MEM_SCAN_CHAIN: { diff --git a/openfpga/src/fabric/build_top_module_memory_bank.cpp b/openfpga/src/fabric/build_top_module_memory_bank.cpp index 7c60a03d8..723d102d5 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.cpp +++ b/openfpga/src/fabric/build_top_module_memory_bank.cpp @@ -474,4 +474,117 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma } } +/******************************************************************** + * Add a list of ports that are used for SRAM configuration to the FPGA + * top-level module + * - Add ports for BL control circuitry: + * - Decoder + * - an enable signals + * - an BL address port + * - a data-in port + * - Flatten + * - BL ports + * - TODO: Shift registers + * - Head of shift register chain for BLs + * - Tail of shift register chain for BLs + * + * - Add ports for WL control circuitry: + * - Decoder + * - an WL address port + * - a Readback port (Optional, only needed when WLR is required) + * - Flatten + * - WL ports + * - WLR ports (Optional) + * - TODO: Shift registers + * - Head of shift register chain for WLs + * - Tail of shift register chain for WLs + * - a Readback port (Optional, only needed when WLR is required) + * + * @note In this memory decoders, the address size will be computed in a different way than the regular one + ********************************************************************/ +void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager, + const ModuleId& module_id, + const CircuitLibrary& circuit_lib, + const ConfigProtocol& config_protocol, + const TopModuleNumConfigBits& num_config_bits) { + VTR_ASSERT_SAFE(CONFIG_MEM_QL_MEMORY_BANK == config_protocol.type()); + CircuitModelId sram_model = config_protocol.memory_model(); + + switch (config_protocol.bl_protocol_type()) { + case BLWL_PROTOCOL_DECODER: { + /* Add enable signals */ + BasicPort en_port(std::string(DECODER_ENABLE_PORT_NAME), 1); + module_manager.add_port(module_id, en_port, ModuleManager::MODULE_INPUT_PORT); + + /* BL address size is the largest among all the regions */ + size_t bl_addr_size = 0; + for (const ConfigRegionId& config_region : module_manager.regions(module_id)) { + bl_addr_size = std::max(bl_addr_size, find_mux_local_decoder_addr_size(num_config_bits[config_region].first)); + } + BasicPort bl_addr_port(std::string(DECODER_BL_ADDRESS_PORT_NAME), bl_addr_size); + module_manager.add_port(module_id, bl_addr_port, ModuleManager::MODULE_INPUT_PORT); + + /* Data input should be dependent on the number of configuration regions*/ + BasicPort din_port(std::string(DECODER_DATA_IN_PORT_NAME), config_protocol.num_regions()); + module_manager.add_port(module_id, din_port, ModuleManager::MODULE_INPUT_PORT); + break; + } + case BLWL_PROTOCOL_FLATTEN: { + /* BL size is the largest among all the regions */ + size_t bl_size = 0; + for (const ConfigRegionId& config_region : module_manager.regions(module_id)) { + bl_size = std::max(bl_size, num_config_bits[config_region].first); + } + BasicPort bl_port(std::string(MEMORY_BL_PORT_NAME), bl_size); + module_manager.add_port(module_id, bl_port, ModuleManager::MODULE_INPUT_PORT); + break; + } + case BLWL_PROTOCOL_SHIFT_REGISTER: { + /* TODO */ + break; + } + default: { + VTR_LOG_ERROR("Invalid BL protocol"); + exit(1); + } + } + + switch (config_protocol.wl_protocol_type()) { + case BLWL_PROTOCOL_DECODER: { + /* WL address size is the largest among all the regions */ + size_t wl_addr_size = 0; + for (const ConfigRegionId& config_region : module_manager.regions(module_id)) { + wl_addr_size = std::max(wl_addr_size, find_mux_local_decoder_addr_size(num_config_bits[config_region].second)); + } + BasicPort wl_addr_port(std::string(DECODER_WL_ADDRESS_PORT_NAME), wl_addr_size); + module_manager.add_port(module_id, wl_addr_port, ModuleManager::MODULE_INPUT_PORT); + + /* Optional: If we have WLR port, we should add a read-back port */ + if (!circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_WLR).empty()) { + BasicPort readback_port(std::string(DECODER_READBACK_PORT_NAME), config_protocol.num_regions()); + module_manager.add_port(module_id, readback_port, ModuleManager::MODULE_INPUT_PORT); + } + break; + } + case BLWL_PROTOCOL_FLATTEN: { + /* WL size is the largest among all the regions */ + size_t wl_size = 0; + for (const ConfigRegionId& config_region : module_manager.regions(module_id)) { + wl_size = std::max(wl_size, num_config_bits[config_region].first); + } + BasicPort wl_port(std::string(MEMORY_WL_PORT_NAME), wl_size); + module_manager.add_port(module_id, wl_port, ModuleManager::MODULE_INPUT_PORT); + break; + } + case BLWL_PROTOCOL_SHIFT_REGISTER: { + /* TODO */ + break; + } + default: { + VTR_LOG_ERROR("Invalid WL protocol"); + exit(1); + } + } +} + } /* end namespace openfpga */ diff --git a/openfpga/src/fabric/build_top_module_memory_bank.h b/openfpga/src/fabric/build_top_module_memory_bank.h index 69f4408ef..50e9567c9 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.h +++ b/openfpga/src/fabric/build_top_module_memory_bank.h @@ -10,6 +10,7 @@ #include "vtr_vector.h" #include "vtr_ndmatrix.h" #include "module_manager.h" +#include "config_protocol.h" #include "circuit_library.h" #include "decoder_library.h" #include "build_top_module_memory_utils.h" @@ -28,6 +29,13 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma const CircuitModelId& sram_model, const TopModuleNumConfigBits& num_config_bits); +void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager, + const ModuleId& module_id, + const CircuitLibrary& circuit_lib, + const ConfigProtocol& config_protocol, + const TopModuleNumConfigBits& num_config_bits); + + } /* end namespace openfpga */ #endif From 18257b3fa1e3c9a859c59d0f8366bff149865f3f Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 24 Sep 2021 11:07:58 -0700 Subject: [PATCH 11/28] [Engine] Update BL/WL port addition for the top-level module in fabric generator --- openfpga/src/base/openfpga_naming.cpp | 9 +++++++++ openfpga/src/base/openfpga_naming.h | 4 ++++ .../fabric/build_top_module_memory_bank.cpp | 18 ++++++++---------- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/openfpga/src/base/openfpga_naming.cpp b/openfpga/src/base/openfpga_naming.cpp index 3dab1ca7f..c3fdd3aa8 100644 --- a/openfpga/src/base/openfpga_naming.cpp +++ b/openfpga/src/base/openfpga_naming.cpp @@ -813,6 +813,15 @@ std::string generate_sram_local_port_name(const CircuitLibrary& circuit_lib, return port_name; } +/********************************************************************* + * Generate the BL/WL port names for the top-level module of an FPGA fabric + * Each BL/WL bus drive a specific configuration region has an unique name + *********************************************************************/ +std::string generate_regional_blwl_port_name(const std::string& blwl_port_prefix, + const ConfigRegionId& region_id) { + return blwl_port_prefix + std::string("_config_region_") + std::to_string(size_t(region_id)); +} + /********************************************************************* * Generate the port name for the input bus of a routing multiplexer * This is very useful in Verilog code generation where the inputs of diff --git a/openfpga/src/base/openfpga_naming.h b/openfpga/src/base/openfpga_naming.h index 319e99a60..77a46e4a6 100644 --- a/openfpga/src/base/openfpga_naming.h +++ b/openfpga/src/base/openfpga_naming.h @@ -16,6 +16,7 @@ #include "circuit_library.h" #include "device_grid.h" #include "openfpga_port.h" +#include "module_manager_fwd.h" /******************************************************************** * Function declaration @@ -183,6 +184,9 @@ std::string generate_sram_local_port_name(const CircuitLibrary& circuit_lib, const e_config_protocol_type& sram_orgz_type, const e_circuit_model_port_type& port_type); +std::string generate_regional_blwl_port_name(const std::string& blwl_port_prefix, + const ConfigRegionId& region_id); + std::string generate_mux_input_bus_port_name(const CircuitLibrary& circuit_lib, const CircuitModelId& mux_model, const size_t& mux_size, diff --git a/openfpga/src/fabric/build_top_module_memory_bank.cpp b/openfpga/src/fabric/build_top_module_memory_bank.cpp index 723d102d5..b5bd39b6f 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.cpp +++ b/openfpga/src/fabric/build_top_module_memory_bank.cpp @@ -530,13 +530,12 @@ void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager, break; } case BLWL_PROTOCOL_FLATTEN: { - /* BL size is the largest among all the regions */ - size_t bl_size = 0; + /* Each region will have independent BLs */ for (const ConfigRegionId& config_region : module_manager.regions(module_id)) { - bl_size = std::max(bl_size, num_config_bits[config_region].first); + size_t bl_size = num_config_bits[config_region].first; + BasicPort bl_port(generate_regional_blwl_port_name(std::string(MEMORY_BL_PORT_NAME), config_region), bl_size); + module_manager.add_port(module_id, bl_port, ModuleManager::MODULE_INPUT_PORT); } - BasicPort bl_port(std::string(MEMORY_BL_PORT_NAME), bl_size); - module_manager.add_port(module_id, bl_port, ModuleManager::MODULE_INPUT_PORT); break; } case BLWL_PROTOCOL_SHIFT_REGISTER: { @@ -567,13 +566,12 @@ void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager, break; } case BLWL_PROTOCOL_FLATTEN: { - /* WL size is the largest among all the regions */ - size_t wl_size = 0; + /* Each region will have independent WLs */ for (const ConfigRegionId& config_region : module_manager.regions(module_id)) { - wl_size = std::max(wl_size, num_config_bits[config_region].first); + size_t wl_size = num_config_bits[config_region].first; + BasicPort wl_port(generate_regional_blwl_port_name(std::string(MEMORY_WL_PORT_NAME), config_region), wl_size); + module_manager.add_port(module_id, wl_port, ModuleManager::MODULE_INPUT_PORT); } - BasicPort wl_port(std::string(MEMORY_WL_PORT_NAME), wl_size); - module_manager.add_port(module_id, wl_port, ModuleManager::MODULE_INPUT_PORT); break; } case BLWL_PROTOCOL_SHIFT_REGISTER: { From be4c850d2d5f42d607aa79b96c310115afe1fe21 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 24 Sep 2021 12:03:35 -0700 Subject: [PATCH 12/28] [Engine] Split the function to add BL/WL configuration bus connections for support flatten BL/WLs --- .../src/read_xml_config_protocol.cpp | 12 +- openfpga/src/fabric/build_top_module.cpp | 2 +- .../src/fabric/build_top_module_memory.cpp | 5 +- openfpga/src/fabric/build_top_module_memory.h | 1 - .../fabric/build_top_module_memory_bank.cpp | 312 ++++++++++++------ .../src/fabric/build_top_module_memory_bank.h | 2 +- 6 files changed, 219 insertions(+), 115 deletions(-) diff --git a/libopenfpga/libarchopenfpga/src/read_xml_config_protocol.cpp b/libopenfpga/libarchopenfpga/src/read_xml_config_protocol.cpp index 44edcbfc0..ebfe64782 100644 --- a/libopenfpga/libarchopenfpga/src/read_xml_config_protocol.cpp +++ b/libopenfpga/libarchopenfpga/src/read_xml_config_protocol.cpp @@ -135,11 +135,15 @@ void read_xml_config_organization(pugi::xml_node& xml_config_orgz, /* Parse BL & WL protocols */ if (config_protocol.type() == CONFIG_MEM_QL_MEMORY_BANK) { - pugi::xml_node xml_bl_protocol = get_single_child(xml_config_orgz, "bl", loc_data); - read_xml_bl_protocol(xml_bl_protocol, loc_data, config_protocol); + pugi::xml_node xml_bl_protocol = get_single_child(xml_config_orgz, "bl", loc_data, pugiutil::ReqOpt::OPTIONAL); + if (xml_bl_protocol) { + read_xml_bl_protocol(xml_bl_protocol, loc_data, config_protocol); + } - pugi::xml_node xml_wl_protocol = get_single_child(xml_config_orgz, "wl", loc_data); - read_xml_wl_protocol(xml_wl_protocol, loc_data, config_protocol); + pugi::xml_node xml_wl_protocol = get_single_child(xml_config_orgz, "wl", loc_data, pugiutil::ReqOpt::OPTIONAL); + if (xml_wl_protocol) { + read_xml_wl_protocol(xml_wl_protocol, loc_data, config_protocol); + } } } diff --git a/openfpga/src/fabric/build_top_module.cpp b/openfpga/src/fabric/build_top_module.cpp index add2ea30b..421b7198a 100644 --- a/openfpga/src/fabric/build_top_module.cpp +++ b/openfpga/src/fabric/build_top_module.cpp @@ -422,7 +422,7 @@ int build_top_module(ModuleManager& module_manager, if (0 < module_manager.configurable_children(top_module).size()) { add_top_module_nets_memory_config_bus(module_manager, decoder_lib, top_module, - circuit_lib, sram_model, + circuit_lib, config_protocol, circuit_lib.design_tech_type(sram_model), top_module_num_config_bits); } diff --git a/openfpga/src/fabric/build_top_module_memory.cpp b/openfpga/src/fabric/build_top_module_memory.cpp index 7c2252883..42debe24f 100644 --- a/openfpga/src/fabric/build_top_module_memory.cpp +++ b/openfpga/src/fabric/build_top_module_memory.cpp @@ -1737,7 +1737,6 @@ void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager, DecoderLibrary& decoder_lib, const ModuleId& parent_module, const CircuitLibrary& circuit_lib, - const CircuitModelId& sram_model, const ConfigProtocol& config_protocol, const TopModuleNumConfigBits& num_config_bits) { switch (config_protocol.type()) { @@ -1755,7 +1754,7 @@ void add_top_module_nets_cmos_memory_config_bus(ModuleManager& module_manager, add_top_module_nets_cmos_memory_bank_config_bus(module_manager, decoder_lib, parent_module, num_config_bits); break; case CONFIG_MEM_QL_MEMORY_BANK: - add_top_module_nets_cmos_ql_memory_bank_config_bus(module_manager, decoder_lib, parent_module, circuit_lib, sram_model, num_config_bits); + add_top_module_nets_cmos_ql_memory_bank_config_bus(module_manager, decoder_lib, parent_module, circuit_lib, config_protocol, num_config_bits); break; case CONFIG_MEM_FRAME_BASED: add_top_module_nets_cmos_memory_frame_config_bus(module_manager, decoder_lib, parent_module, num_config_bits); @@ -1803,7 +1802,6 @@ void add_top_module_nets_memory_config_bus(ModuleManager& module_manager, DecoderLibrary& decoder_lib, const ModuleId& parent_module, const CircuitLibrary& circuit_lib, - const CircuitModelId& sram_model, const ConfigProtocol& config_protocol, const e_circuit_model_design_tech& mem_tech, const TopModuleNumConfigBits& num_config_bits) { @@ -1815,7 +1813,6 @@ void add_top_module_nets_memory_config_bus(ModuleManager& module_manager, add_top_module_nets_cmos_memory_config_bus(module_manager, decoder_lib, parent_module, circuit_lib, - sram_model, config_protocol, num_config_bits); break; diff --git a/openfpga/src/fabric/build_top_module_memory.h b/openfpga/src/fabric/build_top_module_memory.h index 336125df0..7b6f9aa10 100644 --- a/openfpga/src/fabric/build_top_module_memory.h +++ b/openfpga/src/fabric/build_top_module_memory.h @@ -66,7 +66,6 @@ void add_top_module_nets_memory_config_bus(ModuleManager& module_manager, DecoderLibrary& decoder_lib, const ModuleId& parent_module, const CircuitLibrary& circuit_lib, - const CircuitModelId& sram_model, const ConfigProtocol& config_protocol, const e_circuit_model_design_tech& mem_tech, const TopModuleNumConfigBits& num_config_bits); diff --git a/openfpga/src/fabric/build_top_module_memory_bank.cpp b/openfpga/src/fabric/build_top_module_memory_bank.cpp index b5bd39b6f..a974fc736 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.cpp +++ b/openfpga/src/fabric/build_top_module_memory_bank.cpp @@ -31,13 +31,15 @@ namespace openfpga { /********************************************************************* - * Top-level function to add nets for quicklogic memory banks + * This function to add nets for quicklogic memory banks * Each configuration region has independent memory bank circuitry * - Find the number of BLs and WLs required for each region * - Create BL and WL decoders, and add them to decoder library * - Create nets to connect from top-level module inputs to inputs of decoders * - Create nets to connect from outputs of decoders to BL/WL of configurable children * + * @note this function only adds the BL configuration bus for decoders + * * Detailed schematic of how memory banks are connected in the top-level: * Consider a random Region X, local BL address lines are aligned to the LSB of the * top-level BL address lines @@ -120,12 +122,13 @@ namespace openfpga { * +---------+ * **********************************************************************/ -void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_manager, - DecoderLibrary& decoder_lib, - const ModuleId& top_module, - const CircuitLibrary& circuit_lib, - const CircuitModelId& sram_model, - const TopModuleNumConfigBits& num_config_bits) { +static +void add_top_module_nets_cmos_ql_memory_bank_bl_decoder_config_bus(ModuleManager& module_manager, + DecoderLibrary& decoder_lib, + const ModuleId& top_module, + const CircuitLibrary& circuit_lib, + const CircuitModelId& sram_model, + const TopModuleNumConfigBits& num_config_bits) { /* Find Enable port from the top-level module */ ModulePortId en_port = module_manager.find_module_port(top_module, std::string(DECODER_ENABLE_PORT_NAME)); BasicPort en_port_info = module_manager.module_port(top_module, en_port); @@ -137,26 +140,12 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma /* Data in port should match the number of configuration regions */ VTR_ASSERT(din_port_info.get_width() == module_manager.regions(top_module).size()); - /* Find readback port from the top-level module */ - ModulePortId readback_port = module_manager.find_module_port(top_module, std::string(DECODER_READBACK_PORT_NAME)); - BasicPort readback_port_info; - - /* Readback port if available, should be a 1-bit port */ - if (readback_port) { - readback_port_info = module_manager.module_port(top_module, readback_port); - VTR_ASSERT(readback_port_info.get_width() == 1); - } - /* Find BL and WL address port from the top-level module */ ModulePortId bl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_BL_ADDRESS_PORT_NAME)); BasicPort bl_addr_port_info = module_manager.module_port(top_module, bl_addr_port); - ModulePortId wl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_WL_ADDRESS_PORT_NAME)); - BasicPort wl_addr_port_info = module_manager.module_port(top_module, wl_addr_port); - /* Find the top-level number of BLs and WLs required to access each memory bit */ size_t bl_addr_size = bl_addr_port_info.get_width(); - size_t wl_addr_size = wl_addr_port_info.get_width(); /* Each memory bank has a unified number of BL/WLs */ size_t num_bls = 0; @@ -164,11 +153,6 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma num_bls = std::max(num_bls, curr_config_bits.first); } - size_t num_wls = 0; - for (const auto& curr_config_bits : num_config_bits) { - num_wls = std::max(num_wls, curr_config_bits.second); - } - /* Create separated memory bank circuitry, i.e., BL/WL decoders for each region */ for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { /************************************************************** @@ -199,34 +183,6 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma size_t curr_bl_decoder_instance_id = module_manager.num_instance(top_module, bl_decoder_module); module_manager.add_child_module(top_module, bl_decoder_module); - /************************************************************** - * Add the WL decoder module - * Search the decoder library - * If we find one, we use the module. - * Otherwise, we create one and add it to the decoder library - */ - DecoderId wl_decoder_id = decoder_lib.find_decoder(wl_addr_size, num_wls, - true, false, false, readback_port != ModulePortId::INVALID()); - if (DecoderId::INVALID() == wl_decoder_id) { - wl_decoder_id = decoder_lib.add_decoder(wl_addr_size, num_wls, true, false, false, readback_port != ModulePortId::INVALID()); - } - VTR_ASSERT(DecoderId::INVALID() != wl_decoder_id); - - /* Create a module if not existed yet */ - std::string wl_decoder_module_name = generate_memory_decoder_subckt_name(wl_addr_size, num_wls); - ModuleId wl_decoder_module = module_manager.find_module(wl_decoder_module_name); - if (ModuleId::INVALID() == wl_decoder_module) { - /* BL decoder has the same ports as the frame-based decoders - * We reuse it here - */ - wl_decoder_module = build_wl_memory_decoder_module(module_manager, - decoder_lib, - wl_decoder_id); - } - VTR_ASSERT(ModuleId::INVALID() != wl_decoder_module); - size_t curr_wl_decoder_instance_id = module_manager.num_instance(top_module, wl_decoder_module); - module_manager.add_child_module(top_module, wl_decoder_module); - /************************************************************** * Add module nets from the top module to BL decoder's inputs */ @@ -267,57 +223,15 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma /* Configure the net sink */ module_manager.add_module_net_sink(top_module, din_net, bl_decoder_module, curr_bl_decoder_instance_id, bl_decoder_din_port, bl_decoder_din_port_info.pins()[0]); - /************************************************************** - * Add module nets from the top module to WL decoder's inputs - */ - ModulePortId wl_decoder_en_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_ENABLE_PORT_NAME)); - BasicPort wl_decoder_en_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_en_port); - - ModulePortId wl_decoder_addr_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_ADDRESS_PORT_NAME)); - BasicPort wl_decoder_addr_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_addr_port); - - ModulePortId wl_decoder_readback_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_READBACK_PORT_NAME)); - BasicPort wl_decoder_readback_port_info; - if (wl_decoder_readback_port) { - wl_decoder_readback_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_readback_port); - } - - /* Top module Enable port -> WL Decoder Enable port */ - add_module_bus_nets(module_manager, - top_module, - top_module, 0, en_port, - wl_decoder_module, curr_wl_decoder_instance_id, wl_decoder_en_port); - - /* Top module Address port -> WL Decoder Address port */ - add_module_bus_nets(module_manager, - top_module, - top_module, 0, wl_addr_port, - wl_decoder_module, curr_wl_decoder_instance_id, wl_decoder_addr_port); - - /* Top module readback port -> WL Decoder readback port */ - if (wl_decoder_readback_port) { - add_module_bus_nets(module_manager, - top_module, - top_module, 0, readback_port, - wl_decoder_module, curr_wl_decoder_instance_id, wl_decoder_readback_port); - } - /************************************************************** * Precompute the BLs and WLs distribution across the FPGA fabric * The distribution is a matrix which contains the starting index of BL/WL for each column or row */ std::pair child_x_range = compute_memory_bank_regional_configurable_child_x_range(module_manager, top_module, config_region); - std::pair child_y_range = compute_memory_bank_regional_configurable_child_y_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 num_wls_per_tile = compute_memory_bank_regional_wordline_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); - std::map wl_start_index_per_tile = compute_memory_bank_regional_blwl_start_index_per_tile(child_y_range, num_wls_per_tile); /************************************************************** * Add nets from BL data out to each configurable child @@ -378,13 +292,148 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma } } + /************************************************************** + * Add the BL and WL decoders to the end of configurable children list + * Note: this MUST be done after adding all the module nets to other regular configurable children + */ + module_manager.add_configurable_child(top_module, bl_decoder_module, curr_bl_decoder_instance_id); + module_manager.add_configurable_child_to_region(top_module, + config_region, + bl_decoder_module, + curr_bl_decoder_instance_id, + module_manager.configurable_children(top_module).size() - 1); + } +} + +/********************************************************************* + * Top-level function to add nets for quicklogic memory banks + * Each configuration region has independent memory bank circuitry + * - Find the number of BLs and WLs required for each region + * - Create BL and WL decoders, and add them to decoder library + * - Create nets to connect from top-level module inputs to inputs of decoders + * - Create nets to connect from outputs of decoders to BL/WL of configurable children + * + * @note this function only adds the WL configuration bus for decoders + * + * @note see detailed explanation on the bus connection in function add_top_module_nets_cmos_ql_memory_bank_config_bus() + **********************************************************************/ +static +void add_top_module_nets_cmos_ql_memory_bank_wl_decoder_config_bus(ModuleManager& module_manager, + DecoderLibrary& decoder_lib, + const ModuleId& top_module, + const CircuitLibrary& circuit_lib, + const CircuitModelId& sram_model, + const TopModuleNumConfigBits& num_config_bits) { + /* Find Enable port from the top-level module */ + ModulePortId en_port = module_manager.find_module_port(top_module, std::string(DECODER_ENABLE_PORT_NAME)); + BasicPort en_port_info = module_manager.module_port(top_module, en_port); + + /* Find readback port from the top-level module */ + ModulePortId readback_port = module_manager.find_module_port(top_module, std::string(DECODER_READBACK_PORT_NAME)); + BasicPort readback_port_info; + + /* Readback port if available, should be a 1-bit port */ + if (readback_port) { + readback_port_info = module_manager.module_port(top_module, readback_port); + VTR_ASSERT(readback_port_info.get_width() == 1); + } + + /* Find BL and WL address port from the top-level module */ + ModulePortId wl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_WL_ADDRESS_PORT_NAME)); + BasicPort wl_addr_port_info = module_manager.module_port(top_module, wl_addr_port); + + /* Find the top-level number of BLs and WLs required to access each memory bit */ + size_t wl_addr_size = wl_addr_port_info.get_width(); + + /* Each memory bank has a unified number of BL/WLs */ + size_t num_wls = 0; + for (const auto& curr_config_bits : num_config_bits) { + num_wls = std::max(num_wls, curr_config_bits.second); + } + + /* Create separated memory bank circuitry, i.e., BL/WL decoders for each region */ + for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { + /************************************************************** + * Add the WL decoder module + * Search the decoder library + * If we find one, we use the module. + * Otherwise, we create one and add it to the decoder library + */ + DecoderId wl_decoder_id = decoder_lib.find_decoder(wl_addr_size, num_wls, + true, false, false, readback_port != ModulePortId::INVALID()); + if (DecoderId::INVALID() == wl_decoder_id) { + wl_decoder_id = decoder_lib.add_decoder(wl_addr_size, num_wls, true, false, false, readback_port != ModulePortId::INVALID()); + } + VTR_ASSERT(DecoderId::INVALID() != wl_decoder_id); + + /* Create a module if not existed yet */ + std::string wl_decoder_module_name = generate_memory_decoder_subckt_name(wl_addr_size, num_wls); + ModuleId wl_decoder_module = module_manager.find_module(wl_decoder_module_name); + if (ModuleId::INVALID() == wl_decoder_module) { + /* BL decoder has the same ports as the frame-based decoders + * We reuse it here + */ + wl_decoder_module = build_wl_memory_decoder_module(module_manager, + decoder_lib, + wl_decoder_id); + } + VTR_ASSERT(ModuleId::INVALID() != wl_decoder_module); + size_t curr_wl_decoder_instance_id = module_manager.num_instance(top_module, wl_decoder_module); + module_manager.add_child_module(top_module, wl_decoder_module); + + /************************************************************** + * Add module nets from the top module to WL decoder's inputs + */ + ModulePortId wl_decoder_en_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_ENABLE_PORT_NAME)); + BasicPort wl_decoder_en_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_en_port); + + ModulePortId wl_decoder_addr_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_ADDRESS_PORT_NAME)); + BasicPort wl_decoder_addr_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_addr_port); + + ModulePortId wl_decoder_readback_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_READBACK_PORT_NAME)); + BasicPort wl_decoder_readback_port_info; + if (wl_decoder_readback_port) { + wl_decoder_readback_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_readback_port); + } + + /* Top module Enable port -> WL Decoder Enable port */ + add_module_bus_nets(module_manager, + top_module, + top_module, 0, en_port, + wl_decoder_module, curr_wl_decoder_instance_id, wl_decoder_en_port); + + /* Top module Address port -> WL Decoder Address port */ + add_module_bus_nets(module_manager, + top_module, + top_module, 0, wl_addr_port, + wl_decoder_module, curr_wl_decoder_instance_id, wl_decoder_addr_port); + + /* Top module readback port -> WL Decoder readback port */ + if (wl_decoder_readback_port) { + add_module_bus_nets(module_manager, + top_module, + top_module, 0, readback_port, + wl_decoder_module, curr_wl_decoder_instance_id, wl_decoder_readback_port); + } + + /************************************************************** + * Precompute the BLs and WLs distribution across the FPGA fabric + * The distribution is a matrix which contains the starting index of BL/WL for each column or row + */ + std::pair 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 nets from WL data out to each configurable child */ ModulePortId wl_decoder_dout_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_DATA_OUT_PORT_NAME)); BasicPort wl_decoder_dout_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_dout_port); - for (size_t child_id = 0; child_id < module_manager.region_configurable_children(top_module, config_region).size(); ++child_id) { + /* Note we skip the last child which is the bl decoder added */ + for (size_t child_id = 0; child_id < module_manager.region_configurable_children(top_module, config_region).size() - 1; ++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]; @@ -458,13 +507,6 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma * Add the BL and WL decoders to the end of configurable children list * Note: this MUST be done after adding all the module nets to other regular configurable children */ - module_manager.add_configurable_child(top_module, bl_decoder_module, curr_bl_decoder_instance_id); - module_manager.add_configurable_child_to_region(top_module, - config_region, - bl_decoder_module, - curr_bl_decoder_instance_id, - module_manager.configurable_children(top_module).size() - 1); - module_manager.add_configurable_child(top_module, wl_decoder_module, curr_wl_decoder_instance_id); module_manager.add_configurable_child_to_region(top_module, config_region, @@ -474,6 +516,68 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma } } +/********************************************************************* + * Top-level function to add nets for quicklogic memory banks + * - Each configuration region has independent memory bank circuitry + * - BL and WL may have different circuitry and wire connection, e.g., decoder, flatten or shift-registers + * - BL control circuitry + * - Decoder: Add a BL decoder; Connect enable, address and data-in (din) between top-level and decoders; Connect data ports between between the decoder and configurable child modules + * - Flatten: Connect BLs between the top-level port and configurable child modules + * - TODO: Shift registers: add blocks of shift register chain (could be multi-head); Connect shift register outputs to configurable child modules + * + * - WL control circuitry + * - Decoder: Add a WL decoder; Connect address ports between top-level and decoders; Connect data ports between the decoder and configurable child modules + * - Flatten: Connect BLs between the top-level port and configurable child modules + * - TODO: Shift registers: add blocks of shift register chain (could be multi-head); Connect shift register outputs to configurable child modules + ********************************************************************/ +void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_manager, + DecoderLibrary& decoder_lib, + const ModuleId& top_module, + const CircuitLibrary& circuit_lib, + const ConfigProtocol& config_protocol, + const TopModuleNumConfigBits& num_config_bits) { + VTR_ASSERT_SAFE(CONFIG_MEM_QL_MEMORY_BANK == config_protocol.type()); + CircuitModelId sram_model = config_protocol.memory_model(); + + switch (config_protocol.bl_protocol_type()) { + case BLWL_PROTOCOL_DECODER: { + add_top_module_nets_cmos_ql_memory_bank_bl_decoder_config_bus(module_manager, decoder_lib, top_module, circuit_lib, sram_model, num_config_bits); + break; + } + case BLWL_PROTOCOL_FLATTEN: { + //add_top_module_nets_cmos_ql_memory_bank_bl_flatten_config_bus(module_manager, decoder_lib, top_module, circuit_lib, num_config_bits); + break; + } + case BLWL_PROTOCOL_SHIFT_REGISTER: { + /* TODO */ + break; + } + default: { + VTR_LOG_ERROR("Invalid BL protocol"); + exit(1); + } + } + + switch (config_protocol.wl_protocol_type()) { + case BLWL_PROTOCOL_DECODER: { + add_top_module_nets_cmos_ql_memory_bank_wl_decoder_config_bus(module_manager, decoder_lib, top_module, circuit_lib, sram_model, num_config_bits); + break; + } + case BLWL_PROTOCOL_FLATTEN: { + //add_top_module_nets_cmos_ql_memory_bank_wl_flatten_config_bus(module_manager, decoder_lib, top_module, circuit_lib, num_config_bits); + break; + } + case BLWL_PROTOCOL_SHIFT_REGISTER: { + /* TODO */ + break; + } + default: { + VTR_LOG_ERROR("Invalid WL protocol"); + exit(1); + } + } +} + /******************************************************************** * Add a list of ports that are used for SRAM configuration to the FPGA * top-level module diff --git a/openfpga/src/fabric/build_top_module_memory_bank.h b/openfpga/src/fabric/build_top_module_memory_bank.h index 50e9567c9..3d6acc255 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.h +++ b/openfpga/src/fabric/build_top_module_memory_bank.h @@ -26,7 +26,7 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma DecoderLibrary& decoder_lib, const ModuleId& top_module, const CircuitLibrary& circuit_lib, - const CircuitModelId& sram_model, + const ConfigProtocol& config_protocol, const TopModuleNumConfigBits& num_config_bits); void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager, From 74ffc8578f7f7a43cb495bdc72504f8e3f992a37 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 24 Sep 2021 15:05:25 -0700 Subject: [PATCH 13/28] [Engine] Upgraded fabric generator to support flatten BL/WL bus for memory banks --- .../fabric/build_top_module_memory_bank.cpp | 247 +++++++++++++++++- 1 file changed, 241 insertions(+), 6 deletions(-) diff --git a/openfpga/src/fabric/build_top_module_memory_bank.cpp b/openfpga/src/fabric/build_top_module_memory_bank.cpp index a974fc736..55203d993 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.cpp +++ b/openfpga/src/fabric/build_top_module_memory_bank.cpp @@ -315,7 +315,7 @@ void add_top_module_nets_cmos_ql_memory_bank_bl_decoder_config_bus(ModuleManager * * @note this function only adds the WL configuration bus for decoders * - * @note see detailed explanation on the bus connection in function add_top_module_nets_cmos_ql_memory_bank_config_bus() + * @note see detailed explanation on the bus connection in function add_top_module_nets_cmos_ql_memory_bank_bl_decoder_config_bus() **********************************************************************/ static void add_top_module_nets_cmos_ql_memory_bank_wl_decoder_config_bus(ModuleManager& module_manager, @@ -433,14 +433,17 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_decoder_config_bus(ModuleManager BasicPort wl_decoder_dout_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_dout_port); /* Note we skip the last child which is the bl decoder added */ - for (size_t child_id = 0; child_id < module_manager.region_configurable_children(top_module, config_region).size() - 1; ++child_id) { + for (size_t child_id = 0; child_id < module_manager.region_configurable_children(top_module, config_region).size(); ++child_id) { ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id]; 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 WL port. If the child does not have WL port, bypass it. It is usually a decoder module */ ModulePortId child_wl_port = module_manager.find_module_port(child_module, std::string(MEMORY_WL_PORT_NAME)); + if (!child_wl_port) { + continue; + } BasicPort child_wl_port_info = module_manager.module_port(child_module, child_wl_port); size_t cur_wl_index = 0; @@ -477,8 +480,11 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_decoder_config_bus(ModuleManager size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[child_id]; - /* Find the WL port */ + /* Find the WLR port. If the child does not have WLR port, bypass it. It is usually a decoder module */ ModulePortId child_wlr_port = module_manager.find_module_port(child_module, std::string(MEMORY_WLR_PORT_NAME)); + if (!child_wlr_port) { + continue; + } BasicPort child_wlr_port_info = module_manager.module_port(child_module, child_wlr_port); size_t cur_wlr_index = 0; @@ -516,6 +522,229 @@ void add_top_module_nets_cmos_ql_memory_bank_wl_decoder_config_bus(ModuleManager } } +/********************************************************************* + * This function to add nets for quicklogic memory banks using flatten BLs and WLs + * Each configuration region has independent BL/WLs + * - Find the number of BLs and WLs required for each region + * - Create nets to connect from top-level module inputs to BL/WL of configurable children + * + * @note this function only adds the BL configuration bus + * + * Detailed schematic of each memory bank: + * @note The numbers are just made to show a simplified example, practical cases are more complicated! + * + * BL[0:9] BL[10:17] BL[18:22] + * | | | + * | | | + * WL[0:3]-->-----------+---------------+---- ... |------+--> + * | | | | | | + * | v | v | v + * | +-------+ | +-------+ | +------+ + * +-->| SRAM | +-->| SRAM | +->| SRAM | + * | | [0:8] | | | [0:5] | ... | | [0:7]| + * | +-------+ | +-------+ | +------+ + * | | | + * WL[4:14] -----------+--------------+--------- | -----+--> + * | | | | | | + * | v | v | v + * | +-------+ | +-------+ | +-------+ + * +-->| SRAM | | | SRAM | +->| SRAM | + * | | [0:80]| | | [0:63]| ... | | [0:31]| + * | +-------+ | +-------+ | +-------+ + * | | + * | ... ... ... | ... + * | | | + * WL[15:18] -----------+---------------+---- --- | -----+--> + * | | | | | | + * | v | v | v + * | +-------+ | +-------+ | +-------+ + * +-->| SRAM | +-->| SRAM | +->| SRAM | + * | |[0:5] | | | [0:8] | ... | | [0:2] | + * | +-------+ | +-------+ | +-------+ + * v v v + * WL[0:9] WL[0:7] WL[0:4] + * + **********************************************************************/ +static +void add_top_module_nets_cmos_ql_memory_bank_bl_flatten_config_bus(ModuleManager& module_manager, + const ModuleId& top_module, + const CircuitLibrary& circuit_lib, + const CircuitModelId& sram_model) { + /* Create connections between BLs of top-level module and BLs of child modules for each region */ + for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { + /************************************************************** + * Precompute the BLs and WLs distribution across the FPGA fabric + * The distribution is a matrix which contains the starting index of BL/WL for each column or row + */ + std::pair 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 + * - Find the number of BLs and WLs required for each region + * - Create nets to connect from top-level module inputs to BL/WL of configurable children + * + * @note this function only adds the WL configuration bus + * + * @note see detailed explanation on the bus connection in function add_top_module_nets_cmos_ql_memory_bank_bl_flatten_config_bus() + **********************************************************************/ +static +void add_top_module_nets_cmos_ql_memory_bank_wl_flatten_config_bus(ModuleManager& module_manager, + const ModuleId& top_module, + const CircuitLibrary& circuit_lib, + const CircuitModelId& sram_model) { + /* Create connections between WLs of top-level module and WLs of child modules for each region */ + for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { + /************************************************************** + * Precompute the BLs and WLs distribution across the FPGA fabric + * The distribution is a matrix which contains the starting index of BL/WL for each column or row + */ + std::pair 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 @@ -545,7 +774,7 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma break; } case BLWL_PROTOCOL_FLATTEN: { - //add_top_module_nets_cmos_ql_memory_bank_bl_flatten_config_bus(module_manager, decoder_lib, top_module, circuit_lib, num_config_bits); + add_top_module_nets_cmos_ql_memory_bank_bl_flatten_config_bus(module_manager, top_module, circuit_lib, sram_model); break; } case BLWL_PROTOCOL_SHIFT_REGISTER: { @@ -564,7 +793,7 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma break; } case BLWL_PROTOCOL_FLATTEN: { - //add_top_module_nets_cmos_ql_memory_bank_wl_flatten_config_bus(module_manager, decoder_lib, top_module, circuit_lib, num_config_bits); + add_top_module_nets_cmos_ql_memory_bank_wl_flatten_config_bus(module_manager, top_module, circuit_lib, sram_model); break; } case BLWL_PROTOCOL_SHIFT_REGISTER: { @@ -675,6 +904,12 @@ void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager, size_t wl_size = num_config_bits[config_region].first; BasicPort wl_port(generate_regional_blwl_port_name(std::string(MEMORY_WL_PORT_NAME), config_region), wl_size); module_manager.add_port(module_id, wl_port, ModuleManager::MODULE_INPUT_PORT); + + /* Optional: If we have WLR port, we should add a read-back port */ + if (!circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_WLR).empty()) { + BasicPort readback_port(std::string(MEMORY_WLR_PORT_NAME), config_protocol.num_regions()); + module_manager.add_port(module_id, readback_port, ModuleManager::MODULE_INPUT_PORT); + } } break; } From 2de4a460a813987cdd60d68f1cc7def98a96767d Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 24 Sep 2021 15:15:32 -0700 Subject: [PATCH 14/28] [Engine] Rework the function that counts the number of configurable children for fabric key writer and bitstream generator --- openfpga/src/base/openfpga_build_fabric.cpp | 2 +- openfpga/src/fabric/fabric_key_writer.cpp | 4 ++-- openfpga/src/fabric/fabric_key_writer.h | 7 ++++--- .../src/fpga_bitstream/build_device_bitstream.cpp | 12 ++++++------ openfpga/src/utils/memory_utils.cpp | 15 +++++++++++---- openfpga/src/utils/memory_utils.h | 3 ++- 6 files changed, 26 insertions(+), 17 deletions(-) diff --git a/openfpga/src/base/openfpga_build_fabric.cpp b/openfpga/src/base/openfpga_build_fabric.cpp index 2c3f491f9..146520624 100644 --- a/openfpga/src/base/openfpga_build_fabric.cpp +++ b/openfpga/src/base/openfpga_build_fabric.cpp @@ -132,7 +132,7 @@ int build_fabric(OpenfpgaContext& openfpga_ctx, VTR_ASSERT(false == fkey_fname.empty()); curr_status = write_fabric_key_to_xml_file(openfpga_ctx.module_graph(), fkey_fname, - openfpga_ctx.arch().config_protocol.type(), + openfpga_ctx.arch().config_protocol, cmd_context.option_enable(cmd, opt_verbose)); /* If there is any error, final status cannot be overwritten by a success flag */ if (CMD_EXEC_SUCCESS != curr_status) { diff --git a/openfpga/src/fabric/fabric_key_writer.cpp b/openfpga/src/fabric/fabric_key_writer.cpp index d6bea0527..38cb599db 100644 --- a/openfpga/src/fabric/fabric_key_writer.cpp +++ b/openfpga/src/fabric/fabric_key_writer.cpp @@ -31,7 +31,7 @@ namespace openfpga { ***************************************************************************************/ int write_fabric_key_to_xml_file(const ModuleManager& module_manager, const std::string& fname, - const e_config_protocol_type& config_protocol_type, + const ConfigProtocol& config_protocol, const bool& verbose) { std::string timer_message = std::string("Write fabric key to XML file '") + fname + std::string("'"); @@ -71,7 +71,7 @@ int write_fabric_key_to_xml_file(const ModuleManager& module_manager, /* Each configuration protocol has some child which should not be in the list. They are typically decoders */ size_t curr_region_num_config_child = module_manager.region_configurable_children(top_module, config_region).size(); - size_t num_child_to_skip = estimate_num_configurable_children_to_skip_by_config_protocol(config_protocol_type, curr_region_num_config_child); + size_t num_child_to_skip = estimate_num_configurable_children_to_skip_by_config_protocol(config_protocol, curr_region_num_config_child); curr_region_num_config_child -= num_child_to_skip; fabric_key.reserve_region_keys(fabric_region, curr_region_num_config_child); diff --git a/openfpga/src/fabric/fabric_key_writer.h b/openfpga/src/fabric/fabric_key_writer.h index 3062db15a..bdb860354 100644 --- a/openfpga/src/fabric/fabric_key_writer.h +++ b/openfpga/src/fabric/fabric_key_writer.h @@ -4,8 +4,9 @@ /******************************************************************** * Include header files that are required by function declaration *******************************************************************/ -#include "vpr_context.h" -#include "openfpga_context.h" +#include +#include "module_manager.h" +#include "config_protocol.h" /******************************************************************** * Function declaration @@ -16,7 +17,7 @@ namespace openfpga { int write_fabric_key_to_xml_file(const ModuleManager& module_manager, const std::string& fname, - const e_config_protocol_type& config_protocol_type, + const ConfigProtocol& config_protocol, const bool& verbose); } /* end namespace openfpga */ diff --git a/openfpga/src/fpga_bitstream/build_device_bitstream.cpp b/openfpga/src/fpga_bitstream/build_device_bitstream.cpp index 1c81e2cb3..8c89c3aaf 100644 --- a/openfpga/src/fpga_bitstream/build_device_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/build_device_bitstream.cpp @@ -64,7 +64,7 @@ static size_t rec_estimate_device_bitstream_num_bits(const ModuleManager& module_manager, const ModuleId& top_module, const ModuleId& parent_module, - const e_config_protocol_type& config_protocol_type) { + const ConfigProtocol& config_protocol) { size_t num_bits = 0; /* If a child module has no configurable children, this is a leaf node @@ -85,13 +85,13 @@ size_t rec_estimate_device_bitstream_num_bits(const ModuleManager& module_manage if (parent_module == top_module) { for (const ConfigRegionId& config_region : module_manager.regions(parent_module)) { size_t curr_region_num_config_child = module_manager.region_configurable_children(parent_module, config_region).size(); - size_t num_child_to_skip = estimate_num_configurable_children_to_skip_by_config_protocol(config_protocol_type, curr_region_num_config_child); + size_t num_child_to_skip = estimate_num_configurable_children_to_skip_by_config_protocol(config_protocol, curr_region_num_config_child); curr_region_num_config_child -= num_child_to_skip; /* Visit all the children in a recursively way */ for (size_t ichild = 0; ichild < curr_region_num_config_child; ++ichild) { ModuleId child_module = module_manager.region_configurable_children(parent_module, config_region)[ichild]; - num_bits += rec_estimate_device_bitstream_num_bits(module_manager, top_module, child_module, config_protocol_type); + num_bits += rec_estimate_device_bitstream_num_bits(module_manager, top_module, child_module, config_protocol); } } } else { @@ -102,14 +102,14 @@ size_t rec_estimate_device_bitstream_num_bits(const ModuleManager& module_manage /* Frame-based configuration protocol will have 1 decoder * if there are more than 1 configurable children */ - if ( (CONFIG_MEM_FRAME_BASED == config_protocol_type) + if ( (CONFIG_MEM_FRAME_BASED == config_protocol.type()) && (2 <= num_configurable_children)) { num_configurable_children--; } for (size_t ichild = 0; ichild < num_configurable_children; ++ichild) { ModuleId child_module = module_manager.configurable_children(parent_module)[ichild]; - num_bits += rec_estimate_device_bitstream_num_bits(module_manager, top_module, child_module, config_protocol_type); + num_bits += rec_estimate_device_bitstream_num_bits(module_manager, top_module, child_module, config_protocol); } } @@ -157,7 +157,7 @@ BitstreamManager build_device_bitstream(const VprContext& vpr_ctx, size_t num_bits_to_reserve = rec_estimate_device_bitstream_num_bits(openfpga_ctx.module_graph(), top_module, top_module, - openfpga_ctx.arch().config_protocol.type()); + openfpga_ctx.arch().config_protocol); bitstream_manager.reserve_bits(num_bits_to_reserve); VTR_LOGV(verbose, "Reserved %lu configuration bits\n", num_bits_to_reserve); diff --git a/openfpga/src/utils/memory_utils.cpp b/openfpga/src/utils/memory_utils.cpp index e5e44b99c..71c2c60ef 100644 --- a/openfpga/src/utils/memory_utils.cpp +++ b/openfpga/src/utils/memory_utils.cpp @@ -429,13 +429,13 @@ size_t generate_pb_sram_port_size(const e_config_protocol_type sram_orgz_type, return sram_port_size; } -size_t estimate_num_configurable_children_to_skip_by_config_protocol(e_config_protocol_type config_protocol_type, +size_t estimate_num_configurable_children_to_skip_by_config_protocol(const ConfigProtocol& config_protocol, size_t curr_region_num_config_child) { size_t num_child_to_skip = 0; /* Frame-based configuration protocol will have 1 decoder * if there are more than 1 configurable children */ - if ( (CONFIG_MEM_FRAME_BASED == config_protocol_type) + if ( (CONFIG_MEM_FRAME_BASED == config_protocol.type()) && (2 <= curr_region_num_config_child)) { num_child_to_skip = 1; } @@ -443,10 +443,17 @@ size_t estimate_num_configurable_children_to_skip_by_config_protocol(e_config_pr /* Memory configuration protocol will have 2 decoders * at the top-level */ - if (CONFIG_MEM_MEMORY_BANK == config_protocol_type - || CONFIG_MEM_QL_MEMORY_BANK == config_protocol_type) { + if (CONFIG_MEM_MEMORY_BANK == config_protocol.type() + || CONFIG_MEM_QL_MEMORY_BANK == config_protocol.type()) { VTR_ASSERT(2 <= curr_region_num_config_child); num_child_to_skip = 2; + /* If flatten bus is used, BL/WL may not need decoders */ + if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) { + num_child_to_skip--; + } + if (BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()) { + num_child_to_skip--; + } } return num_child_to_skip; diff --git a/openfpga/src/utils/memory_utils.h b/openfpga/src/utils/memory_utils.h index d34e5f0ce..bf092b81a 100644 --- a/openfpga/src/utils/memory_utils.h +++ b/openfpga/src/utils/memory_utils.h @@ -7,6 +7,7 @@ #include #include "openfpga_port.h" #include "circuit_types.h" +#include "config_protocol.h" #include "module_manager.h" /******************************************************************** @@ -46,7 +47,7 @@ size_t generate_pb_sram_port_size(const e_config_protocol_type sram_orgz_type, * (they are included in the list for bitstream generator usage) * The number of decoders depends on the type of configuration protocol. */ -size_t estimate_num_configurable_children_to_skip_by_config_protocol(e_config_protocol_type config_protocol_type, +size_t estimate_num_configurable_children_to_skip_by_config_protocol(const ConfigProtocol& config_protocol, size_t curr_region_num_config_child); } /* end namespace openfpga */ From f735c10b84cb6dfa21d41b084ec77cad30b50492 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 24 Sep 2021 15:18:31 -0700 Subject: [PATCH 15/28] [Engine] Clear up compiler warnings --- libopenfpga/libopenfpgautil/src/openfpga_port.cpp | 5 ----- libopenfpga/libopenfpgautil/src/openfpga_port.h | 1 - 2 files changed, 6 deletions(-) diff --git a/libopenfpga/libopenfpgautil/src/openfpga_port.cpp b/libopenfpga/libopenfpgautil/src/openfpga_port.cpp index a68431739..570fdf603 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_port.cpp +++ b/libopenfpga/libopenfpgautil/src/openfpga_port.cpp @@ -51,11 +51,6 @@ BasicPort::BasicPort(const std::string& name, const size_t& width) { set_origin_port_width(-1); } -/* Copy constructor */ -BasicPort::BasicPort(const BasicPort& basic_port) { - set(basic_port); -} - /************************************************************************ * Accessors ***********************************************************************/ diff --git a/libopenfpga/libopenfpgautil/src/openfpga_port.h b/libopenfpga/libopenfpgautil/src/openfpga_port.h index 4779e2332..3df6d0efa 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_port.h +++ b/libopenfpga/libopenfpgautil/src/openfpga_port.h @@ -18,7 +18,6 @@ class BasicPort { BasicPort(const char* name, const size_t& width); BasicPort(const std::string& name, const size_t& lsb, const size_t& msb); BasicPort(const std::string& name, const size_t& width); - BasicPort(const BasicPort& basic_port); /* Copy constructor */ public: /* Overloaded operators */ bool operator== (const BasicPort& portA) const; bool operator< (const BasicPort& portA) const; From 5f7617b682cfefb7aa2f2ff08b74b12b3eb5035b Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 24 Sep 2021 15:18:50 -0700 Subject: [PATCH 16/28] [Engine] Clear up compiler warnings in circuit library --- libopenfpga/libarchopenfpga/src/circuit_library.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libopenfpga/libarchopenfpga/src/circuit_library.cpp b/libopenfpga/libarchopenfpga/src/circuit_library.cpp index 537a436bc..4195158d4 100644 --- a/libopenfpga/libarchopenfpga/src/circuit_library.cpp +++ b/libopenfpga/libarchopenfpga/src/circuit_library.cpp @@ -1170,7 +1170,7 @@ CircuitModelId CircuitLibrary::add_model(const enum e_circuit_model_type& type) /* Pass-gate-related parameters */ pass_gate_logic_model_names_.emplace_back(); - pass_gate_logic_model_ids_.emplace_back(); + pass_gate_logic_model_ids_.emplace_back(CircuitModelId::INVALID()); /* Delay information */ delay_types_.emplace_back(); From 025ee67bc7ddfe24b57cc61ca34ab381da28a1ea Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 24 Sep 2021 15:20:43 -0700 Subject: [PATCH 17/28] [Engine] Clear up compiler warning in tileable rr_graph builder --- vpr/src/tileable_rr_graph/rr_chan.cpp | 6 ------ vpr/src/tileable_rr_graph/rr_chan.h | 1 - vpr/src/tileable_rr_graph/rr_gsb.cpp | 7 ------- vpr/src/tileable_rr_graph/rr_gsb.h | 1 - 4 files changed, 15 deletions(-) diff --git a/vpr/src/tileable_rr_graph/rr_chan.cpp b/vpr/src/tileable_rr_graph/rr_chan.cpp index fc387a988..0aea3cee4 100644 --- a/vpr/src/tileable_rr_graph/rr_chan.cpp +++ b/vpr/src/tileable_rr_graph/rr_chan.cpp @@ -11,12 +11,6 @@ namespace openfpga { /************************************************************************ * Constructors ***********************************************************************/ -/* Copy Constructor */ -RRChan::RRChan(const RRChan& rr_chan) { - this->set(rr_chan); - return; -} - /* default constructor */ RRChan::RRChan() { type_ = NUM_RR_TYPES; diff --git a/vpr/src/tileable_rr_graph/rr_chan.h b/vpr/src/tileable_rr_graph/rr_chan.h index 3277bb173..d06d894ca 100644 --- a/vpr/src/tileable_rr_graph/rr_chan.h +++ b/vpr/src/tileable_rr_graph/rr_chan.h @@ -43,7 +43,6 @@ namespace openfpga { *******************************************************************/ class RRChan { public: /* Constructors */ - RRChan(const RRChan&); /* Copy Constructor */ RRChan(); public: /* Accessors */ t_rr_type get_type() const; diff --git a/vpr/src/tileable_rr_graph/rr_gsb.cpp b/vpr/src/tileable_rr_graph/rr_gsb.cpp index c0d8d4143..eff2ebf00 100644 --- a/vpr/src/tileable_rr_graph/rr_gsb.cpp +++ b/vpr/src/tileable_rr_graph/rr_gsb.cpp @@ -32,13 +32,6 @@ RRGSB::RRGSB() { opin_node_.clear(); } -/* Copy constructor */ -RRGSB::RRGSB(const RRGSB& src) { - /* Copy coordinate */ - this->set(src); - return; -} - /************************************************************************ * Accessors ***********************************************************************/ diff --git a/vpr/src/tileable_rr_graph/rr_gsb.h b/vpr/src/tileable_rr_graph/rr_gsb.h index a0d13ad4a..38465369d 100644 --- a/vpr/src/tileable_rr_graph/rr_gsb.h +++ b/vpr/src/tileable_rr_graph/rr_gsb.h @@ -52,7 +52,6 @@ namespace openfpga { *******************************************************************/ class RRGSB { public: /* Contructors */ - RRGSB(const RRGSB&);/* Copy constructor */ RRGSB();/* Default constructor */ public: /* Accessors */ /* Get the number of sides of this SB */ From a49e3fe57a1895254a1d55306694ec0383568e0e Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 24 Sep 2021 16:30:18 -0700 Subject: [PATCH 18/28] [FPGA-bitstream] Upgraded bitstream generator to support flatten BL/WLs for QL memory bank --- .../libopenfpgautil/src/openfpga_decode.cpp | 34 +++++++ .../libopenfpgautil/src/openfpga_decode.h | 3 + .../build_fabric_bitstream_memory_bank.cpp | 92 +++++++++++++++---- 3 files changed, 111 insertions(+), 18 deletions(-) diff --git a/libopenfpga/libopenfpgautil/src/openfpga_decode.cpp b/libopenfpga/libopenfpgautil/src/openfpga_decode.cpp index b4dae065f..d6a6d0463 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_decode.cpp +++ b/libopenfpga/libopenfpgautil/src/openfpga_decode.cpp @@ -46,6 +46,40 @@ std::vector ito1hot_vec(const size_t& in_int, return ret; } +/******************************************************************** + * Convert an integer to an one-hot encoding character array + * For example: + * Input integer: 3 + * Binary length : 4 + * Output: + * index | 0 | 1 | 2 | 3 + * ret | 0 | 0 | 0 | 1 + * + * If you need all zero code, set the input integer same as the binary length + * For example: + * Input integer: 4 + * Binary length : 4 + * Output: + * index | 0 | 1 | 2 | 3 + * ret | 0 | 0 | 0 | 0 + * + ********************************************************************/ +std::vector ito1hot_charvec(const size_t& in_int, + const size_t& bin_len) { + /* Make sure we do not have any overflow! */ + VTR_ASSERT ( (in_int <= bin_len) ); + + /* Initialize */ + std::vector ret(bin_len, '0'); + + if (bin_len == in_int) { + return ret; /* all zero case */ + } + ret[in_int] = '1'; /* Keep a good sequence of bits */ + + return ret; +} + /******************************************************************** * Converter an integer to a binary vector * For example: diff --git a/libopenfpga/libopenfpgautil/src/openfpga_decode.h b/libopenfpga/libopenfpgautil/src/openfpga_decode.h index 2e92bb9f4..21568b0dc 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_decode.h +++ b/libopenfpga/libopenfpgautil/src/openfpga_decode.h @@ -22,6 +22,9 @@ constexpr char DONT_CARE_CHAR = 'x'; std::vector ito1hot_vec(const size_t& in_int, const size_t& bin_len); +std::vector ito1hot_charvec(const size_t& in_int, + const size_t& bin_len); + std::vector itobin_vec(const size_t& in_int, const size_t& bin_len); 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 3e7f2e9cc..1a5479842 100644 --- a/openfpga/src/fpga_bitstream/build_fabric_bitstream_memory_bank.cpp +++ b/openfpga/src/fpga_bitstream/build_fabric_bitstream_memory_bank.cpp @@ -47,6 +47,7 @@ void rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(const B const ModuleId& top_module, const ModuleId& parent_module, const ConfigRegionId& config_region, + const ConfigProtocol& config_protocol, const CircuitLibrary& circuit_lib, const CircuitModelId& sram_model, const size_t& bl_addr_size, @@ -101,6 +102,7 @@ void rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(const B rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(bitstream_manager, child_block, module_manager, top_module, child_module, config_region, + config_protocol, circuit_lib, sram_model, bl_addr_size, wl_addr_size, num_bls_cur_tile, bl_start_index_per_tile, @@ -143,6 +145,7 @@ void rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(const B rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(bitstream_manager, child_block, module_manager, top_module, child_module, config_region, + config_protocol, circuit_lib, sram_model, bl_addr_size, wl_addr_size, num_bls_cur_tile, bl_start_index_per_tile, @@ -166,13 +169,29 @@ void rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(const B for (const ConfigBitId& config_bit : bitstream_manager.block_bits(parent_block)) { FabricBitId fabric_bit = fabric_bitstream.add_bit(config_bit); - /* Find BL address */ + /* The BL address to be decoded depends on the protocol + * - flatten BLs: use 1-hot decoding + * - BL decoders: fully encoded + * - Shift register: use 1-hot decoding + */ size_t cur_bl_index = bl_start_index_per_tile.at(tile_coord.x()) + cur_mem_index[tile_coord] % num_bls_cur_tile; - std::vector bl_addr_bits_vec = itobin_charvec(cur_bl_index, bl_addr_size); + std::vector bl_addr_bits_vec; + if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) { + bl_addr_bits_vec = itobin_charvec(cur_bl_index, bl_addr_size); + } else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type() + || BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) { + bl_addr_bits_vec = ito1hot_charvec(cur_bl_index, bl_addr_size); + } /* Find WL address */ size_t cur_wl_index = wl_start_index_per_tile.at(tile_coord.y()) + std::floor(cur_mem_index[tile_coord] / num_bls_cur_tile); - std::vector wl_addr_bits_vec = itobin_charvec(cur_wl_index, wl_addr_size); + std::vector wl_addr_bits_vec; + if (BLWL_PROTOCOL_DECODER == config_protocol.wl_protocol_type()) { + wl_addr_bits_vec = itobin_charvec(cur_wl_index, wl_addr_size); + } else if (BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type() + || BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()) { + wl_addr_bits_vec = ito1hot_charvec(cur_wl_index, wl_addr_size); + } /* Set BL address */ fabric_bitstream.set_bit_bl_address(fabric_bit, bl_addr_bits_vec); @@ -193,7 +212,7 @@ void rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(const B /******************************************************************** * Main function to build a fabric-dependent bitstream - * by considering the configuration protocol types + * by considering the QuickLogic memory banks *******************************************************************/ void build_module_fabric_dependent_bitstream_ql_memory_bank(const ConfigProtocol& config_protocol, const CircuitLibrary& circuit_lib, @@ -205,13 +224,57 @@ void build_module_fabric_dependent_bitstream_ql_memory_bank(const ConfigProtocol /* Ensure we are in the correct type of configuration protocol*/ VTR_ASSERT(config_protocol.type() == CONFIG_MEM_QL_MEMORY_BANK); - /* Find global BL address port size */ - ModulePortId bl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_BL_ADDRESS_PORT_NAME)); - BasicPort bl_addr_port_info = module_manager.module_port(top_module, bl_addr_port); + /* For different BL control protocol, the address ports are different + * - flatten BLs: the address port should be raw BL ports at top-level module. + * Due to each configuration region has separated BLs, the address port should be the one with largest size + * - BL decoders: the address port should be the BL address port at top-level module + * - Shift register: the address port size will be calculated by the total number of unique BLs per child module in each configuration region + * Due to each configuration region has separated BLs, the address port should be the one with largest size + */ + ModulePortId bl_addr_port; + BasicPort bl_addr_port_info; + if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) { + bl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_BL_ADDRESS_PORT_NAME)); + bl_addr_port_info = module_manager.module_port(top_module, bl_addr_port); + } else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) { + for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { + ModulePortId temp_bl_addr_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_BL_PORT_NAME), config_region)); + BasicPort temp_bl_addr_port_info = module_manager.module_port(top_module, temp_bl_addr_port); + if (!bl_addr_port || (temp_bl_addr_port_info.get_width() > bl_addr_port_info.get_width())) { + bl_addr_port = temp_bl_addr_port; + bl_addr_port_info = temp_bl_addr_port_info; + } + } + } else { + /* TODO */ + VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()); + } - /* Find global WL address port size */ - ModulePortId wl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_WL_ADDRESS_PORT_NAME)); - BasicPort wl_addr_port_info = module_manager.module_port(top_module, wl_addr_port); + /* For different WL control protocol, the address ports are different + * - flatten WLs: the address port should be raw WL ports at top-level module. + * Due to each configuration region has separated WLs, the address port should be the one with largest size + * - WL decoders: the address port should be the WL address port at top-level module + * - Shift register: the address port size will be calculated by the total number of unique WLs per child module in each configuration region + * Due to each configuration region has separated WLs, the address port should be the one with largest size + */ + ModulePortId wl_addr_port; + BasicPort wl_addr_port_info; + if (BLWL_PROTOCOL_DECODER == config_protocol.wl_protocol_type()) { + wl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_WL_ADDRESS_PORT_NAME)); + wl_addr_port_info = module_manager.module_port(top_module, wl_addr_port); + } else if (BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()) { + for (const ConfigRegionId& config_region : module_manager.regions(top_module)) { + ModulePortId temp_wl_addr_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_WL_PORT_NAME), config_region)); + BasicPort temp_wl_addr_port_info = module_manager.module_port(top_module, temp_wl_addr_port); + if (!wl_addr_port || (temp_wl_addr_port_info.get_width() > wl_addr_port_info.get_width())) { + wl_addr_port = temp_wl_addr_port; + wl_addr_port_info = temp_wl_addr_port_info; + } + } + } else { + /* TODO */ + VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type()); + } /* Reserve bits before build-up */ fabric_bitstream.set_use_address(true); @@ -225,14 +288,6 @@ void build_module_fabric_dependent_bitstream_ql_memory_bank(const ConfigProtocol /* Find port information for local BL and WL decoder in this region */ std::vector configurable_children = module_manager.region_configurable_children(top_module, config_region); VTR_ASSERT(2 <= configurable_children.size()); - ModuleId bl_decoder_module = configurable_children[configurable_children.size() - 2]; - ModuleId wl_decoder_module = configurable_children[configurable_children.size() - 1]; - - ModulePortId bl_port = module_manager.find_module_port(bl_decoder_module, std::string(DECODER_DATA_OUT_PORT_NAME)); - BasicPort bl_port_info = module_manager.module_port(bl_decoder_module, bl_port); - - ModulePortId wl_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_DATA_OUT_PORT_NAME)); - BasicPort wl_port_info = module_manager.module_port(wl_decoder_module, wl_port); /* Build the bitstream for all the blocks in this region */ FabricBitRegionId fabric_bitstream_region = fabric_bitstream.add_region(); @@ -262,6 +317,7 @@ void build_module_fabric_dependent_bitstream_ql_memory_bank(const ConfigProtocol rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(bitstream_manager, top_block, module_manager, top_module, top_module, config_region, + config_protocol, circuit_lib, config_protocol.memory_model(), bl_addr_port_info.get_width(), wl_addr_port_info.get_width(), From 8b72447dad067aba430c68b1a4ae19c993abfd55 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Fri, 24 Sep 2021 18:07:07 -0700 Subject: [PATCH 19/28] [FPA-Bistream] Updating fabric bitstream writer to organize bitstream for flatten BL/WLs --- .../libopenfpgautil/src/openfpga_decode.cpp | 13 ++++ .../libopenfpgautil/src/openfpga_decode.h | 12 ++++ .../write_text_fabric_bitstream.cpp | 61 ++++++++++++++++++- openfpga/src/utils/fabric_bitstream_utils.cpp | 41 ++++++++++++- openfpga/src/utils/fabric_bitstream_utils.h | 23 +++++++ 5 files changed, 148 insertions(+), 2 deletions(-) diff --git a/libopenfpga/libopenfpgautil/src/openfpga_decode.cpp b/libopenfpga/libopenfpgautil/src/openfpga_decode.cpp index d6a6d0463..2961f423b 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_decode.cpp +++ b/libopenfpga/libopenfpgautil/src/openfpga_decode.cpp @@ -80,6 +80,19 @@ std::vector ito1hot_charvec(const size_t& in_int, return ret; } +std::string combine_two_1hot_str(const std::string& code1, + const std::string& code2) { + VTR_ASSERT(code1.length() == code2.length()); + std::string ret = code1; + for (size_t ichar = 0; ichar < code2.length(); ichar++) { + VTR_ASSERT('0' == code2[ichar] || '1' == code2[ichar]); + if ('1' == code2[ichar]) { + ret[ichar] = code2[ichar]; + } + } + return ret; +} + /******************************************************************** * Converter an integer to a binary vector * For example: diff --git a/libopenfpga/libopenfpgautil/src/openfpga_decode.h b/libopenfpga/libopenfpgautil/src/openfpga_decode.h index 21568b0dc..4798af856 100644 --- a/libopenfpga/libopenfpgautil/src/openfpga_decode.h +++ b/libopenfpga/libopenfpgautil/src/openfpga_decode.h @@ -25,6 +25,18 @@ std::vector ito1hot_vec(const size_t& in_int, std::vector ito1hot_charvec(const size_t& in_int, const size_t& bin_len); +/******************************************************************** + * @brief Combine to two 1-hot codes which are in string format + * Any unique '1' will be merged + * For example: + * Code 1: 001000110 + * Code 2: 010001001 + * Output: 011001111 + * @note This function requires two codes in the same length + ********************************************************************/ +std::string combine_two_1hot_str(const std::string& code1, + const std::string& code2); + std::vector itobin_vec(const size_t& in_int, const size_t& bin_len); diff --git a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp index 8b2daaf87..8130fb447 100644 --- a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp @@ -180,6 +180,45 @@ int write_memory_bank_fabric_bitstream_to_text_file(std::fstream& fp, return status; } +/******************************************************************** + * Write the fabric bitstream fitting a memory bank protocol + * to a plain text file + * + * Return: + * - 0 if succeed + * - 1 if critical errors occured + *******************************************************************/ +static +int write_memory_bank_flatten_fabric_bitstream_to_text_file(std::fstream& fp, + const FabricBitstream& fabric_bitstream) { + int status = 0; + + MemoryBankFabricBitstream fabric_bits_by_addr = build_memory_bank_fabric_bitstream_by_address(fabric_bitstream); + + /* 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 = fabric_bits_by_addr.begin()->first.first.size(); + size_t wl_addr_size = fabric_bits_by_addr.begin()->first.second.size(); + + /* Output information about how to intepret the bitstream */ + fp << "// Bitstream length: " << fabric_bits_by_addr.size() << std::endl; + fp << "// Bitstream width (LSB -> MSB): "; + fp << ""; + fp << ""; + fp << std::endl; + + for (const auto& addr_din_pair : fabric_bits_by_addr) { + /* Write BL address code */ + fp << addr_din_pair.first.first; + /* Write WL address code */ + fp << addr_din_pair.first.second; + fp << std::endl; + } + + return status; +} + /******************************************************************** * Write the fabric bitstream fitting a frame-based protocol * to a plain text file @@ -306,7 +345,27 @@ int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manage bitstream_manager, fabric_bitstream); break; - case CONFIG_MEM_QL_MEMORY_BANK: + case CONFIG_MEM_QL_MEMORY_BANK: { + /* Bitstream organization depends on the BL/WL protocols + * - If BL uses decoders, we have to config each memory cell one by one. + * - If BL uses flatten, we can configure all the memory cells on the same row by enabling dedicated WL + * In such case, we will merge the BL data under the same WL address + * Fast configuration is NOT applicable in this case + * - if BL uses shift-register, TODO + */ + if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) { + status = write_memory_bank_fabric_bitstream_to_text_file(fp, + apply_fast_configuration, + bit_value_to_skip, + fabric_bitstream); + } else { + VTR_ASSERT(BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type() + || BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()); + status = write_memory_bank_flatten_fabric_bitstream_to_text_file(fp, + fabric_bitstream); + } + break; + } case CONFIG_MEM_MEMORY_BANK: status = write_memory_bank_fabric_bitstream_to_text_file(fp, apply_fast_configuration, diff --git a/openfpga/src/utils/fabric_bitstream_utils.cpp b/openfpga/src/utils/fabric_bitstream_utils.cpp index 52f81dcdb..4fb46f0cf 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.cpp +++ b/openfpga/src/utils/fabric_bitstream_utils.cpp @@ -188,7 +188,7 @@ size_t find_frame_based_fast_configuration_fabric_bitstream_size(const FabricBit } /******************************************************************** - * Reorganize the fabric bitstream for memory banks + * Reorganize the fabric bitstream for memory banks which use BL and WL decoders * by the same address across regions: * This is due to that the length of fabric bitstream could be different in each region. * Template: @@ -232,6 +232,45 @@ MemoryBankFabricBitstream build_memory_bank_fabric_bitstream_by_address(const Fa return fabric_bits_by_addr; } +MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream) { + /* 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)) { + /* Create string for BL address */ + std::string bl_addr_str; + for (const char& addr_bit : fabric_bitstream.bit_bl_address(bit_id)) { + bl_addr_str.push_back(addr_bit); + } + + /* Create string for WL address */ + std::string wl_addr_str; + for (const char& addr_bit : fabric_bitstream.bit_wl_address(bit_id)) { + wl_addr_str.push_back(addr_bit); + } + + /* Place the config bit */ + auto result = fabric_bits_per_region[region].find(wl_addr_str); + if (result == fabric_bits_per_region[region].end()) { + /* This is a new bit, resize the vector to the number of regions + * and deposit '0' to all the bits + */ + fabric_bits_per_region[region][wl_addr_str] = bl_addr_str; + } else { + VTR_ASSERT_SAFE(result != fabric_bits_per_region[region].end()); + result->second = combine_two_1hot_str(bl_addr_str, result->second); + } + } + } + + /* TODO: Combine the bitstream from different region into a unique one. Now we follow the convention: use (BL, WL) pairs */ + MemoryBankFlattenFabricBitstream fabric_bits; + + return fabric_bits; +} + + /******************************************************************** * For fast configuration, the number of bits to be skipped * the rule to skip any configuration bit should consider the whole data input values. diff --git a/openfpga/src/utils/fabric_bitstream_utils.h b/openfpga/src/utils/fabric_bitstream_utils.h index 4da8c3c92..ca23a5363 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.h +++ b/openfpga/src/utils/fabric_bitstream_utils.h @@ -37,6 +37,29 @@ 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); +/******************************************************************** + * @ brief Reorganize the fabric bitstream for memory banks which use flatten or shift register to manipulate BL and WLs + * For each configuration region, we will merge BL address (which are 1-hot codes) under the same WL address + * + * Quick Example + * _ _ + * 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 + * + * @note the std::map may cause large memory footprint for large bitstream databases! + *******************************************************************/ +typedef std::map, std::vector> MemoryBankFlattenFabricBitstream; +MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream); + /* 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 1a2a2a6e633d504beb9d3582351b74154bfa43e2 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 25 Sep 2021 12:03:33 -0700 Subject: [PATCH 20/28] [FPGA-Bitstream] Relax fabric bitstream address check --- .../build_fabric_bitstream_memory_bank.cpp | 30 ++++++++++++++++--- .../src/fpga_bitstream/fabric_bitstream.cpp | 23 ++++++++++---- .../src/fpga_bitstream/fabric_bitstream.h | 9 ++++-- 3 files changed, 49 insertions(+), 13 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 1a5479842..09ae2e966 100644 --- a/openfpga/src/fpga_bitstream/build_fabric_bitstream_memory_bank.cpp +++ b/openfpga/src/fpga_bitstream/build_fabric_bitstream_memory_bank.cpp @@ -194,10 +194,10 @@ void rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(const B } /* Set BL address */ - fabric_bitstream.set_bit_bl_address(fabric_bit, bl_addr_bits_vec); + fabric_bitstream.set_bit_bl_address(fabric_bit, bl_addr_bits_vec, true); /* Set WL address */ - fabric_bitstream.set_bit_wl_address(fabric_bit, wl_addr_bits_vec); + fabric_bitstream.set_bit_wl_address(fabric_bit, wl_addr_bits_vec, true); /* Set data input */ fabric_bitstream.set_bit_din(fabric_bit, bitstream_manager.bit_value(config_bit)); @@ -291,6 +291,28 @@ void build_module_fabric_dependent_bitstream_ql_memory_bank(const ConfigProtocol /* Build the bitstream for all the blocks in this region */ FabricBitRegionId fabric_bitstream_region = fabric_bitstream.add_region(); + + /* Find the BL/WL port (different region may have different sizes of BL/WLs) */ + ModulePortId cur_bl_addr_port; + if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) { + cur_bl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_BL_ADDRESS_PORT_NAME)); + } else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) { + cur_bl_addr_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_BL_PORT_NAME), config_region)); + } else { + /* TODO */ + VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()); + } + + ModulePortId cur_wl_addr_port; + if (BLWL_PROTOCOL_DECODER == config_protocol.wl_protocol_type()) { + cur_wl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_WL_ADDRESS_PORT_NAME)); + } else if (BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()) { + cur_wl_addr_port = module_manager.find_module_port(top_module, generate_regional_blwl_port_name(std::string(MEMORY_WL_PORT_NAME), config_region)); + } else { + /* TODO */ + VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type()); + } + BasicPort cur_wl_addr_port_info = module_manager.module_port(top_module, cur_wl_addr_port); /************************************************************** * Precompute the BLs and WLs distribution across the FPGA fabric @@ -319,8 +341,8 @@ void build_module_fabric_dependent_bitstream_ql_memory_bank(const ConfigProtocol config_region, config_protocol, circuit_lib, config_protocol.memory_model(), - bl_addr_port_info.get_width(), - wl_addr_port_info.get_width(), + cur_bl_addr_port_info.get_width(), + cur_wl_addr_port_info.get_width(), temp_num_bls_cur_tile, bl_start_index_per_tile, temp_num_wls_cur_tile, wl_start_index_per_tile, temp_coord, diff --git a/openfpga/src/fpga_bitstream/fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/fabric_bitstream.cpp index 785327661..ca3702a3e 100644 --- a/openfpga/src/fpga_bitstream/fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/fabric_bitstream.cpp @@ -139,24 +139,35 @@ FabricBitId FabricBitstream::add_bit(const ConfigBitId& config_bit_id) { } void FabricBitstream::set_bit_address(const FabricBitId& bit_id, - const std::vector& address) { + const std::vector& address, + const bool& tolerant_short_address) { VTR_ASSERT(true == valid_bit_id(bit_id)); VTR_ASSERT(true == use_address_); - VTR_ASSERT(address_length_ == address.size()); + if (tolerant_short_address) { + VTR_ASSERT(address_length_ => address.size()); + } else { + VTR_ASSERT(address_length_ == address.size()); + } bit_addresses_[bit_id] = address; } void FabricBitstream::set_bit_bl_address(const FabricBitId& bit_id, - const std::vector& address) { - set_bit_address(bit_id, address); + const std::vector& address, + const bool& tolerant_short_address) { + set_bit_address(bit_id, address, tolerant_short_address); } void FabricBitstream::set_bit_wl_address(const FabricBitId& bit_id, - const std::vector& address) { + const std::vector& address, + const bool& tolerant_short_address) { VTR_ASSERT(true == valid_bit_id(bit_id)); VTR_ASSERT(true == use_address_); VTR_ASSERT(true == use_wl_address_); - VTR_ASSERT(wl_address_length_ == address.size()); + if (tolerant_short_address) { + VTR_ASSERT(wl_address_length_ => address.size()); + } else { + VTR_ASSERT(wl_address_length_ == address.size()); + } bit_wl_addresses_[bit_id] = address; } diff --git a/openfpga/src/fpga_bitstream/fabric_bitstream.h b/openfpga/src/fpga_bitstream/fabric_bitstream.h index 028452a58..e46edb74f 100644 --- a/openfpga/src/fpga_bitstream/fabric_bitstream.h +++ b/openfpga/src/fpga_bitstream/fabric_bitstream.h @@ -135,13 +135,16 @@ class FabricBitstream { FabricBitId add_bit(const ConfigBitId& config_bit_id); void set_bit_address(const FabricBitId& bit_id, - const std::vector& address); + const std::vector& address, + const bool& tolerant_short_address = false); void set_bit_bl_address(const FabricBitId& bit_id, - const std::vector& address); + const std::vector& address, + const bool& tolerant_short_address = false); void set_bit_wl_address(const FabricBitId& bit_id, - const std::vector& address); + const std::vector& address, + const bool& tolerant_short_address = false); void set_bit_din(const FabricBitId& bit_id, const char& din); From 386812777c563183eae0fe980e1d96dbe1618f2e Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 25 Sep 2021 12:49:32 -0700 Subject: [PATCH 21/28] [FPGA-Bitstream] Upgraded bitstream writer to support flatten BL/WLs --- .../build_fabric_bitstream_memory_bank.cpp | 1 + .../src/fpga_bitstream/fabric_bitstream.cpp | 4 +- .../write_text_fabric_bitstream.cpp | 26 ++++++--- openfpga/src/utils/fabric_bitstream_utils.cpp | 56 ++++++++++++++++++- openfpga/src/utils/fabric_bitstream_utils.h | 3 +- 5 files changed, 78 insertions(+), 12 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 09ae2e966..d4befa8bb 100644 --- a/openfpga/src/fpga_bitstream/build_fabric_bitstream_memory_bank.cpp +++ b/openfpga/src/fpga_bitstream/build_fabric_bitstream_memory_bank.cpp @@ -302,6 +302,7 @@ void build_module_fabric_dependent_bitstream_ql_memory_bank(const ConfigProtocol /* TODO */ VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()); } + BasicPort cur_bl_addr_port_info = module_manager.module_port(top_module, cur_bl_addr_port); ModulePortId cur_wl_addr_port; if (BLWL_PROTOCOL_DECODER == config_protocol.wl_protocol_type()) { diff --git a/openfpga/src/fpga_bitstream/fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/fabric_bitstream.cpp index ca3702a3e..23530f627 100644 --- a/openfpga/src/fpga_bitstream/fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/fabric_bitstream.cpp @@ -144,7 +144,7 @@ void FabricBitstream::set_bit_address(const FabricBitId& bit_id, VTR_ASSERT(true == valid_bit_id(bit_id)); VTR_ASSERT(true == use_address_); if (tolerant_short_address) { - VTR_ASSERT(address_length_ => address.size()); + VTR_ASSERT(address_length_ >= address.size()); } else { VTR_ASSERT(address_length_ == address.size()); } @@ -164,7 +164,7 @@ void FabricBitstream::set_bit_wl_address(const FabricBitId& bit_id, VTR_ASSERT(true == use_address_); VTR_ASSERT(true == use_wl_address_); if (tolerant_short_address) { - VTR_ASSERT(wl_address_length_ => address.size()); + VTR_ASSERT(wl_address_length_ >= address.size()); } else { VTR_ASSERT(wl_address_length_ == address.size()); } diff --git a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp index 8130fb447..13ef05726 100644 --- a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp @@ -190,29 +190,40 @@ 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& bit_value_to_skip, const FabricBitstream& fabric_bitstream) { int status = 0; - MemoryBankFabricBitstream fabric_bits_by_addr = build_memory_bank_fabric_bitstream_by_address(fabric_bitstream); + MemoryBankFlattenFabricBitstream fabric_bits = build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, bit_value_to_skip); /* The address sizes and data input sizes are the same across any element, * just get it from the 1st element to save runtime */ - size_t bl_addr_size = fabric_bits_by_addr.begin()->first.first.size(); - size_t wl_addr_size = fabric_bits_by_addr.begin()->first.second.size(); + size_t bl_addr_size = 0; + for (const auto& bl_vec : fabric_bits.begin()->first) { + bl_addr_size += bl_vec.size(); + } + size_t wl_addr_size = 0; + for (const auto& wl_vec : fabric_bits.begin()->second) { + wl_addr_size += wl_vec.size(); + } /* Output information about how to intepret the bitstream */ - fp << "// Bitstream length: " << fabric_bits_by_addr.size() << std::endl; + fp << "// Bitstream length: " << fabric_bits.size() << std::endl; fp << "// Bitstream width (LSB -> MSB): "; fp << ""; fp << ""; fp << std::endl; - for (const auto& addr_din_pair : fabric_bits_by_addr) { + for (const auto& addr_pair : fabric_bits) { /* Write BL address code */ - fp << addr_din_pair.first.first; + for (const auto& bl_vec : addr_pair.first) { + fp << bl_vec; + } /* Write WL address code */ - fp << addr_din_pair.first.second; + for (const auto& wl_vec : addr_pair.second) { + fp << wl_vec; + } fp << std::endl; } @@ -362,6 +373,7 @@ int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manage VTR_ASSERT(BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type() || BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()); status = write_memory_bank_flatten_fabric_bitstream_to_text_file(fp, + bit_value_to_skip, fabric_bitstream); } break; diff --git a/openfpga/src/utils/fabric_bitstream_utils.cpp b/openfpga/src/utils/fabric_bitstream_utils.cpp index 4fb46f0cf..bd518c7b2 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.cpp +++ b/openfpga/src/utils/fabric_bitstream_utils.cpp @@ -232,12 +232,17 @@ MemoryBankFabricBitstream build_memory_bank_fabric_bitstream_by_address(const Fa return fabric_bits_by_addr; } -MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream) { +MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream, + const bool& bit_value_to_skip) { /* Build the bitstream by each region, here we use (WL, BL) pairs when storing bitstreams */ vtr::vector> 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) == '1') == bit_value_to_skip) { + continue; + } /* Create string for BL address */ std::string bl_addr_str; for (const char& addr_bit : fabric_bitstream.bit_bl_address(bit_id)) { @@ -264,8 +269,55 @@ MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(cons } } - /* TODO: Combine the bitstream from different region into a unique one. Now we follow the convention: use (BL, WL) pairs */ + /* Find all the keys for the hash tables containing bitstream of each region */ + vtr::vector> fabric_bits_per_region_keys; + fabric_bits_per_region_keys.resize(fabric_bitstream.num_regions()); + for (const FabricBitRegionId& region : fabric_bitstream.regions()) { + /* Pre-allocate memory, because the key size may be large */ + fabric_bits_per_region_keys[region].reserve(fabric_bits_per_region[region].size()); + for (const auto& pair : fabric_bits_per_region[region]) { + fabric_bits_per_region_keys[region].push_back(pair.first); + } + } + + /* Find the maxium key size */ + size_t max_key_size = 0; + for (const FabricBitRegionId& region : fabric_bitstream.regions()) { + max_key_size = std::max(max_key_size, fabric_bits_per_region_keys[region].size()); + } + + /* Find the BL/WL sizes per region; Pair convention is (BL, WL) + * The address sizes are the same across any element, + * just get it from the 1st element to save runtime + */ + vtr::vector> max_blwl_sizes_per_region; + max_blwl_sizes_per_region.resize(fabric_bitstream.num_regions()); + for (const FabricBitRegionId& region : fabric_bitstream.regions()) { + max_blwl_sizes_per_region[region].first = std::max(max_blwl_sizes_per_region[region].first, fabric_bits_per_region[region].begin()->second.size()); + max_blwl_sizes_per_region[region].second = std::max(max_blwl_sizes_per_region[region].second, fabric_bits_per_region[region].begin()->first.size()); + } + + /* Combine the bitstream from different region into a unique one. Now we follow the convention: use (BL, WL) pairs */ MemoryBankFlattenFabricBitstream fabric_bits; + for (size_t ikey = 0; ikey < max_key_size; ikey++) { + /* Prepare the final BL/WL vectors to be added to the bitstream database */ + std::vector cur_bl_vectors; + std::vector cur_wl_vectors; + for (const FabricBitRegionId& region : fabric_bitstream.regions()) { + /* If the key id is in bound for the key list in this region, find the BL and WL and add to the final bitstream database + * If the key id is out of bound for the key list in this region, we append an all-zero string for both BL and WLs + */ + if (ikey < fabric_bits_per_region_keys[region].size()) { + cur_wl_vectors.push_back(fabric_bits_per_region_keys[region][ikey]); + cur_bl_vectors.push_back(fabric_bits_per_region[region].at(fabric_bits_per_region_keys[region][ikey])); + } else { + cur_wl_vectors.push_back(std::string(max_blwl_sizes_per_region[region].second, '0')); + cur_bl_vectors.push_back(std::string(max_blwl_sizes_per_region[region].first, '0')); + } + } + /* Add the pair to std map */ + fabric_bits[cur_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 ca23a5363..cb3406347 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.h +++ b/openfpga/src/utils/fabric_bitstream_utils.h @@ -58,7 +58,8 @@ 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! *******************************************************************/ typedef std::map, std::vector> MemoryBankFlattenFabricBitstream; -MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream); +MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream, + const bool& bit_value_to_skip); /* Alias to a specific organization of bitstreams for memory bank configuration protocol */ typedef std::map, std::vector> MemoryBankFabricBitstream; From a56d1f4fdb27f211bb0e97746fe0f47d984774a6 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 25 Sep 2021 17:49:15 -0700 Subject: [PATCH 22/28] [FPGA-Verilog] Upgraded testbench generator to support memory bank using flatten BL/WLs --- .../fpga_verilog/verilog_top_testbench.cpp | 14 +- .../verilog_top_testbench_memory_bank.cpp | 290 +++++++++++++++++- .../verilog_top_testbench_memory_bank.h | 9 + .../src/fpga_verilog/verilog_writer_utils.cpp | 28 +- .../src/fpga_verilog/verilog_writer_utils.h | 4 + 5 files changed, 333 insertions(+), 12 deletions(-) diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp index eb070690d..7f7f12790 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp @@ -229,6 +229,8 @@ void print_verilog_top_testbench_config_protocol_port(std::fstream& fp, print_verilog_top_testbench_config_chain_port(fp, module_manager, top_module); break; case CONFIG_MEM_QL_MEMORY_BANK: + print_verilog_top_testbench_ql_memory_bank_port(fp, module_manager, top_module, config_protocol); + break; case CONFIG_MEM_MEMORY_BANK: print_verilog_top_testbench_memory_bank_port(fp, module_manager, top_module); break; @@ -1111,7 +1113,10 @@ void print_verilog_top_testbench_configuration_protocol_stimulus(std::fstream& f case CONFIG_MEM_FRAME_BASED: { ModulePortId en_port_id = module_manager.find_module_port(top_module, std::string(DECODER_ENABLE_PORT_NAME)); - BasicPort en_port = module_manager.module_port(top_module, en_port_id); + BasicPort en_port(std::string(DECODER_ENABLE_PORT_NAME), 1); + if (en_port_id) { + en_port = module_manager.module_port(top_module, en_port_id); + } BasicPort en_register_port(std::string(en_port.get_name() + std::string(TOP_TB_CLOCK_REG_POSTFIX)), 1); print_verilog_comment(fp, std::string("---- Generate enable signal waveform -----")); print_verilog_shifted_clock_stimuli(fp, en_register_port, @@ -1684,7 +1689,7 @@ void print_verilog_full_testbench_frame_decoder_bitstream(std::fstream& fp, static void print_verilog_full_testbench_bitstream(std::fstream& fp, const std::string& bitstream_file, - const e_config_protocol_type& config_protocol_type, + const ConfigProtocol& config_protocol, const bool& fast_configuration, const bool& bit_value_to_skip, const ModuleManager& module_manager, @@ -1693,7 +1698,7 @@ void print_verilog_full_testbench_bitstream(std::fstream& fp, const FabricBitstream& fabric_bitstream) { /* Branch on the type of configuration protocol */ - switch (config_protocol_type) { + switch (config_protocol.type()) { case CONFIG_MEM_STANDALONE: print_verilog_full_testbench_vanilla_bitstream(fp, bitstream_file, @@ -1719,6 +1724,7 @@ void print_verilog_full_testbench_bitstream(std::fstream& fp, break; case CONFIG_MEM_QL_MEMORY_BANK: print_verilog_full_testbench_ql_memory_bank_bitstream(fp, bitstream_file, + config_protocol, fast_configuration, bit_value_to_skip, module_manager, top_module, @@ -1998,7 +2004,7 @@ int print_verilog_full_testbench(const ModuleManager& module_manager, /* load bitstream to FPGA fabric in a configuration phase */ print_verilog_full_testbench_bitstream(fp, bitstream_file, - config_protocol.type(), + config_protocol, apply_fast_configuration, bit_value_to_skip, module_manager, top_module, 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 d2a286984..b39f8b1c1 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.cpp @@ -36,13 +36,264 @@ /* begin namespace openfpga */ namespace openfpga { -void print_verilog_full_testbench_ql_memory_bank_bitstream(std::fstream& fp, - const std::string& bitstream_file, - const bool& fast_configuration, - const bool& bit_value_to_skip, - const ModuleManager& module_manager, - const ModuleId& top_module, - const FabricBitstream& fabric_bitstream) { +void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& top_module, + const ConfigProtocol& config_protocol) { + /* Validate the file stream */ + valid_file_stream(fp); + + /* Print the address port for the Bit-Line decoder here */ + if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) { + print_verilog_comment(fp, std::string("---- Address port for Bit-Line decoder -----")); + ModulePortId bl_addr_port_id = module_manager.find_module_port(top_module, + std::string(DECODER_BL_ADDRESS_PORT_NAME)); + BasicPort bl_addr_port = module_manager.module_port(top_module, bl_addr_port_id); + + fp << generate_verilog_port(VERILOG_PORT_REG, bl_addr_port) << ";" << std::endl; + } else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) { + print_verilog_comment(fp, std::string("---- Bit-Line ports -----")); + for (const ConfigRegionId& region : module_manager.regions(top_module)) { + ModulePortId bl_port_id = module_manager.find_module_port(top_module, + generate_regional_blwl_port_name(std::string(MEMORY_BL_PORT_NAME), region)); + BasicPort bl_port = module_manager.module_port(top_module, bl_port_id); + fp << generate_verilog_port(VERILOG_PORT_REG, bl_port) << ";" << std::endl; + } + } else { + VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()); + /* TODO */ + } + + /* Print the address port for the Word-Line decoder here */ + if (BLWL_PROTOCOL_DECODER == config_protocol.wl_protocol_type()) { + print_verilog_comment(fp, std::string("---- Address port for Word-Line decoder -----")); + ModulePortId wl_addr_port_id = module_manager.find_module_port(top_module, + std::string(DECODER_WL_ADDRESS_PORT_NAME)); + BasicPort wl_addr_port = module_manager.module_port(top_module, wl_addr_port_id); + + fp << generate_verilog_port(VERILOG_PORT_REG, wl_addr_port) << ";" << std::endl; + } else if (BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()) { + print_verilog_comment(fp, std::string("---- Word-Line ports -----")); + for (const ConfigRegionId& region : module_manager.regions(top_module)) { + ModulePortId wl_port_id = module_manager.find_module_port(top_module, + generate_regional_blwl_port_name(std::string(MEMORY_WL_PORT_NAME), region)); + BasicPort wl_port = module_manager.module_port(top_module, wl_port_id); + fp << generate_verilog_port(VERILOG_PORT_REG, wl_port) << ";" << std::endl; + } + } else { + VTR_ASSERT(BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type()); + /* TODO */ + } + + /* Print the data-input port: only available when BL has a decoder */ + if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) { + print_verilog_comment(fp, std::string("---- Data input port for memory decoders -----")); + ModulePortId din_port_id = module_manager.find_module_port(top_module, + std::string(DECODER_DATA_IN_PORT_NAME)); + BasicPort din_port = module_manager.module_port(top_module, din_port_id); + fp << generate_verilog_port(VERILOG_PORT_REG, din_port) << ";" << std::endl; + } + + /* Print the optional readback port for the decoder here */ + if (BLWL_PROTOCOL_DECODER == config_protocol.wl_protocol_type()) { + print_verilog_comment(fp, std::string("---- Readback port for memory decoders -----")); + ModulePortId readback_port_id = module_manager.find_module_port(top_module, + std::string(DECODER_READBACK_PORT_NAME)); + if (readback_port_id) { + BasicPort readback_port = module_manager.module_port(top_module, readback_port_id); + fp << generate_verilog_port(VERILOG_PORT_WIRE, readback_port) << ";" << std::endl; + /* Disable readback in full testbenches */ + print_verilog_wire_constant_values(fp, readback_port, std::vector(readback_port.get_width(), 0)); + } + } else if (BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()) { + print_verilog_comment(fp, std::string("---- Word line read ports -----")); + for (const ConfigRegionId& region : module_manager.regions(top_module)) { + ModulePortId wlr_port_id = module_manager.find_module_port(top_module, + generate_regional_blwl_port_name(std::string(MEMORY_WLR_PORT_NAME), region)); + if (wlr_port_id) { + BasicPort wlr_port = module_manager.module_port(top_module, wlr_port_id); + fp << generate_verilog_port(VERILOG_PORT_WIRE, wlr_port) << ";" << std::endl; + /* Disable readback in full testbenches */ + print_verilog_wire_constant_values(fp, wlr_port, std::vector(wlr_port.get_width(), 0)); + } + } + } + + /* Generate enable signal waveform here: + * which is a 90 degree phase shift than the programming clock + */ + print_verilog_comment(fp, std::string("---- Wire enable port of memory decoders -----")); + ModulePortId en_port_id = module_manager.find_module_port(top_module, + std::string(DECODER_ENABLE_PORT_NAME)); + BasicPort en_port(std::string(DECODER_ENABLE_PORT_NAME), 1); + if (en_port_id) { + en_port = module_manager.module_port(top_module, en_port_id); + } + BasicPort en_register_port(std::string(en_port.get_name() + std::string(TOP_TB_CLOCK_REG_POSTFIX)), 1); + + BasicPort config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1); + + fp << generate_verilog_port(VERILOG_PORT_WIRE, en_port) << ";" << std::endl; + fp << generate_verilog_port(VERILOG_PORT_REG, en_register_port) << ";" << std::endl; + + write_tab_to_file(fp, 1); + fp << "assign "; + fp << generate_verilog_port(VERILOG_PORT_CONKT, en_port); + fp << "= "; + fp << "~" << generate_verilog_port(VERILOG_PORT_CONKT, en_register_port); + fp << " & "; + fp << "~" << generate_verilog_port(VERILOG_PORT_CONKT, config_done_port); + fp << ";" << std::endl; +} + +/* Verilog codes to load bitstream from a bit file for memory bank using flatten BL/WLs */ +static +void print_verilog_full_testbench_ql_memory_bank_flatten_bitstream(std::fstream& fp, + const std::string& bitstream_file, + const bool& fast_configuration, + const bool& bit_value_to_skip, + const ModuleManager& module_manager, + const ModuleId& top_module, + const FabricBitstream& fabric_bitstream) { + /* Validate the file stream */ + valid_file_stream(fp); + + /* No fast configuration available in this configuration protocol. Give a warning */ + if (true == fast_configuration) { + VTR_LOG_WARN("Fast configuration is not available for flatten BL protocol"); + } + + /* Reorganize the fabric bitstream by the same address across regions */ + MemoryBankFlattenFabricBitstream fabric_bits_by_addr = build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, + bit_value_to_skip); + + /* Feed address and data input pair one by one + * Note: the first cycle is reserved for programming reset + * We should give dummy values + */ + std::vector bl_ports; + for (const ConfigRegionId& region : module_manager.regions(top_module)) { + ModulePortId cur_bl_port_id = module_manager.find_module_port(top_module, + generate_regional_blwl_port_name(std::string(MEMORY_BL_PORT_NAME), region)); + bl_ports.push_back(module_manager.module_port(top_module, cur_bl_port_id)); + } + + std::vector wl_ports; + for (const ConfigRegionId& region : module_manager.regions(top_module)) { + ModulePortId cur_wl_port_id = module_manager.find_module_port(top_module, + generate_regional_blwl_port_name(std::string(MEMORY_WL_PORT_NAME), region)); + wl_ports.push_back(module_manager.module_port(top_module, cur_wl_port_id)); + } + + /* Calculate the total size of BL/WL ports */ + size_t bl_port_width = 0; + for (const BasicPort& bl_port : bl_ports) { + bl_port_width += bl_port.get_width(); + } + size_t wl_port_width = 0; + for (const BasicPort& wl_port : wl_ports) { + wl_port_width += wl_port.get_width(); + } + + std::vector initial_bl_values(bl_port_width, 0); + std::vector initial_wl_values(wl_port_width, 0); + + /* Define a constant for the bitstream length */ + print_verilog_define_flag(fp, std::string(TOP_TB_BITSTREAM_LENGTH_VARIABLE), fabric_bits_by_addr.size()); + print_verilog_define_flag(fp, std::string(TOP_TB_BITSTREAM_WIDTH_VARIABLE), bl_port_width + wl_port_width); + + /* Declare local variables for bitstream loading in Verilog */ + print_verilog_comment(fp, "----- Virtual memory to store the bitstream from external file -----"); + fp << "reg [0:`" << TOP_TB_BITSTREAM_WIDTH_VARIABLE << " - 1] "; + fp << TOP_TB_BITSTREAM_MEM_REG_NAME << "[0:`" << TOP_TB_BITSTREAM_LENGTH_VARIABLE << " - 1];"; + fp << std::endl; + + fp << "reg [$clog2(`" << TOP_TB_BITSTREAM_LENGTH_VARIABLE << "):0] " << TOP_TB_BITSTREAM_INDEX_REG_NAME << ";" << std::endl; + + print_verilog_comment(fp, "----- Preload bitstream file to a virtual memory -----"); + fp << "initial begin" << std::endl; + fp << "\t"; + fp << "$readmemb(\"" << bitstream_file << "\", " << TOP_TB_BITSTREAM_MEM_REG_NAME << ");"; + fp << std::endl; + + print_verilog_comment(fp, "----- Bit-Line Address port default input -----"); + fp << "\t"; + fp << generate_verilog_ports_constant_values(bl_ports, initial_bl_values); + fp << ";"; + fp << std::endl; + + print_verilog_comment(fp, "----- Word-Line Address port default input -----"); + fp << "\t"; + fp << generate_verilog_ports_constant_values(wl_ports, initial_wl_values); + fp << ";"; + fp << std::endl; + + fp << "\t"; + fp << TOP_TB_BITSTREAM_INDEX_REG_NAME << " <= 0"; + fp << ";"; + fp << std::endl; + + fp << "end"; + fp << std::endl; + + print_verilog_comment(fp, "----- Begin bitstream loading during configuration phase -----"); + BasicPort prog_clock_port(std::string(TOP_TB_PROG_CLOCK_PORT_NAME) + std::string(TOP_TB_CLOCK_REG_POSTFIX), 1); + fp << "always"; + fp << " @(negedge " << generate_verilog_port(VERILOG_PORT_CONKT, prog_clock_port) << ")"; + fp << " begin"; + fp << std::endl; + + fp << "\t"; + fp << "if ("; + fp << TOP_TB_BITSTREAM_INDEX_REG_NAME; + fp << " >= "; + fp << "`" << TOP_TB_BITSTREAM_LENGTH_VARIABLE; + fp << ") begin"; + fp << std::endl; + + BasicPort config_done_port(std::string(TOP_TB_CONFIG_DONE_PORT_NAME), 1); + fp << "\t\t"; + std::vector config_done_final_values(config_done_port.get_width(), 1); + fp << generate_verilog_port_constant_values(config_done_port, config_done_final_values, true); + fp << ";" << std::endl; + + fp << "\t"; + fp << "end else begin"; + fp << std::endl; + + std::vector blwl_ports = bl_ports; + blwl_ports.insert(blwl_ports.end(), wl_ports.begin(), wl_ports.end()); + fp << "\t\t"; + fp << generate_verilog_ports(blwl_ports); + fp << " <= "; + fp << TOP_TB_BITSTREAM_MEM_REG_NAME << "[" << TOP_TB_BITSTREAM_INDEX_REG_NAME << "]"; + fp << ";" << std::endl; + + fp << "\t\t"; + fp << TOP_TB_BITSTREAM_INDEX_REG_NAME; + fp << " <= "; + fp << TOP_TB_BITSTREAM_INDEX_REG_NAME << " + 1"; + fp << ";" << std::endl; + + fp << "\t"; + fp << "end"; + fp << std::endl; + + fp << "end"; + fp << std::endl; + + print_verilog_comment(fp, "----- End bitstream loading during configuration phase -----"); +} + +/* Verilog codes to load bitstream from a bit file for memory bank using BL/WL decoders */ +static +void print_verilog_full_testbench_ql_memory_bank_decoder_bitstream(std::fstream& fp, + const std::string& bitstream_file, + const bool& fast_configuration, + const bool& bit_value_to_skip, + const ModuleManager& module_manager, + const ModuleId& top_module, + const FabricBitstream& fabric_bitstream) { /* Validate the file stream */ valid_file_stream(fp); @@ -172,4 +423,29 @@ void print_verilog_full_testbench_ql_memory_bank_bitstream(std::fstream& fp, print_verilog_comment(fp, "----- End bitstream loading during configuration phase -----"); } +void print_verilog_full_testbench_ql_memory_bank_bitstream(std::fstream& fp, + const std::string& bitstream_file, + const ConfigProtocol& config_protocol, + const bool& fast_configuration, + const bool& bit_value_to_skip, + const ModuleManager& module_manager, + const ModuleId& top_module, + const FabricBitstream& fabric_bitstream) { + if ( (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) + && (BLWL_PROTOCOL_DECODER == config_protocol.wl_protocol_type()) ) { + print_verilog_full_testbench_ql_memory_bank_decoder_bitstream(fp, bitstream_file, + fast_configuration, + bit_value_to_skip, + module_manager, top_module, + fabric_bitstream); + } else if ( (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) + && (BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()) ) { + print_verilog_full_testbench_ql_memory_bank_flatten_bitstream(fp, bitstream_file, + fast_configuration, + bit_value_to_skip, + module_manager, top_module, + fabric_bitstream); + } +} + } /* end namespace openfpga */ 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 e82a956e2..87ddf3ac5 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h +++ b/openfpga/src/fpga_verilog/verilog_top_testbench_memory_bank.h @@ -26,12 +26,21 @@ /* begin namespace openfpga */ namespace openfpga { +/** + * @brief Print local wires for memory bank configuration protocols + */ +void print_verilog_top_testbench_ql_memory_bank_port(std::fstream& fp, + const ModuleManager& module_manager, + const ModuleId& top_module, + const ConfigProtocol& config_protocol); + /** * @brief Print stimulus for a FPGA fabric with a memory bank configuration protocol * where configuration bits are programming in serial (one by one) */ void print_verilog_full_testbench_ql_memory_bank_bitstream(std::fstream& fp, const std::string& bitstream_file, + const ConfigProtocol& config_protocol, const bool& fast_configuration, const bool& bit_value_to_skip, const ModuleManager& module_manager, diff --git a/openfpga/src/fpga_verilog/verilog_writer_utils.cpp b/openfpga/src/fpga_verilog/verilog_writer_utils.cpp index 7d5c3dd77..4b5981eda 100644 --- a/openfpga/src/fpga_verilog/verilog_writer_utils.cpp +++ b/openfpga/src/fpga_verilog/verilog_writer_utils.cpp @@ -721,7 +721,7 @@ std::string generate_verilog_constant_values(const std::vector& const_va } /******************************************************************** - * Generate a verilog port with a deposite of constant values + * Generate a verilog port with a deposit of constant values ********************************************************************/ std::string generate_verilog_port_constant_values(const BasicPort& output_port, const std::vector& const_values, @@ -742,6 +742,32 @@ std::string generate_verilog_port_constant_values(const BasicPort& output_port, return port_str; } +/******************************************************************** + * Generate a list of verilog ports with a deposit of constant values + ********************************************************************/ +std::string generate_verilog_ports_constant_values(const std::vector& output_ports, + const std::vector& const_values, + const bool& is_register) { + std::string port_str; + + /* Must check: the port width matches */ + size_t total_width = 0; + for (const BasicPort& port : output_ports) { + total_width += port.get_width(); + } + VTR_ASSERT( const_values.size() == total_width ); + + port_str = generate_verilog_ports(output_ports); + if (is_register) { + port_str += " <= "; + } else { + VTR_ASSERT_SAFE(!is_register); + port_str += " = "; + } + port_str += generate_verilog_constant_values(const_values); + return port_str; +} + /******************************************************************** * Generate a wire connection, that assigns constant values to a * Verilog port diff --git a/openfpga/src/fpga_verilog/verilog_writer_utils.h b/openfpga/src/fpga_verilog/verilog_writer_utils.h index 09a5dba7a..67d60b7f1 100644 --- a/openfpga/src/fpga_verilog/verilog_writer_utils.h +++ b/openfpga/src/fpga_verilog/verilog_writer_utils.h @@ -111,6 +111,10 @@ std::string generate_verilog_port_constant_values(const BasicPort& output_port, const std::vector& const_values, const bool& is_register = false); +std::string generate_verilog_ports_constant_values(const std::vector& output_ports, + const std::vector& const_values, + const bool& is_register = false); + void print_verilog_wire_constant_values(std::fstream& fp, const BasicPort& output_port, const std::vector& const_values); From 3cf31f156597077b964e81a1b6e36df0dc51a61c Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 25 Sep 2021 18:22:55 -0700 Subject: [PATCH 23/28] [Engine] Fixed bugs --- .../build_fabric_bitstream_memory_bank.cpp | 13 ++++++++----- .../fpga_bitstream/write_text_fabric_bitstream.cpp | 2 +- openfpga/src/utils/fabric_bitstream_utils.cpp | 2 +- 3 files changed, 10 insertions(+), 7 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 d4befa8bb..998b3960b 100644 --- a/openfpga/src/fpga_bitstream/build_fabric_bitstream_memory_bank.cpp +++ b/openfpga/src/fpga_bitstream/build_fabric_bitstream_memory_bank.cpp @@ -19,6 +19,7 @@ #include "decoder_library_utils.h" #include "bitstream_manager_utils.h" +#include "memory_utils.h" #include "memory_bank_utils.h" #include "build_fabric_bitstream_memory_bank.h" @@ -73,7 +74,9 @@ void rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(const B std::vector configurable_children = module_manager.region_configurable_children(parent_module, config_region); VTR_ASSERT(2 <= configurable_children.size()); - size_t num_configurable_children = configurable_children.size() - 2; + size_t num_config_child_to_skip = estimate_num_configurable_children_to_skip_by_config_protocol(config_protocol, + configurable_children.size()); + size_t num_configurable_children = configurable_children.size() - num_config_child_to_skip; /* Early exit if there is no configurable children */ if (0 == num_configurable_children) { @@ -179,7 +182,7 @@ void rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(const B if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) { bl_addr_bits_vec = itobin_charvec(cur_bl_index, bl_addr_size); } else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type() - || BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) { + || BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()) { bl_addr_bits_vec = ito1hot_charvec(cur_bl_index, bl_addr_size); } @@ -189,15 +192,15 @@ void rec_build_module_fabric_dependent_ql_memory_bank_regional_bitstream(const B if (BLWL_PROTOCOL_DECODER == config_protocol.wl_protocol_type()) { wl_addr_bits_vec = itobin_charvec(cur_wl_index, wl_addr_size); } else if (BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type() - || BLWL_PROTOCOL_FLATTEN == config_protocol.wl_protocol_type()) { + || BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.wl_protocol_type()) { wl_addr_bits_vec = ito1hot_charvec(cur_wl_index, wl_addr_size); } /* Set BL address */ - fabric_bitstream.set_bit_bl_address(fabric_bit, bl_addr_bits_vec, true); + fabric_bitstream.set_bit_bl_address(fabric_bit, bl_addr_bits_vec, BLWL_PROTOCOL_DECODER != config_protocol.bl_protocol_type()); /* Set WL address */ - fabric_bitstream.set_bit_wl_address(fabric_bit, wl_addr_bits_vec, true); + fabric_bitstream.set_bit_wl_address(fabric_bit, wl_addr_bits_vec, BLWL_PROTOCOL_DECODER != config_protocol.wl_protocol_type()); /* Set data input */ fabric_bitstream.set_bit_din(fabric_bit, bitstream_manager.bit_value(config_bit)); diff --git a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp index 13ef05726..e6c458b37 100644 --- a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp @@ -370,7 +370,7 @@ int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manage bit_value_to_skip, fabric_bitstream); } else { - VTR_ASSERT(BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type() + VTR_ASSERT(BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type() || BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()); status = write_memory_bank_flatten_fabric_bitstream_to_text_file(fp, bit_value_to_skip, diff --git a/openfpga/src/utils/fabric_bitstream_utils.cpp b/openfpga/src/utils/fabric_bitstream_utils.cpp index bd518c7b2..c196429c3 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.cpp +++ b/openfpga/src/utils/fabric_bitstream_utils.cpp @@ -240,7 +240,7 @@ MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(cons 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) == '1') == bit_value_to_skip) { + if (fabric_bitstream.bit_din(bit_id) == bit_value_to_skip) { continue; } /* Create string for BL address */ From e06ac1163010e552a754ecf1398a0ad6a0d731c8 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 25 Sep 2021 19:21:16 -0700 Subject: [PATCH 24/28] [Engine] Bug fix --- 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 55203d993..63cf7ea77 100644 --- a/openfpga/src/fabric/build_top_module_memory_bank.cpp +++ b/openfpga/src/fabric/build_top_module_memory_bank.cpp @@ -901,13 +901,13 @@ void add_top_module_ql_memory_bank_sram_ports(ModuleManager& module_manager, case BLWL_PROTOCOL_FLATTEN: { /* Each region will have independent WLs */ for (const ConfigRegionId& config_region : module_manager.regions(module_id)) { - size_t wl_size = num_config_bits[config_region].first; + size_t wl_size = num_config_bits[config_region].second; BasicPort wl_port(generate_regional_blwl_port_name(std::string(MEMORY_WL_PORT_NAME), config_region), wl_size); module_manager.add_port(module_id, wl_port, ModuleManager::MODULE_INPUT_PORT); /* Optional: If we have WLR port, we should add a read-back port */ if (!circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_WLR).empty()) { - BasicPort readback_port(std::string(MEMORY_WLR_PORT_NAME), config_protocol.num_regions()); + BasicPort readback_port(std::string(MEMORY_WLR_PORT_NAME), wl_size); module_manager.add_port(module_id, readback_port, ModuleManager::MODULE_INPUT_PORT); } } From 29c351f5a45e1c40c1c512fd7fba3bf6e1ffceb0 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 25 Sep 2021 19:34:21 -0700 Subject: [PATCH 25/28] [Engine] Bug fix in estimating the configuration cycles for Verilog testbench generator --- .../fpga_verilog/verilog_top_testbench.cpp | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp index 7f7f12790..4b0524308 100644 --- a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp +++ b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp @@ -810,7 +810,7 @@ void print_verilog_top_testbench_ports(std::fstream& fp, * Note that this will not applicable to configuration chain!!! *******************************************************************/ static -size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz_type, +size_t calculate_num_config_clock_cycles(const ConfigProtocol& config_protocol, const bool& fast_configuration, const bool& bit_value_to_skip, const BitstreamManager& bitstream_manager, @@ -821,7 +821,7 @@ size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz size_t num_config_clock_cycles = 1 + regional_bitstream_max_size; /* Branch on the type of configuration protocol */ - switch (sram_orgz_type) { + switch (config_protocol.type()) { case CONFIG_MEM_STANDALONE: /* We just need 1 clock cycle to load all the configuration bits * since all the ports are exposed at the top-level @@ -849,7 +849,25 @@ size_t calculate_num_config_clock_cycles(const e_config_protocol_type& sram_orgz 100. * ((float)num_config_clock_cycles / (float)(1 + regional_bitstream_max_size) - 1.)); } break; - case CONFIG_MEM_QL_MEMORY_BANK: + case CONFIG_MEM_QL_MEMORY_BANK: { + if (BLWL_PROTOCOL_DECODER == config_protocol.bl_protocol_type()) { + /* For fast configuration, we will skip all the zero data points */ + num_config_clock_cycles = 1 + build_memory_bank_fabric_bitstream_by_address(fabric_bitstream).size(); + if (true == fast_configuration) { + size_t full_num_config_clock_cycles = num_config_clock_cycles; + num_config_clock_cycles = 1 + find_memory_bank_fast_configuration_fabric_bitstream_size(fabric_bitstream, bit_value_to_skip); + VTR_LOG("Fast configuration reduces number of configuration clock cycles from %lu to %lu (compression_rate = %f%)\n", + full_num_config_clock_cycles, + num_config_clock_cycles, + 100. * ((float)num_config_clock_cycles / (float)full_num_config_clock_cycles - 1.)); + } + } else if (BLWL_PROTOCOL_FLATTEN == config_protocol.bl_protocol_type()) { + num_config_clock_cycles = 1 + build_memory_bank_flatten_fabric_bitstream(fabric_bitstream, bit_value_to_skip).size(); + } else if (BLWL_PROTOCOL_SHIFT_REGISTER == config_protocol.bl_protocol_type()) { + /* TODO */ + } + break; + } case CONFIG_MEM_MEMORY_BANK: { /* For fast configuration, we will skip all the zero data points */ num_config_clock_cycles = 1 + build_memory_bank_fabric_bitstream_by_address(fabric_bitstream).size(); @@ -1922,7 +1940,7 @@ int print_verilog_full_testbench(const ModuleManager& module_manager, } /* Estimate the number of configuration clock cycles */ - size_t num_config_clock_cycles = calculate_num_config_clock_cycles(config_protocol.type(), + size_t num_config_clock_cycles = calculate_num_config_clock_cycles(config_protocol, apply_fast_configuration, bit_value_to_skip, bitstream_manager, From 33e9b27cb80902984bbefb88c552c14aaf69114e Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 25 Sep 2021 20:22:27 -0700 Subject: [PATCH 26/28] [Engine] Fixed a critical bug when building final bitstream, which may cause loss when merging BLs --- .../src/fpga_bitstream/write_text_fabric_bitstream.cpp | 8 ++++---- openfpga/src/utils/fabric_bitstream_utils.cpp | 7 ++----- openfpga/src/utils/fabric_bitstream_utils.h | 5 ++++- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp index e6c458b37..ee1b3deda 100644 --- a/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp +++ b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp @@ -200,11 +200,11 @@ int write_memory_bank_flatten_fabric_bitstream_to_text_file(std::fstream& fp, * just get it from the 1st element to save runtime */ size_t bl_addr_size = 0; - for (const auto& bl_vec : fabric_bits.begin()->first) { + 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()->second) { + for (const auto& wl_vec : fabric_bits.begin()->first) { wl_addr_size += wl_vec.size(); } @@ -217,11 +217,11 @@ int write_memory_bank_flatten_fabric_bitstream_to_text_file(std::fstream& fp, for (const auto& addr_pair : fabric_bits) { /* Write BL address code */ - for (const auto& bl_vec : addr_pair.first) { + for (const auto& bl_vec : addr_pair.second) { fp << bl_vec; } /* Write WL address code */ - for (const auto& wl_vec : addr_pair.second) { + for (const auto& wl_vec : addr_pair.first) { fp << wl_vec; } fp << std::endl; diff --git a/openfpga/src/utils/fabric_bitstream_utils.cpp b/openfpga/src/utils/fabric_bitstream_utils.cpp index c196429c3..2df7bcb23 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.cpp +++ b/openfpga/src/utils/fabric_bitstream_utils.cpp @@ -258,9 +258,6 @@ MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(cons /* Place the config bit */ auto result = fabric_bits_per_region[region].find(wl_addr_str); if (result == fabric_bits_per_region[region].end()) { - /* This is a new bit, resize the vector to the number of regions - * and deposit '0' to all the bits - */ fabric_bits_per_region[region][wl_addr_str] = bl_addr_str; } else { VTR_ASSERT_SAFE(result != fabric_bits_per_region[region].end()); @@ -297,7 +294,7 @@ MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(cons max_blwl_sizes_per_region[region].second = std::max(max_blwl_sizes_per_region[region].second, fabric_bits_per_region[region].begin()->first.size()); } - /* Combine the bitstream from different region into a unique one. Now we follow the convention: use (BL, WL) pairs */ + /* Combine the bitstream from different region into a unique one. Now we follow the convention: use (WL, BL) pairs */ MemoryBankFlattenFabricBitstream fabric_bits; for (size_t ikey = 0; ikey < max_key_size; ikey++) { /* Prepare the final BL/WL vectors to be added to the bitstream database */ @@ -316,7 +313,7 @@ MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(cons } } /* Add the pair to std map */ - fabric_bits[cur_bl_vectors] = cur_wl_vectors; + fabric_bits[cur_wl_vectors] = cur_bl_vectors; } return fabric_bits; diff --git a/openfpga/src/utils/fabric_bitstream_utils.h b/openfpga/src/utils/fabric_bitstream_utils.h index cb3406347..ad14aef74 100644 --- a/openfpga/src/utils/fabric_bitstream_utils.h +++ b/openfpga/src/utils/fabric_bitstream_utils.h @@ -37,6 +37,10 @@ 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 @@ -57,7 +61,6 @@ 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! *******************************************************************/ -typedef std::map, std::vector> MemoryBankFlattenFabricBitstream; MemoryBankFlattenFabricBitstream build_memory_bank_flatten_fabric_bitstream(const FabricBitstream& fabric_bitstream, const bool& bit_value_to_skip); From f9bceff33a60b79680a61e314264e90fc2e48ba0 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Sat, 25 Sep 2021 20:44:45 -0700 Subject: [PATCH 27/28] [Doc] Update documentation for the flatten BL/WL protocols --- docs/source/manual/arch_lang/config_protocol.rst | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/docs/source/manual/arch_lang/config_protocol.rst b/docs/source/manual/arch_lang/config_protocol.rst index 087914c80..560dc77fa 100644 --- a/docs/source/manual/arch_lang/config_protocol.rst +++ b/docs/source/manual/arch_lang/config_protocol.rst @@ -40,6 +40,7 @@ Template - ``scan_chain`` requires a circuit model type of ``ccff`` - ``frame_based`` requires a circuit model type of ``sram`` - ``memory_bank`` requires a circuit model type of ``sram`` + - ``ql_memory_bank`` requires a circuit model type of ``sram`` - ``standalone`` requires a circuit model type of ``sram`` .. option:: num_regions="" @@ -148,18 +149,29 @@ Users can customized the number of memory banks to be used across the fabrics. B .. warning:: Please do NOT add inverted Bit-Line and Word-Line inputs. It is not supported yet! - QuickLogic Memory bank Example ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The following XML code describes a physical design friendly memory-bank circuitry to configure the core logic of FPGA, as illustrated in :numref:`fig_memory_bank`. It will use the circuit model defined in :numref:`fig_sram_blwl`. +The BL and WL protocols can be customized through the XML syntax ``bl`` and ``wl``. + +.. note:: If not specified, the BL/WL protocols will use decoders. + .. code-block:: xml - + + + + +.. option:: protocol="decoder|flatten" + + - ``decoder``: BLs or WLs are controlled by decoders with address lines. For BLs, the decoder includes an enable signal as well as a data input signal. This is the default option if not specified. + - ``flatten``: BLs or WLs are directly available at the FPGA fabric. In this way, all the configurable memorys on the same WL can be written through the BL signals in one clock cycle + .. note:: Memory-bank decoders does require a memory cell to have - two outputs (one regular and another inverted) From b0a97a7052f0c85e66d541f8ca465071c158f0d8 Mon Sep 17 00:00:00 2001 From: tangxifan Date: Mon, 27 Sep 2021 10:24:04 -0700 Subject: [PATCH 28/28] [Doc] Update doc about WLR usage for QL memory bank --- docs/source/manual/arch_lang/config_protocol.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/source/manual/arch_lang/config_protocol.rst b/docs/source/manual/arch_lang/config_protocol.rst index 560dc77fa..04b47d638 100644 --- a/docs/source/manual/arch_lang/config_protocol.rst +++ b/docs/source/manual/arch_lang/config_protocol.rst @@ -177,6 +177,7 @@ The BL and WL protocols can be customized through the XML syntax ``bl`` and ``wl - two outputs (one regular and another inverted) - a Bit-Line input to load the data - a Word-Line input to enable data write + - (optional) a Word-Line read input to enabe data readback .. warning:: Please do NOT add inverted Bit-Line and Word-Line inputs. It is not supported yet!