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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Produced by OmniGraffle 7.18.1\n2021-01-05 01:03:21 +0000 + + regular + + Layer 1 + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + + + + Q + + + + + QN + + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + + + + Q + + + + + QN + + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + + + + Q + + + + + QN + + + + + + + + + + + + + + + + + + + + + CLK + + + + + CCFF_HEAD + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + + + + Q + + + + + QN + + + + + + + + + + + + + + + + + + + + + CCFF_TAIL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + mem_out[0] + + + + + mem_outb[0] + + + + + mem_out[1] + + + + + mem_outb[1] + + + + + mem_out[2] + + + + + mem_outb[2] + + + + + mem_out[n] + + + + + mem_outb[n] + + + + + + + + Configurable Circuits + + + + + Configuration Chain + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Produced by OmniGraffle 7.18.1\n2021-01-05 01:03:21 +0000 + + config_enable + + Layer 1 + + + + + + + + + CLK + + + + + CCFF_HEAD + + + + + + + + + + + + + + + + + + + + + + CCFF_TAIL + + + + + + + + + + + mem_out[0] + + + + + mem_outb[0] + + + + + mem_out[1] + + + + + mem_outb[1] + + + + + mem_out[2] + + + + + mem_outb[2] + + + + + mem_out[n] + + + + + mem_outb[n] + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + SCAN_Q + + + + + QN + + + + + Q + + + + + + + + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + SCAN_Q + + + + + QN + + + + + Q + + + + + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + SCAN_Q + + + + + QN + + + + + Q + + + + + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + SCAN_Q + + + + + QN + + + + + Q + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CONFIG_EN + + + + + CFG_EN + + + + + CONFIG_EN + + + + + + + + + + + CONFIG_EN + + + + + + + + CONFIG_EN + + + + + + + + + + + + + + + + + + + + + + + + + + Configurable Circuits + + + + + Configuration Chain + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Produced by OmniGraffle 7.18.1\n2021-01-05 01:03:21 +0000 + + scan_capable + + Layer 1 + + + + + + + + + CLK + + + + + CCFF_HEAD + + + + + + + + + + + + + + + + + + + + + + CCFF_TAIL + + + + + + + + + + + mem_out[0] + + + + + mem_outb[0] + + + + + mem_out[1] + + + + + mem_outb[1] + + + + + mem_out[2] + + + + + mem_outb[2] + + + + + mem_out[n] + + + + + mem_outb[n] + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + SCAN_Q + + + + + QN + + + + + Q + + + + + + + + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + SCAN_Q + + + + + QN + + + + + Q + + + + + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + SCAN_Q + + + + + QN + + + + + Q + + + + + + + + + + + + CCFF + + + + + D + + + + + CLK + + + + + + + + + + + + + + + + + + SCAN_Q + + + + + QN + + + + + Q + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + CONFIG_EN + + + + + CFG_EN + + + + + CONFIG_EN + + + + + + + + + + + CONFIG_EN + + + + + + + + CONFIG_EN + + + + + + + + + + + + + + + + + + + + + + + + + + Configurable Circuits + + + + + Configuration Chain + + + + + SI + + + + + + + + + + + + + + + SI + + + + + + + + + + + + SI + + + + + + + + + + + + SI + + + + + + + + + + + + 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=