diff --git a/docs/source/manual/file_formats/fabric_key.rst b/docs/source/manual/file_formats/fabric_key.rst
index f87cf1b2e..185e1b40a 100644
--- a/docs/source/manual/file_formats/fabric_key.rst
+++ b/docs/source/manual/file_formats/fabric_key.rst
@@ -62,6 +62,14 @@ Each configurable block is defined as a key. There are two ways to define a key,
- ``alias`` indicates the instance name of the configurable memory block in the top-level FPGA fabric. If a valid alias is specified, the ``name`` and ``value`` are not required.
+ - ``column`` indicates the relative x coordinate for a configurable memory in a configurable region at the top-level FPGA fabric. This is required when the memory bank protocol is selection.
+
+ .. note:: The configurable memory blocks in the same column will share the same Bit Line (BL) bus
+
+ - ``row`` indicates the relative y coordinate for a configurable memory in a configurable region at the top-level FPGA fabric. This is required when the memory bank protocol is selection.
+
+ .. note:: The configurable memory blocks in the same row will share the same Word Line (WL) bus
+
.. warning:: For fast loading of fabric key, strongly recommend to use pairs ``name`` and ``alias`` or ``name`` and ``value`` in the fabric key file. Using only ``alias`` may cause long parsing time for fabric key.
The following is an example of a fabric key generate by OpenFPGA for a 2 :math:`\times` 2 FPGA.
@@ -149,3 +157,46 @@ This key contains only ``name`` and ``value`` which is fast to parse.
+
+The following shows another example of a fabric key generate by OpenFPGA for a 2 :math:`\times` 2 FPGA using memory bank.
+This key contains only ``name``, ``value``, ``row`` and ``column``.
+
+.. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/libopenfpga/libfabrickey/src/fabric_key.cpp b/libopenfpga/libfabrickey/src/fabric_key.cpp
index dfe445c75..d15c86e56 100644
--- a/libopenfpga/libfabrickey/src/fabric_key.cpp
+++ b/libopenfpga/libfabrickey/src/fabric_key.cpp
@@ -54,6 +54,12 @@ std::string FabricKey::key_alias(const FabricKeyId& key_id) const {
return key_alias_[key_id];
}
+vtr::Point FabricKey::key_coordinate(const FabricKeyId& key_id) const {
+ /* validate the key_id */
+ VTR_ASSERT(valid_key_id(key_id));
+ return key_coordinates_[key_id];
+}
+
bool FabricKey::empty() const {
return 0 == key_ids_.size();
}
@@ -124,6 +130,7 @@ void FabricKey::reserve_keys(const size_t& num_keys) {
key_values_.reserve(num_keys);
key_regions_.reserve(num_keys);
key_alias_.reserve(num_keys);
+ key_coordinates_.reserve(num_keys);
}
FabricKeyId FabricKey::create_key() {
@@ -134,6 +141,7 @@ FabricKeyId FabricKey::create_key() {
key_values_.emplace_back();
key_regions_.emplace_back(FabricRegionId::INVALID());
key_alias_.emplace_back();
+ key_coordinates_.emplace_back(vtr::Point(-1, -1));
return key;
}
@@ -162,6 +170,14 @@ void FabricKey::set_key_alias(const FabricKeyId& key_id,
key_alias_[key_id] = alias;
}
+void FabricKey::set_key_coordinate(const FabricKeyId& key_id,
+ const vtr::Point& coord) {
+ /* validate the key_id */
+ VTR_ASSERT(valid_key_id(key_id));
+
+ key_coordinates_[key_id] = coord;
+}
+
/************************************************************************
* Internal invalidators/validators
***********************************************************************/
@@ -173,3 +189,7 @@ bool FabricKey::valid_region_id(const FabricRegionId& region_id) const {
bool FabricKey::valid_key_id(const FabricKeyId& key_id) const {
return ( size_t(key_id) < key_ids_.size() ) && ( key_id == key_ids_[key_id] );
}
+
+bool FabricKey::valid_key_coordinate(const vtr::Point& coord) const {
+ return coord.x() > -1 && coord.y() > -1;
+}
diff --git a/libopenfpga/libfabrickey/src/fabric_key.h b/libopenfpga/libfabrickey/src/fabric_key.h
index 0ca1d252d..6e9025f9e 100644
--- a/libopenfpga/libfabrickey/src/fabric_key.h
+++ b/libopenfpga/libfabrickey/src/fabric_key.h
@@ -10,6 +10,7 @@
/* Headers from vtrutil library */
#include "vtr_vector.h"
+#include "vtr_geometry.h"
#include "fabric_key_fwd.h"
@@ -58,6 +59,9 @@ class FabricKey {
/* Access the alias of a key */
std::string key_alias(const FabricKeyId& key_id) const;
+ /* Access the coordinate of a key */
+ vtr::Point key_coordinate(const FabricKeyId& key_id) const;
+
/* Check if there are any keys */
bool empty() const;
@@ -93,9 +97,14 @@ class FabricKey {
void set_key_alias(const FabricKeyId& key_id,
const std::string& alias);
+ void set_key_coordinate(const FabricKeyId& key_id,
+ const vtr::Point& coord);
+
public: /* Public invalidators/validators */
bool valid_region_id(const FabricRegionId& region_id) const;
bool valid_key_id(const FabricKeyId& key_id) const;
+ /* Identify if key coordinate is acceptable to fabric key convention */
+ bool valid_key_coordinate(const vtr::Point& coord) const;
private: /* Internal data */
/* Unique ids for each region */
vtr::vector region_ids_;
@@ -112,6 +121,9 @@ class FabricKey {
/* Values for each key */
vtr::vector key_values_;
+ /* Values for each key */
+ vtr::vector> key_coordinates_;
+
/* Region for each key */
vtr::vector key_regions_;
diff --git a/libopenfpga/libfabrickey/src/read_xml_fabric_key.cpp b/libopenfpga/libfabrickey/src/read_xml_fabric_key.cpp
index 24e0d8255..1c42b07bb 100644
--- a/libopenfpga/libfabrickey/src/read_xml_fabric_key.cpp
+++ b/libopenfpga/libfabrickey/src/read_xml_fabric_key.cpp
@@ -60,6 +60,14 @@ void read_xml_region_key(pugi::xml_node& xml_component_key,
fabric_key.set_key_name(FabricKeyId(id), name);
fabric_key.set_key_value(FabricKeyId(id), value);
fabric_key.add_key_to_region(fabric_region, FabricKeyId(id));
+
+ /* Parse coordinates */
+ vtr::Point coord;
+ coord.set_x(get_attribute(xml_component_key, "column", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(-1));
+ coord.set_y(get_attribute(xml_component_key, "row", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(-1));
+ if (fabric_key.valid_key_coordinate(coord)) {
+ fabric_key.set_key_coordinate(FabricKeyId(id), coord);
+ }
}
/********************************************************************
diff --git a/libopenfpga/libfabrickey/src/write_xml_fabric_key.cpp b/libopenfpga/libfabrickey/src/write_xml_fabric_key.cpp
index ea12d75a1..aa38c8140 100644
--- a/libopenfpga/libfabrickey/src/write_xml_fabric_key.cpp
+++ b/libopenfpga/libfabrickey/src/write_xml_fabric_key.cpp
@@ -52,6 +52,12 @@ int write_xml_fabric_component_key(std::fstream& fp,
write_xml_attribute(fp, "alias", fabric_key.key_alias(component_key).c_str());
}
+ vtr::Point coord = fabric_key.key_coordinate(component_key);
+ if (fabric_key.valid_key_coordinate(coord)) {
+ write_xml_attribute(fp, "column", coord.x());
+ write_xml_attribute(fp, "row", coord.y());
+ }
+
fp << "/>" << "\n";
return 0;
diff --git a/openfpga/src/fabric/build_top_module_memory.cpp b/openfpga/src/fabric/build_top_module_memory.cpp
index c9ee2b722..ca78f8e88 100644
--- a/openfpga/src/fabric/build_top_module_memory.cpp
+++ b/openfpga/src/fabric/build_top_module_memory.cpp
@@ -636,7 +636,8 @@ int load_top_module_memory_modules_from_fabric_key(ModuleManager& module_manager
/* Now we can add the child to configurable children of the top module */
module_manager.add_configurable_child(top_module,
instance_info.first,
- instance_info.second);
+ instance_info.second,
+ fabric_key.key_coordinate(key));
module_manager.add_configurable_child_to_region(top_module,
top_module_config_region,
instance_info.first,
diff --git a/openfpga/src/fabric/fabric_key_writer.cpp b/openfpga/src/fabric/fabric_key_writer.cpp
index 63202ea90..c099d5468 100644
--- a/openfpga/src/fabric/fabric_key_writer.cpp
+++ b/openfpga/src/fabric/fabric_key_writer.cpp
@@ -70,6 +70,7 @@ int write_fabric_key_to_xml_file(const ModuleManager& module_manager,
for (size_t ichild = 0; ichild < module_manager.region_configurable_children(top_module, config_region).size(); ++ichild) {
ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[ichild];
size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[ichild];
+ vtr::Point child_coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[ichild];
FabricKeyId key = fabric_key.create_key();
fabric_key.set_key_name(key, module_manager.module_name(child_module));
@@ -79,6 +80,9 @@ int write_fabric_key_to_xml_file(const ModuleManager& module_manager,
fabric_key.set_key_alias(key, module_manager.instance_name(top_module, child_module, child_instance));
}
+ /* Add key coordinate */
+ fabric_key.set_key_coordinate(key, child_coord);
+
/* Add keys to the region */
fabric_key.add_key_to_region(fabric_region, key);
}
diff --git a/openfpga_flow/fabric_keys/k4_N4_2x2_qlbank_sample_key.xml b/openfpga_flow/fabric_keys/k4_N4_2x2_qlbank_sample_key.xml
new file mode 100644
index 000000000..1de56c747
--- /dev/null
+++ b/openfpga_flow/fabric_keys/k4_N4_2x2_qlbank_sample_key.xml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/openfpga_flow/regression_test_scripts/basic_reg_test.sh b/openfpga_flow/regression_test_scripts/basic_reg_test.sh
index 531ba5f42..c9fd5e378 100755
--- a/openfpga_flow/regression_test_scripts/basic_reg_test.sh
+++ b/openfpga_flow/regression_test_scripts/basic_reg_test.sh
@@ -84,10 +84,11 @@ echo -e "Testing Secured FPGA fabrics";
run-task basic_tests/fabric_key/generate_vanilla_key --debug --show_thread_logs
run-task basic_tests/fabric_key/generate_multi_region_vanilla_key --debug --show_thread_logs
run-task basic_tests/fabric_key/generate_random_key --debug --show_thread_logs
+run-task basic_tests/fabric_key/generate_random_key_ql_memory_bank --debug --show_thread_logs
run-task basic_tests/fabric_key/load_external_key --debug --show_thread_logs
run-task basic_tests/fabric_key/load_external_key_cc_fpga --debug --show_thread_logs
run-task basic_tests/fabric_key/load_external_key_multi_region_cc_fpga --debug --show_thread_logs
-
+run-task basic_tests/fabric_key/load_external_key_qlbank_fpga --debug --show_thread_logs
echo -e "Testing K4 series FPGA";
echo -e "Testing K4N4 with facturable LUTs";
diff --git a/openfpga_flow/tasks/basic_tests/fabric_key/generate_random_key_ql_memory_bank/config/task.conf b/openfpga_flow/tasks/basic_tests/fabric_key/generate_random_key_ql_memory_bank/config/task.conf
new file mode 100644
index 000000000..f7f308a77
--- /dev/null
+++ b/openfpga_flow/tasks/basic_tests/fabric_key/generate_random_key_ql_memory_bank/config/task.conf
@@ -0,0 +1,36 @@
+# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
+# 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=vpr_blif
+
+[OpenFPGA_SHELL]
+openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/generate_secure_fabric_example_script.openfpga
+openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbank_openfpga.xml
+openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
+
+[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.blif
+
+[SYNTHESIS_PARAM]
+bench0_top = and2
+bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.act
+bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
+bench0_chan_width = 300
+
+[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
+end_flow_with_test=
diff --git a/openfpga_flow/tasks/basic_tests/fabric_key/load_external_key_qlbank_fpga/config/task.conf b/openfpga_flow/tasks/basic_tests/fabric_key/load_external_key_qlbank_fpga/config/task.conf
new file mode 100644
index 000000000..314c9c544
--- /dev/null
+++ b/openfpga_flow/tasks/basic_tests/fabric_key/load_external_key_qlbank_fpga/config/task.conf
@@ -0,0 +1,39 @@
+# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
+# 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=vpr_blif
+
+[OpenFPGA_SHELL]
+openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/generate_secure_fabric_from_key_example_script.openfpga
+openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbank_openfpga.xml
+openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
+external_fabric_key_file=${PATH:OPENFPGA_PATH}/openfpga_flow/fabric_keys/k4_N4_2x2_qlbank_sample_key.xml
+openfpga_vpr_device_layout=2x2
+
+[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.blif
+
+[SYNTHESIS_PARAM]
+bench0_top = and2
+bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.act
+bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
+bench0_chan_width = 300
+
+[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
+end_flow_with_test=
+#vpr_fpga_verilog_formal_verification_top_netlist=