diff --git a/.github/workflows/basic_reg_test.sh b/.github/workflows/basic_reg_test.sh
index 3e67023e3..1dbf7705c 100755
--- a/.github/workflows/basic_reg_test.sh
+++ b/.github/workflows/basic_reg_test.sh
@@ -14,6 +14,7 @@ python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/config
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/configuration_chain_use_set --debug --show_thread_logs
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/configuration_chain_use_setb --debug --show_thread_logs
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/configuration_chain_use_set_reset --debug --show_thread_logs
+python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/configuration_chain_config_enable_scff --debug --show_thread_logs
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/multi_region_configuration_chain --debug --show_thread_logs
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/fast_configuration_chain --debug --show_thread_logs
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/full_testbench/fast_configuration_chain_use_set --debug --show_thread_logs
diff --git a/docs/source/manual/arch_lang/circuit_model_examples.rst b/docs/source/manual/arch_lang/circuit_model_examples.rst
index 48b7fdf2f..1f4c0c1d3 100644
--- a/docs/source/manual/arch_lang/circuit_model_examples.rst
+++ b/docs/source/manual/arch_lang/circuit_model_examples.rst
@@ -979,18 +979,18 @@ This example shows:
.. _circuit_model_ccff_example:
-Configuration-chain Flip-flop
-`````````````````````````````
+Regular Configuration-chain Flip-flop
+`````````````````````````````````````
-:numref:`fig_ccff` illustrates an example of scan-chain flop-flop used to build a configuration chain.
+:numref:`fig_ccff_config_chain` illustrates an example of standard flip-flops used to build a configuration chain.
-.. _fig_ccff:
+.. _fig_ccff_config_chain:
-.. figure:: ./figures/scff.png
+.. figure:: ./figures/config_chain.svg
:scale: 50%
:alt: SCFF symbol
- An example of a Scan-Chain Flip-Flop.
+ An example of a Flip-Flop organized in a chain.
The code describing this FF is:
@@ -999,14 +999,94 @@ The code describing this FF is:
-
-
+
+
This example shows:
- A configuration-chain flip-flop which is defined in a Verilog netlist ``ccff.v`` and a SPICE netlist ``ccff.sp``
- The flip-flop has a global clock port, ``CK``, which will be wired a global programming clock
+.. note::
+ The output ports of the configuration flip-flop must follow a fixed sequence in definition:
+ - The first output port **MUST** be the data output port, e.g., ``Q``.
+ - The second output port **MUST** be the **inverted** data output port, e.g., ``QN``.
+
+Configuration-chain Flip-flop with Configure Enable Signals
+```````````````````````````````````````````````````````````
+
+Configuration chain could be built with flip-flops with outputs that are enabled by specific signals.
+Consider the example in :numref:`fig_ccff_config_chain_config_enable`, the flip-flop has
+
+- a configure enable signal ``CFG_EN`` to release the data output ``Q`` and ``QN``
+- a pair of data outputs ``Q`` and ``QN`` which are controlled by the configure enable signal ``CFG_EN``
+- a regular data output ``SCAN_Q`` which outputs registered data
+
+.. _fig_ccff_config_chain_config_enable:
+
+.. figure:: ./figures/config_chain_config_enable.svg
+ :scale: 50%
+ :alt: SCFF symbol
+
+ An example of a Flip-Flop with config enable feature organized in a chain.
+
+The code describing this FF is:
+
+.. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+.. note::
+ The output ports of the configuration flip-flop must follow a fixed sequence in definition:
+ - The first output port **MUST** be the regular data output port, e.g., ``SCAN_Q``.
+ - The second output port **MUST** be the **inverted** data output port which is activated by the configure enable signal, e.g., ``QN``.
+ - The second output port **MUST** be the data output port which is activated by the configure enable signal, e.g., ``Q``.
+
+Configuration-chain Flip-flop with Scan Input
+`````````````````````````````````````````````
+
+Configuration chain could be built with flip-flops with a scan chain input .
+Consider the example in :numref:`fig_ccff_config_chain_scan_capable`, the flip-flop has
+
+- an additional input ``SI`` to enable scan-chain capabaility
+- a configure enable signal ``CFG_EN`` to release the data output ``Q`` and ``QN``
+- a pair of data outputs ``Q`` and ``QN`` which are controlled by the configure enable signal ``CFG_EN``
+- a regular data output ``SCAN_Q`` which outputs registered data
+
+.. _fig_ccff_config_chain_scan_capable:
+
+.. figure:: ./figures/config_chain_scan_capable.svg
+ :scale: 50%
+ :alt: SCFF symbol
+
+ An example of a Flip-Flop with scan input organized in a chain.
+
+The code describing this FF is:
+
+.. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+
+.. note::
+ The input ports of the configuration flip-flop must follow a fixed sequence in definition:
+ - The first input port **MUST** be the regular data input port, e.g., ``D``.
+ - The second input port **MUST** be the scan input port, e.g., ``SI``.
+
Hard Logics
~~~~~~~~~~~
diff --git a/docs/source/manual/arch_lang/figures/config_chain.svg b/docs/source/manual/arch_lang/figures/config_chain.svg
new file mode 100644
index 000000000..d7e1ad8fc
--- /dev/null
+++ b/docs/source/manual/arch_lang/figures/config_chain.svg
@@ -0,0 +1,375 @@
+
+
+
diff --git a/docs/source/manual/arch_lang/figures/config_chain_config_enable.svg b/docs/source/manual/arch_lang/figures/config_chain_config_enable.svg
new file mode 100644
index 000000000..4df2c7854
--- /dev/null
+++ b/docs/source/manual/arch_lang/figures/config_chain_config_enable.svg
@@ -0,0 +1,411 @@
+
+
+
diff --git a/docs/source/manual/arch_lang/figures/config_chain_scan_capable.svg b/docs/source/manual/arch_lang/figures/config_chain_scan_capable.svg
new file mode 100644
index 000000000..68a30d37d
--- /dev/null
+++ b/docs/source/manual/arch_lang/figures/config_chain_scan_capable.svg
@@ -0,0 +1,462 @@
+
+
+
diff --git a/docs/source/manual/arch_lang/figures/scff.png b/docs/source/manual/arch_lang/figures/scff.png
deleted file mode 100644
index db0bf66dd..000000000
Binary files a/docs/source/manual/arch_lang/figures/scff.png and /dev/null differ
diff --git a/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp b/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp
index d7b19f41a..689d1af6f 100644
--- a/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp
+++ b/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp
@@ -290,17 +290,35 @@ size_t check_ccff_circuit_model_ports(const CircuitLibrary& circuit_lib,
VTR_ASSERT(CIRCUIT_MODEL_CCFF == circuit_lib.model_type(circuit_model));
/* Check if we have D, Set and Reset */
+ /* We can have either 1 input which is D or 2 inputs which are D and scan input */
+ size_t num_input_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true).size();
+ if ((1 != num_input_ports) && (2 != num_input_ports)) {
+ VTR_LOG_ERROR("Configuration flip-flop '%s' must have either 1 or 2 %s ports!\n\tAmong which:\n\t\tthe first input is a regular input (e.g., D)\n\t\tand the other could be scan-chain input (e.g., SI)\n",
+ circuit_lib.model_name(circuit_model).c_str(),
+ CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(CIRCUIT_MODEL_PORT_INPUT)]);
+ num_err++;
+ }
+
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
CIRCUIT_MODEL_PORT_INPUT,
- 1, 1, false);
+ num_input_ports, 1, false);
/* Check if we have a clock */
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
CIRCUIT_MODEL_PORT_CLOCK,
1, 1, true);
- /* Check if we have 1 or 2 outputs */
+ /* Check if we have 1 or 2 or 3 outputs */
size_t num_output_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, true).size();
+ if ((1 != num_output_ports)
+ && (2 != num_output_ports)
+ && (3 != num_output_ports)) {
+ VTR_LOG_ERROR("Configuration flip-flop '%s' must have either 1 or 2 or 3 %s ports!\n\tAmong which:\n\t\tthe first port is the manadatory regular data output (e.g., Q) and \n\t\tthe second port could be the inverted data output which can optionally be enabled by configure-enable signal (e.g., QN or cgf_en_QN) and \n\t\tthe third port could be the data output which can optionally be enabled by configure-enable signal (e.g., cgf_en_Q)\n",
+ circuit_lib.model_name(circuit_model).c_str(),
+ CIRCUIT_MODEL_PORT_TYPE_STRING[size_t(CIRCUIT_MODEL_PORT_OUTPUT)]);
+ num_err++;
+ }
+
num_err += check_one_circuit_model_port_type_and_size_required(circuit_lib, circuit_model,
CIRCUIT_MODEL_PORT_OUTPUT,
num_output_ports, 1, false);
diff --git a/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h b/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h
index 3f27c6966..2f9bae817 100644
--- a/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h
+++ b/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h
@@ -13,7 +13,10 @@ namespace openfpga {
/* Top-level module name */
constexpr char* FPGA_TOP_MODULE_NAME = "fpga_top";
+constexpr char* CONFIGURABLE_MEMORY_CHAIN_IN_NAME = "ccff_head";
+constexpr char* CONFIGURABLE_MEMORY_CHAIN_OUT_NAME = "ccff_tail";
constexpr char* CONFIGURABLE_MEMORY_DATA_OUT_NAME = "mem_out";
+constexpr char* CONFIGURABLE_MEMORY_INVERTED_DATA_OUT_NAME = "mem_outb";
/* IO PORT */
/* Prefix of global input, output and inout ports of FPGA fabric */
diff --git a/openfpga/src/base/openfpga_naming.cpp b/openfpga/src/base/openfpga_naming.cpp
index d2e41f549..192015ddf 100644
--- a/openfpga/src/base/openfpga_naming.cpp
+++ b/openfpga/src/base/openfpga_naming.cpp
@@ -708,7 +708,7 @@ std::string generate_formal_verification_sram_port_name(const CircuitLibrary& ci
* TODO: This could be replaced as a constexpr string
*********************************************************************/
std::string generate_configuration_chain_head_name() {
- return std::string("ccff_head");
+ return std::string(CONFIGURABLE_MEMORY_CHAIN_IN_NAME);
}
/*********************************************************************
@@ -716,7 +716,7 @@ std::string generate_configuration_chain_head_name() {
* TODO: This could be replaced as a constexpr string
*********************************************************************/
std::string generate_configuration_chain_tail_name() {
- return std::string("ccff_tail");
+ return std::string(CONFIGURABLE_MEMORY_CHAIN_OUT_NAME);
}
/*********************************************************************
@@ -732,7 +732,7 @@ std::string generate_configurable_memory_data_out_name() {
* TODO: This could be replaced as a constexpr string
*********************************************************************/
std::string generate_configurable_memory_inverted_data_out_name() {
- return std::string("mem_outb");
+ return std::string(CONFIGURABLE_MEMORY_INVERTED_DATA_OUT_NAME);
}
/*********************************************************************
diff --git a/openfpga/src/fabric/build_memory_modules.cpp b/openfpga/src/fabric/build_memory_modules.cpp
index 32d1c93b2..970ef8a95 100644
--- a/openfpga/src/fabric/build_memory_modules.cpp
+++ b/openfpga/src/fabric/build_memory_modules.cpp
@@ -77,8 +77,6 @@ void add_module_input_nets_to_mem_modules(ModuleManager& module_manager,
* j-th pin of output port of the i-th child module is wired to the j + i*W -th
* pin of output port of the memory module, where W is the size of port
* 3. It assumes fixed port name for output ports
- *
- * We cache the module nets that have been created because they will be used later
********************************************************************/
static
std::vector add_module_output_nets_to_chain_mem_modules(ModuleManager& module_manager,
@@ -165,15 +163,11 @@ void add_module_output_nets_to_mem_modules(ModuleManager& module_manager,
* add_module_nets_cmos_memory_chain_config_bus() !!!
*********************************************************************/
static
-void add_module_nets_to_cmos_memory_chain_module(ModuleManager& module_manager,
- const ModuleId& parent_module,
- const std::vector& output_nets,
- const CircuitLibrary& circuit_lib,
- const CircuitPortId& model_input_port,
- const CircuitPortId& model_output_port) {
- /* Counter for the nets */
- size_t net_counter = 0;
-
+void add_module_nets_to_cmos_memory_config_chain_module(ModuleManager& module_manager,
+ const ModuleId& parent_module,
+ const CircuitLibrary& circuit_lib,
+ const CircuitPortId& model_input_port,
+ const CircuitPortId& model_output_port) {
for (size_t mem_index = 0; mem_index < module_manager.configurable_children(parent_module).size(); ++mem_index) {
ModuleId net_src_module_id;
size_t net_src_instance_id;
@@ -219,21 +213,9 @@ void add_module_nets_to_cmos_memory_chain_module(ModuleManager& module_manager,
/* Create a net for each pin */
for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) {
/* Create a net and add source and sink to it */
- ModuleNetId net;
- if (0 == mem_index) {
- net = module_manager.create_module_net(parent_module);
- } else {
- net = output_nets[net_counter];
- }
- /* Add net source */
- module_manager.add_module_net_source(parent_module, net, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]);
+ ModuleNetId net = create_module_source_pin_net(module_manager, parent_module, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]);
/* Add net sink */
module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]);
-
- /* Update net counter */
- if (0 < mem_index) {
- net_counter++;
- }
}
}
@@ -263,17 +245,90 @@ void add_module_nets_to_cmos_memory_chain_module(ModuleManager& module_manager,
/* Create a net for each pin */
for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) {
/* Create a net and add source and sink to it */
- ModuleNetId net = output_nets[net_counter];
- /* Add net source */
- module_manager.add_module_net_source(parent_module, net, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]);
+ ModuleNetId net = create_module_source_pin_net(module_manager, parent_module, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]);
/* Add net sink */
module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]);
-
- /* Update net counter */
- net_counter++;
}
+}
- VTR_ASSERT(net_counter == output_nets.size());
+/********************************************************************
+ * Connect the scan input of all the memory modules
+ * under the parent module in a chain
+ *
+ * +--------+ +--------+ +--------+
+ * ccff_head --->| Memory |--->| Memory |--->... --->| Memory |
+ * | Module | | Module | | Module |
+ * | [0] | | [1] | | [N-1] |
+ * +--------+ +--------+ +--------+
+ * For the 1st memory module:
+ * net source is the configuration chain head of the primitive module
+ * net sink is the scan input of the next memory module
+ *
+ * For the rest of memory modules:
+ * net source is the configuration chain tail of the previous memory module
+ * net sink is the scan input of the next memory module
+ *
+ * Note that:
+ * This function is designed for memory modules ONLY!
+ * Do not use it to replace the
+ * add_module_nets_cmos_memory_chain_config_bus() !!!
+ *********************************************************************/
+static
+void add_module_nets_to_cmos_memory_scan_chain_module(ModuleManager& module_manager,
+ const ModuleId& parent_module,
+ const CircuitLibrary& circuit_lib,
+ const CircuitPortId& model_input_port,
+ const CircuitPortId& model_output_port) {
+ for (size_t mem_index = 0; mem_index < module_manager.configurable_children(parent_module).size(); ++mem_index) {
+ ModuleId net_src_module_id;
+ size_t net_src_instance_id;
+ ModulePortId net_src_port_id;
+
+ ModuleId net_sink_module_id;
+ size_t net_sink_instance_id;
+ ModulePortId net_sink_port_id;
+
+ if (0 == mem_index) {
+ /* Find the port name of configuration chain head */
+ std::string src_port_name = generate_configuration_chain_head_name();
+ net_src_module_id = parent_module;
+ net_src_instance_id = 0;
+ net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name);
+
+ /* Find the port name of next memory module */
+ std::string sink_port_name = circuit_lib.port_prefix(model_input_port);
+ net_sink_module_id = module_manager.configurable_children(parent_module)[mem_index];
+ net_sink_instance_id = module_manager.configurable_child_instances(parent_module)[mem_index];
+ net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name);
+ } else {
+ /* Find the port name of previous memory module */
+ std::string src_port_name = circuit_lib.port_prefix(model_output_port);
+ net_src_module_id = module_manager.configurable_children(parent_module)[mem_index - 1];
+ net_src_instance_id = module_manager.configurable_child_instances(parent_module)[mem_index - 1];
+ net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name);
+
+ /* Find the port name of next memory module */
+ std::string sink_port_name = circuit_lib.port_prefix(model_input_port);
+ net_sink_module_id = module_manager.configurable_children(parent_module)[mem_index];
+ net_sink_instance_id = module_manager.configurable_child_instances(parent_module)[mem_index];
+ net_sink_port_id = module_manager.find_module_port(net_sink_module_id, sink_port_name);
+ }
+
+ /* Get the pin id for source port */
+ BasicPort net_src_port = module_manager.module_port(net_src_module_id, net_src_port_id);
+ /* Get the pin id for sink port */
+ BasicPort net_sink_port = module_manager.module_port(net_sink_module_id, net_sink_port_id);
+ /* Port sizes of source and sink should match */
+ VTR_ASSERT(net_src_port.get_width() == net_sink_port.get_width());
+
+ /* Create a net for each pin */
+ for (size_t pin_id = 0; pin_id < net_src_port.pins().size(); ++pin_id) {
+ /* Create a net and add source and sink to it */
+ ModuleNetId net = create_module_source_pin_net(module_manager, parent_module, net_src_module_id, net_src_instance_id, net_src_port_id, net_src_port.pins()[pin_id]);
+ /* Add net sink */
+ module_manager.add_module_net_sink(parent_module, net, net_sink_module_id, net_sink_instance_id, net_sink_port_id, net_sink_port.pins()[pin_id]);
+ }
+ }
}
/*********************************************************************
@@ -382,7 +437,7 @@ void build_memory_flatten_module(ModuleManager& module_manager,
* scan-chain--->| CCFF |--->| CCFF |--->... --->| CCFF |---->scan-chain
* input&clock | [0] | | [1] | | [N-1] | output
* +-------+ +-------+ +-------+
- * | | ... |
+ * | | ... | config-memory output
* v v v
* +-----------------------------------------+
* | Multiplexer Configuration port |
@@ -397,12 +452,15 @@ void build_memory_chain_module(ModuleManager& module_manager,
/* Get the input ports from the SRAM */
std::vector sram_input_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_INPUT, true);
- /* Should have only 1 input port */
- VTR_ASSERT( 1 == sram_input_ports.size() );
+ /* Should have only 1 or 2 input port */
+ VTR_ASSERT( (1 == sram_input_ports.size())
+ || (2 == sram_input_ports.size()) );
/* Get the output ports from the SRAM */
std::vector sram_output_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_OUTPUT, true);
- /* Should have only 1 or 2 output port */
- VTR_ASSERT( (1 == sram_output_ports.size()) || ( 2 == sram_output_ports.size()) );
+ /* Should have only 1 or 2 or 3 output port */
+ VTR_ASSERT( (1 == sram_output_ports.size())
+ || (2 == sram_output_ports.size())
+ || (3 == sram_output_ports.size()) );
/* Create a module and add to the module manager */
ModuleId mem_module = module_manager.add_module(module_name);
@@ -428,13 +486,27 @@ void build_memory_chain_module(ModuleManager& module_manager,
circuit_lib.port_size(sram_output_ports[0]));
module_manager.add_port(mem_module, chain_tail_port, ModuleManager::MODULE_OUTPUT_PORT);
- /* Add each output port: port width should match the number of memories */
- for (size_t iport = 0; iport < sram_output_ports.size(); ++iport) {
+ /* There could be 3 conditions w.r.t. the number of output ports:
+ * - Only one output port is defined. In this case, the 1st port is the Q
+ * In such case, only Q will be considered as data output ports
+ * - Two output port is defined. In this case, the 1st port is the Q while the 2nd port is the QN
+ * In such case, both Q and QN will be considered as data output ports
+ * - Three output port is defined.
+ * In this case:
+ * - the 1st port is the Q (the chain output)
+ * - the 2nd port is the QN (the inverted data output)
+ * - the 3nd port is the configure-enabled Q
+ * In such case, configure-enabled Q and QN will be considered as data output ports
+ */
+ size_t num_data_output_ports = sram_output_ports.size();
+ if (3 == sram_output_ports.size()) {
+ num_data_output_ports = 2;
+ }
+ for (size_t iport = 0; iport < num_data_output_ports; ++iport) {
std::string port_name;
if (0 == iport) {
port_name = generate_configurable_memory_data_out_name();
- } else {
- VTR_ASSERT( 1 == iport);
+ } else if (1 == iport) {
port_name = generate_configurable_memory_inverted_data_out_name();
}
BasicPort output_port(port_name, num_mems);
@@ -444,9 +516,6 @@ void build_memory_chain_module(ModuleManager& module_manager,
/* Find the sram module in the module manager */
ModuleId sram_mem_module = module_manager.find_module(circuit_lib.model_name(sram_model));
- /* Cache the output nets for non-inverted data output */
- std::vector mem_output_nets;
-
/* Instanciate each submodule */
for (size_t i = 0; i < num_mems; ++i) {
size_t sram_mem_instance = module_manager.num_instance(mem_module, sram_mem_module);
@@ -454,7 +523,7 @@ void build_memory_chain_module(ModuleManager& module_manager,
module_manager.add_configurable_child(mem_module, sram_mem_module, sram_mem_instance);
/* Build module nets to wire outputs of sram modules to outputs of memory module */
- for (size_t iport = 0; iport < sram_output_ports.size(); ++iport) {
+ for (size_t iport = 0; iport < num_data_output_ports; ++iport) {
std::string port_name;
if (0 == iport) {
port_name = generate_configurable_memory_data_out_name();
@@ -462,20 +531,32 @@ void build_memory_chain_module(ModuleManager& module_manager,
VTR_ASSERT( 1 == iport);
port_name = generate_configurable_memory_inverted_data_out_name();
}
+ /* Find the proper data output port
+ * The exception is when there are 3 output ports defined
+ * The 3rd port is the regular data output port to be used
+ */
+ CircuitPortId data_output_port_to_connect = sram_output_ports[iport];
+ if ((3 == sram_output_ports.size()) && (0 == iport)) {
+ data_output_port_to_connect = sram_output_ports.back();
+ }
+
std::vector output_nets = add_module_output_nets_to_chain_mem_modules(module_manager, mem_module,
- port_name, circuit_lib, sram_output_ports[iport],
+ port_name, circuit_lib, data_output_port_to_connect,
sram_mem_module, i, sram_mem_instance);
- /* Cache only for regular data outputs */
- if (0 == iport) {
- mem_output_nets.insert(mem_output_nets.end(), output_nets.begin(), output_nets.end());
- }
}
}
/* Build module nets to wire the configuration chain */
- add_module_nets_to_cmos_memory_chain_module(module_manager, mem_module, mem_output_nets,
- circuit_lib, sram_input_ports[0], sram_output_ports[0]);
+ add_module_nets_to_cmos_memory_config_chain_module(module_manager, mem_module,
+ circuit_lib, sram_input_ports[0], sram_output_ports[0]);
+ /* If there is a second input defined,
+ * add nets to short wire the 2nd inputs to the first inputs
+ */
+ if (2 == sram_input_ports.size()) {
+ add_module_nets_to_cmos_memory_scan_chain_module(module_manager, mem_module,
+ circuit_lib, sram_input_ports[1], sram_output_ports[0]);
+ }
/* Add global ports to the pb_module:
* This is a much easier job after adding sub modules (instances),
diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_cc_cfgscff_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_cc_cfgscff_openfpga.xml
new file mode 100644
index 000000000..e0fd1f9bb
--- /dev/null
+++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_cc_cfgscff_openfpga.xml
@@ -0,0 +1,194 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 10e-12
+
+
+ 10e-12
+
+
+
+
+
+
+
+
+ 10e-12
+
+
+ 10e-12
+
+
+
+
+
+
+
+
+ 10e-12
+
+
+ 10e-12
+
+
+
+
+
+
+
+
+
+
+
+
+ 10e-12 5e-12 5e-12
+
+
+ 10e-12 5e-12 5e-12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/openfpga_flow/openfpga_cell_library/verilog/dff.v b/openfpga_flow/openfpga_cell_library/verilog/dff.v
index e54950827..a0548c54c 100644
--- a/openfpga_flow/openfpga_cell_library/verilog/dff.v
+++ b/openfpga_flow/openfpga_cell_library/verilog/dff.v
@@ -397,3 +397,50 @@ end
assign Q = q_reg;
endmodule //End Of Module
+
+//-----------------------------------------------------
+// Function : D-type flip-flop with
+// - asynchronous active high reset
+// - scan-chain input
+// - a scan-chain enable
+// - a configure enable, when enabled the registered output will
+// be released to the Q
+//-----------------------------------------------------
+module CFGSDFFR (
+ input RST, // Reset input
+ input CK, // Clock Input
+ input SE, // Scan-chain Enable
+ input D, // Data Input
+ input SI, // Scan-chain input
+ input CFGE, // Configure enable
+ output Q, // Regular Q output
+ output CFGQ, // Data Q output which is released when configure enable is activated
+ output CFGQN // Data Qb output which is released when configure enable is activated
+);
+//------------Internal Variables--------
+reg q_reg;
+wire QN;
+
+//-------------Code Starts Here---------
+always @ ( posedge CK or posedge RST)
+if (RST) begin
+ q_reg <= 1'b0;
+end else if (SE) begin
+ q_reg <= SI;
+end else begin
+ q_reg <= D;
+end
+
+assign CFGQ = CFGE ? Q : 1'b0;
+assign CFGQN = CFGE ? QN : 1'b1;
+
+`ifndef ENABLE_FORMAL_VERIFICATION
+// Wire q_reg to Q
+ assign Q = q_reg;
+ assign QN = !Q;
+`else
+ assign Q = 1'bZ;
+ assign QN = !Q;
+`endif
+
+endmodule //End Of Module
diff --git a/openfpga_flow/tasks/basic_tests/full_testbench/configuration_chain_config_enable_scff/config/task.conf b/openfpga_flow/tasks/basic_tests/full_testbench/configuration_chain_config_enable_scff/config/task.conf
new file mode 100644
index 000000000..8fd922fd9
--- /dev/null
+++ b/openfpga_flow/tasks/basic_tests/full_testbench/configuration_chain_config_enable_scff/config/task.conf
@@ -0,0 +1,42 @@
+# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
+# 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 = 1*60
+fpga_flow=yosys_vpr
+
+[OpenFPGA_SHELL]
+openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/configuration_chain_example_script.openfpga
+openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_cc_cfgscff_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.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=