diff --git a/.github/workflows/basic_reg_test.sh b/.github/workflows/basic_reg_test.sh
index 02d5da8db..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
@@ -108,3 +109,6 @@ python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/tile_organization/til
echo -e "Testing global port definition from tiles";
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/global_tile_ports/global_tile_clock --debug --show_thread_logs
python3 openfpga_flow/scripts/run_fpga_task.py basic_tests/global_tile_ports/global_tile_reset --debug --show_thread_logs
+
+echo -e "Testing yosys flow using custom ys script for running quicklogic device";
+python3 openfpga_flow/scripts/run_fpga_task.py quicklogic_tests/flow_test --debug --show_thread_logs
diff --git a/.github/workflows/fpga_verilog_reg_test.sh b/.github/workflows/fpga_verilog_reg_test.sh
index a866b7bfc..4e01c1a0a 100755
--- a/.github/workflows/fpga_verilog_reg_test.sh
+++ b/.github/workflows/fpga_verilog_reg_test.sh
@@ -49,6 +49,9 @@ python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/io/embedded_io --deb
echo -e "Testing Verilog generation with SoC I/Os for an FPGA ";
python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/io/soc_io --debug --show_thread_logs
+echo -e "Testing Verilog generation with registerable I/Os for an FPGA ";
+python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/io/registerable_io --debug --show_thread_logs
+
echo -e "Testing Verilog generation with adder chain across an FPGA";
python3 openfpga_flow/scripts/run_fpga_task.py fpga_verilog/fabric_chain/adder_chain --debug --show_thread_logs
diff --git a/docs/source/manual/arch_lang/annotate_vpr_arch.rst b/docs/source/manual/arch_lang/annotate_vpr_arch.rst
index b5d8a93e5..14581f327 100644
--- a/docs/source/manual/arch_lang/annotate_vpr_arch.rst
+++ b/docs/source/manual/arch_lang/annotate_vpr_arch.rst
@@ -60,21 +60,14 @@ Here is an example:
.. code-block:: xml
-
+
+
+ ...
+
- ``name=""`` is the port name to appear in the top-level FPGA fabric.
-- ``tile_port=""`` is the port name of a physical tile, e.g., ``tile_port="clb.clk"``.
-
-.. note:: The port of physical tile must be a valid port of the physical definition in VPR architecture!
-
-.. note:: The linked port of physical tile must meet the following requirements:
-
- - If the ``global_port`` is set as clock through ``is_clock="true"``, the port of the physical tile must also be a clock port.
- - If not a clock, the port of the physical tile must be defined as non-clock global
- - The port of the physical tile should have zero connectivity (``Fc=0``) in VPR architecture
-
- ``is_clock=""`` define if the global port is a clock port at the top-level FPGA fabric. An operating clock port will be driven by proper signals in auto-generated testbenches.
- ``is_reset=""`` define if the global port is a reset port at the top-level FPGA fabric. An operating reset port will be driven by proper signals in testbenches.
@@ -87,6 +80,26 @@ Here is an example:
- ``default_val=""`` define if the default value for the global port when initialized in testbenches. Valid values are either ``0`` or ``1``. For example, the default value of an active-high reset pin is ``0``, while an active-low reset pin is ``1``.
+.. note:: A global port could be connected from different tiles by defining multiple lines under a global port!!!
+
+.. option::
+
+- ``name=""`` is the name of a physical tile, e.g., ``name="clb"``.
+
+- ``port=""`` is the port name of a physical tile, e.g., ``port="clk[0:3]"``.
+
+- ``x=""`` is the x coordinate of a physical tile, e.g., ``x="1"``. If the x coordinate is set to ``-1``, it means all the valid x coordinates of the selected physical tile in the FPGA device will be considered.
+
+- ``y=""`` is the y coordinate of a physical tile, e.g., ``y="1"``. If the y coordinate is set to ``-1``, it means all the valid y coordinates of the selected physical tile in the FPGA device will be considered.
+
+.. note:: The port of physical tile must be a valid port of the physical definition in VPR architecture! If you define a multi-bit port, it must be explicitly defined in the port, e.g., clk[0:3], which must be in the range of the port definition in physical tiles of VPR architecture files!!!
+
+.. note:: The linked port of physical tile must meet the following requirements:
+
+ - If the ``global_port`` is set as clock through ``is_clock="true"``, the port of the physical tile must also be a clock port.
+ - If not a clock, the port of the physical tile must be defined as non-clock global
+ - The port of the physical tile should have zero connectivity (``Fc=0``) in VPR architecture
+
A more illustrative example:
:numref:`fig_global_tile_ports` illustrates the difference between the global ports defined through ``circuit_model`` and ``tile_annotation``.
@@ -114,7 +127,9 @@ When a global port, e.g., ``clk``, is defined in ``tile_annotation`` using the f
.. code-block:: xml
-
+
+
+
Clock port ``clk`` of each ``clb`` tile will be connected to a common clock port of the top module, while local clock network is customizable through VPR's architecture description language. For instance, the local clock network can be a programmable clock network.
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/libarchopenfpga/src/read_xml_tile_annotation.cpp b/libopenfpga/libarchopenfpga/src/read_xml_tile_annotation.cpp
index 28d2a6ab8..4f1a42745 100644
--- a/libopenfpga/libarchopenfpga/src/read_xml_tile_annotation.cpp
+++ b/libopenfpga/libarchopenfpga/src/read_xml_tile_annotation.cpp
@@ -30,25 +30,12 @@ static
void read_xml_tile_global_port_annotation(pugi::xml_node& xml_tile,
const pugiutil::loc_data& loc_data,
openfpga::TileAnnotation& tile_annotation) {
- /* We have two mandatory XML attributes
- * 1. name of the port
- * 2. name of the tile and ports in the format of .
+ /* We have mandatory XML attributes:
+ * - name of the port
*/
const std::string& name_attr = get_attribute(xml_tile, "name", loc_data).as_string();
- const std::string& tile_port_name_attr = get_attribute(xml_tile, "tile_port", loc_data).as_string();
- /* Extract the tile name */
- openfpga::StringToken tokenizer(tile_port_name_attr);
- std::vector tile_port_tokens = tokenizer.split('.');
- if (2 != tile_port_tokens.size()) {
- archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_tile),
- "Invalid tile_port attribute '%s'! Valid format is .\n",
- tile_port_name_attr.c_str());
- }
- /* Extract the tile port information */
- openfpga::PortParser tile_port_parser(tile_port_tokens[1]);
-
- TileGlobalPortId tile_global_port_id = tile_annotation.create_global_port(name_attr, tile_port_tokens[0], tile_port_parser.port());
+ TileGlobalPortId tile_global_port_id = tile_annotation.create_global_port(name_attr);
/* Report any duplicated port names */
if (TileGlobalPortId::INVALID() == tile_global_port_id) {
@@ -57,6 +44,39 @@ void read_xml_tile_global_port_annotation(pugi::xml_node& xml_tile,
name_attr.c_str());
}
+ /* Iterate over the children under this node,
+ * each child should be named after
+ */
+ for (pugi::xml_node xml_tile_port : xml_tile.children()) {
+ /* Error out if the XML child has an invalid name! */
+ if (xml_tile_port.name() != std::string("tile")) {
+ bad_tag(xml_tile_port, loc_data, xml_tile, {"tile"});
+ }
+ /* Parse the name of the tiles and ports */
+ const std::string& tile_name_attr = get_attribute(xml_tile_port, "name", loc_data).as_string();
+ const std::string& port_name_attr = get_attribute(xml_tile_port, "port", loc_data).as_string();
+
+ /* Extract the tile port information */
+ openfpga::PortParser tile_port_parser(port_name_attr);
+
+ /* Parse tile coordinates */
+ vtr::Point tile_coord(get_attribute(xml_tile_port, "x", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(-1),
+ get_attribute(xml_tile_port, "y", loc_data, pugiutil::ReqOpt::OPTIONAL).as_int(-1));
+
+ /* Add tile port information */
+ tile_annotation.add_global_port_tile_information(tile_global_port_id,
+ tile_name_attr,
+ tile_port_parser.port(),
+ tile_coord);
+ }
+
+ /* Check: Must have at least one global port tile information */
+ if (true == tile_annotation.global_port_tile_names(tile_global_port_id).empty()) {
+ archfpga_throw(loc_data.filename_c_str(), loc_data.line(xml_tile),
+ "Invalid tile annotation for global port '%s'! At least 1 tile port definition is expected!\n",
+ name_attr.c_str());
+ }
+
/* Get is_clock attributes */
tile_annotation.set_global_port_is_clock(tile_global_port_id, get_attribute(xml_tile, "is_clock", loc_data, pugiutil::ReqOpt::OPTIONAL).as_bool(false));
@@ -81,7 +101,7 @@ void read_xml_tile_global_port_annotation(pugi::xml_node& xml_tile,
* Top function to parse XML description about tile annotation
*******************************************************************/
openfpga::TileAnnotation read_xml_tile_annotations(pugi::xml_node& Node,
- const pugiutil::loc_data& loc_data) {
+ const pugiutil::loc_data& loc_data) {
openfpga::TileAnnotation tile_annotations;
/* Parse configuration protocol root node */
diff --git a/libopenfpga/libarchopenfpga/src/tile_annotation.cpp b/libopenfpga/libarchopenfpga/src/tile_annotation.cpp
index 5bef68a31..a1268aefa 100644
--- a/libopenfpga/libarchopenfpga/src/tile_annotation.cpp
+++ b/libopenfpga/libarchopenfpga/src/tile_annotation.cpp
@@ -30,16 +30,21 @@ std::string TileAnnotation::global_port_name(const TileGlobalPortId& global_port
return global_port_names_[global_port_id];
}
-std::string TileAnnotation::global_port_tile_name(const TileGlobalPortId& global_port_id) const {
+std::vector TileAnnotation::global_port_tile_names(const TileGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
return global_port_tile_names_[global_port_id];
}
-BasicPort TileAnnotation::global_port_tile_port(const TileGlobalPortId& global_port_id) const {
+std::vector TileAnnotation::global_port_tile_ports(const TileGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
return global_port_tile_ports_[global_port_id];
}
+std::vector> TileAnnotation::global_port_tile_coordinates(const TileGlobalPortId& global_port_id) const {
+ VTR_ASSERT(valid_global_port_id(global_port_id));
+ return global_port_tile_coordinates_[global_port_id];
+}
+
bool TileAnnotation::global_port_is_clock(const TileGlobalPortId& global_port_id) const {
VTR_ASSERT(valid_global_port_id(global_port_id));
return global_port_is_clock_[global_port_id];
@@ -63,9 +68,7 @@ size_t TileAnnotation::global_port_default_value(const TileGlobalPortId& global_
/************************************************************************
* Public Mutators
***********************************************************************/
-TileGlobalPortId TileAnnotation::create_global_port(const std::string& port_name,
- const std::string& tile_name,
- const BasicPort& tile_port) {
+TileGlobalPortId TileAnnotation::create_global_port(const std::string& port_name) {
/* Ensure that the name is unique */
std::map::iterator it = global_port_name2ids_.find(port_name);
if (it != global_port_name2ids_.end()) {
@@ -76,8 +79,9 @@ TileGlobalPortId TileAnnotation::create_global_port(const std::string& port_name
TileGlobalPortId port_id = TileGlobalPortId(global_port_ids_.size());
global_port_ids_.push_back(port_id);
global_port_names_.push_back(port_name);
- global_port_tile_names_.push_back(tile_name);
- global_port_tile_ports_.push_back(tile_port);
+ global_port_tile_names_.emplace_back();
+ global_port_tile_ports_.emplace_back();
+ global_port_tile_coordinates_.emplace_back();
global_port_is_clock_.push_back(false);
global_port_is_set_.push_back(false);
global_port_is_reset_.push_back(false);
@@ -89,6 +93,16 @@ TileGlobalPortId TileAnnotation::create_global_port(const std::string& port_name
return port_id;
}
+void TileAnnotation::add_global_port_tile_information(const TileGlobalPortId& global_port_id,
+ const std::string& tile_name,
+ const BasicPort& tile_port,
+ const vtr::Point& tile_coord) {
+ VTR_ASSERT(valid_global_port_id(global_port_id));
+ global_port_tile_names_[global_port_id].push_back(tile_name);
+ global_port_tile_ports_[global_port_id].push_back(tile_port);
+ global_port_tile_coordinates_[global_port_id].push_back(tile_coord);
+}
+
void TileAnnotation::set_global_port_is_clock(const TileGlobalPortId& global_port_id,
const bool& is_clock) {
VTR_ASSERT(valid_global_port_id(global_port_id));
diff --git a/libopenfpga/libarchopenfpga/src/tile_annotation.h b/libopenfpga/libarchopenfpga/src/tile_annotation.h
index b87ceb74a..1f863d1ac 100644
--- a/libopenfpga/libarchopenfpga/src/tile_annotation.h
+++ b/libopenfpga/libarchopenfpga/src/tile_annotation.h
@@ -9,6 +9,7 @@
#include
#include "vtr_vector.h"
+#include "vtr_geometry.h"
#include "openfpga_port.h"
@@ -39,8 +40,9 @@ class TileAnnotation {
global_port_range global_ports() const;
public: /* Public accessors */
std::string global_port_name(const TileGlobalPortId& global_port_id) const;
- std::string global_port_tile_name(const TileGlobalPortId& global_port_id) const;
- BasicPort global_port_tile_port(const TileGlobalPortId& global_port_id) const;
+ std::vector global_port_tile_names(const TileGlobalPortId& global_port_id) const;
+ std::vector global_port_tile_ports(const TileGlobalPortId& global_port_id) const;
+ std::vector> global_port_tile_coordinates(const TileGlobalPortId& global_port_id) const;
bool global_port_is_clock(const TileGlobalPortId& global_port_id) const;
bool global_port_is_set(const TileGlobalPortId& global_port_id) const;
bool global_port_is_reset(const TileGlobalPortId& global_port_id) const;
@@ -49,9 +51,12 @@ class TileAnnotation {
/* By default, we do not set it as a clock.
* Users should set it through the set_global_port_is_clock() function
*/
- TileGlobalPortId create_global_port(const std::string& port_name,
- const std::string& tile_name,
- const BasicPort& tile_port);
+ TileGlobalPortId create_global_port(const std::string& port_name);
+ /* Add tile port information */
+ void add_global_port_tile_information(const TileGlobalPortId& global_port_id,
+ const std::string& tile_name,
+ const BasicPort& tile_port,
+ const vtr::Point& tile_coord);
void set_global_port_is_clock(const TileGlobalPortId& global_port_id,
const bool& is_clock);
void set_global_port_is_set(const TileGlobalPortId& global_port_id,
@@ -70,8 +75,9 @@ class TileAnnotation {
/* Global port information for tiles */
vtr::vector global_port_ids_;
vtr::vector global_port_names_;
- vtr::vector global_port_tile_names_;
- vtr::vector global_port_tile_ports_;
+ vtr::vector> global_port_tile_names_;
+ vtr::vector>> global_port_tile_coordinates_;
+ vtr::vector> global_port_tile_ports_;
vtr::vector global_port_is_clock_;
vtr::vector global_port_is_reset_;
vtr::vector global_port_is_set_;
diff --git a/libopenfpga/libarchopenfpga/src/write_xml_tile_annotation.cpp b/libopenfpga/libarchopenfpga/src/write_xml_tile_annotation.cpp
index a3214d4df..69a568fc5 100644
--- a/libopenfpga/libarchopenfpga/src/write_xml_tile_annotation.cpp
+++ b/libopenfpga/libarchopenfpga/src/write_xml_tile_annotation.cpp
@@ -51,11 +51,6 @@ void write_xml_tile_annotation_global_port(std::fstream& fp,
write_xml_attribute(fp, "name", tile_annotation.global_port_name(global_port_id).c_str());
- std::string tile_port_attr = tile_annotation.global_port_tile_name(global_port_id)
- + "."
- + generate_tile_port_name(tile_annotation.global_port_tile_port(global_port_id));
- write_xml_attribute(fp, "tile_port", tile_port_attr.c_str());
-
write_xml_attribute(fp, "is_clock", tile_annotation.global_port_is_clock(global_port_id));
write_xml_attribute(fp, "is_set", tile_annotation.global_port_is_set(global_port_id));
@@ -64,7 +59,18 @@ void write_xml_tile_annotation_global_port(std::fstream& fp,
write_xml_attribute(fp, "default_value", tile_annotation.global_port_default_value(global_port_id));
- fp << "/>" << "\n";
+ fp << ">" << "\n";
+
+ for (size_t tile_info_id = 0; tile_info_id < tile_annotation.global_port_tile_names(global_port_id).size(); ++tile_info_id) {
+ fp << "\t\t\t" << "";
+ }
+
+ fp << "\t\t" << "";
}
/********************************************************************
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/src/fabric/build_top_module_connection.cpp b/openfpga/src/fabric/build_top_module_connection.cpp
index 8843f5210..354e785a2 100644
--- a/openfpga/src/fabric/build_top_module_connection.cpp
+++ b/openfpga/src/fabric/build_top_module_connection.cpp
@@ -695,33 +695,42 @@ void add_top_module_nets_connect_grids_and_gsbs(ModuleManager& module_manager,
* that are defined as global in tile annotation
*******************************************************************/
static
-void build_top_module_global_net_for_given_grid_module(ModuleManager& module_manager,
- const ModuleId& top_module,
- const ModulePortId& top_module_port,
- const TileAnnotation& tile_annotation,
- const TileGlobalPortId& tile_global_port,
- const DeviceGrid& grids,
- const vtr::Point& grid_coordinate,
- const e_side& border_side,
- const vtr::Matrix& grid_instance_ids) {
+int build_top_module_global_net_for_given_grid_module(ModuleManager& module_manager,
+ const ModuleId& top_module,
+ const ModulePortId& top_module_port,
+ const TileAnnotation& tile_annotation,
+ const TileGlobalPortId& tile_global_port,
+ const BasicPort& tile_port_to_connect,
+ const DeviceGrid& grids,
+ const vtr::Point& grid_coordinate,
+ const e_side& border_side,
+ const vtr::Matrix& grid_instance_ids) {
t_physical_tile_type_ptr physical_tile = grids[grid_coordinate.x()][grid_coordinate.y()].type;
- /* Ensure physical tile matches the global port definition */
- VTR_ASSERT(std::string(physical_tile->name) == tile_annotation.global_port_tile_name(tile_global_port));
/* Find the port of the grid module according to the tile annotation */
- int grid_pin_index = physical_tile->num_pins;
+ int grid_pin_start_index = physical_tile->num_pins;
for (const t_physical_tile_port& tile_port : physical_tile->ports) {
- if (std::string(tile_port.name) == tile_annotation.global_port_tile_port(tile_global_port).get_name()) {
+ if (std::string(tile_port.name) == tile_port_to_connect.get_name()) {
+ BasicPort ref_tile_port(tile_port.name, tile_port.num_pins);
/* Port size must match!!! */
- VTR_ASSERT(size_t(tile_port.num_pins) == tile_annotation.global_port_tile_port(tile_global_port).get_width());
- /* TODO: Should check there is only port matching!!! */
- grid_pin_index = tile_port.absolute_first_pin_index;
+ if (false == ref_tile_port.contained(tile_port_to_connect)) {
+ VTR_LOG_ERROR("Tile annotation '%s' port '%s[%lu:%lu]' is out of the range of physical tile port '%s[%lu:%lu]'!",
+ tile_annotation.global_port_name(tile_global_port).c_str(),
+ tile_port_to_connect.get_name().c_str(),
+ tile_port_to_connect.get_lsb(),
+ tile_port_to_connect.get_msb(),
+ ref_tile_port.get_name().c_str(),
+ ref_tile_port.get_lsb(),
+ ref_tile_port.get_msb());
+ return CMD_EXEC_FATAL_ERROR;
+ }
+ grid_pin_start_index = tile_port.absolute_first_pin_index;
break;
}
}
/* Ensure the pin index is valid */
- VTR_ASSERT(grid_pin_index < physical_tile->num_pins);
+ VTR_ASSERT(grid_pin_start_index < physical_tile->num_pins);
/* Find the module name for this type of grid */
std::string grid_module_name_prefix(GRID_MODULE_NAME_PREFIX);
@@ -730,23 +739,39 @@ void build_top_module_global_net_for_given_grid_module(ModuleManager& module_man
VTR_ASSERT(true == module_manager.valid_module_id(grid_module));
size_t grid_instance = grid_instance_ids[grid_coordinate.x()][grid_coordinate.y()];
- /* Find the module pin */
- size_t grid_pin_width = physical_tile->pin_width_offset[grid_pin_index];
- size_t grid_pin_height = physical_tile->pin_height_offset[grid_pin_index];
- std::vector pin_sides = find_physical_tile_pin_side(physical_tile, grid_pin_index, border_side);
- for (const e_side& pin_side : pin_sides) {
- std::string grid_port_name = generate_grid_port_name(grid_coordinate,
- grid_pin_width, grid_pin_height,
- pin_side,
- grid_pin_index, false);
- ModulePortId grid_port_id = module_manager.find_module_port(grid_module, grid_port_name);
- VTR_ASSERT(true == module_manager.valid_module_port_id(grid_module, grid_port_id));
+ VTR_ASSERT(1 == physical_tile->equivalent_sites.size());
- /* Build nets */
- add_module_bus_nets(module_manager, top_module,
- top_module, 0, top_module_port,
- grid_module, grid_instance, grid_port_id);
+ /* A tile may consist of multiple subtile, connect to all the pins from sub tiles */
+ for (int iz = 0; iz < physical_tile->capacity; ++iz) {
+ /* TODO: This should be replaced by using a pin mapping data structure from physical tile! */
+ int grid_pin_index = grid_pin_start_index + iz * physical_tile->equivalent_sites[0]->pb_type->num_pins;
+ /* Find the module pin */
+ size_t grid_pin_width = physical_tile->pin_width_offset[grid_pin_index];
+ size_t grid_pin_height = physical_tile->pin_height_offset[grid_pin_index];
+ std::vector pin_sides = find_physical_tile_pin_side(physical_tile, grid_pin_index, border_side);
+ for (const e_side& pin_side : pin_sides) {
+ std::string grid_port_name = generate_grid_port_name(grid_coordinate,
+ grid_pin_width, grid_pin_height,
+ pin_side,
+ grid_pin_index, false);
+ ModulePortId grid_port_id = module_manager.find_module_port(grid_module, grid_port_name);
+ VTR_ASSERT(true == module_manager.valid_module_port_id(grid_module, grid_port_id));
+
+ /* Build nets */
+ BasicPort src_port = module_manager.module_port(top_module, top_module_port);
+ for (size_t pin_id = 0; pin_id < tile_port_to_connect.pins().size(); ++pin_id) {
+ ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
+ top_module, 0,
+ top_module_port, src_port.pins()[pin_id]);
+ VTR_ASSERT(ModuleNetId::INVALID() != net);
+
+ /* Configure the net sink */
+ module_manager.add_module_net_sink(top_module, net, grid_module, grid_instance, grid_port_id, tile_port_to_connect.pins()[pin_id]);
+ }
+ }
}
+
+ return CMD_EXEC_SUCCESS;
}
/********************************************************************
@@ -757,17 +782,23 @@ int add_top_module_global_ports_from_grid_modules(ModuleManager& module_manager,
const TileAnnotation& tile_annotation,
const DeviceGrid& grids,
const vtr::Matrix& grid_instance_ids) {
+ int status = CMD_EXEC_SUCCESS;
- /* Add the global ports which are yet added to the top-level module
+ /* Add the global ports which are NOT yet added to the top-level module
* (in different names than the global ports defined in circuit library
*/
std::vector global_ports_to_add;
for (const TileGlobalPortId& tile_global_port : tile_annotation.global_ports()) {
ModulePortId module_port = module_manager.find_module_port(top_module, tile_annotation.global_port_name(tile_global_port));
+ /* The global port size is derived from the maximum port size among all the tile port defintion */
if (ModulePortId::INVALID() == module_port) {
BasicPort global_port_to_add;
global_port_to_add.set_name(tile_annotation.global_port_name(tile_global_port));
- global_port_to_add.set_width(tile_annotation.global_port_tile_port(tile_global_port).get_width());
+ size_t max_port_size = 0;
+ for (const BasicPort& tile_port : tile_annotation.global_port_tile_ports(tile_global_port)) {
+ max_port_size = std::max(tile_port.get_width(), max_port_size);
+ }
+ global_port_to_add.set_width(max_port_size);
global_ports_to_add.push_back(global_port_to_add);
}
}
@@ -784,72 +815,130 @@ int add_top_module_global_ports_from_grid_modules(ModuleManager& module_manager,
ModulePortId top_module_port = module_manager.find_module_port(top_module, tile_annotation.global_port_name(tile_global_port));
VTR_ASSERT(ModulePortId::INVALID() != top_module_port);
- /* Spot the port from child modules from core grids */
- for (size_t ix = 1; ix < grids.width() - 1; ++ix) {
- for (size_t iy = 1; iy < grids.height() - 1; ++iy) {
- /* Bypass EMPTY tiles */
- if (true == is_empty_type(grids[ix][iy].type)) {
- continue;
- }
- /* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
- if ( (0 < grids[ix][iy].width_offset)
- || (0 < grids[ix][iy].height_offset)) {
- continue;
- }
+ for (size_t tile_info_id = 0; tile_info_id < tile_annotation.global_port_tile_names(tile_global_port).size(); ++tile_info_id) {
+ std::string tile_name = tile_annotation.global_port_tile_names(tile_global_port)[tile_info_id];
+ BasicPort tile_port = tile_annotation.global_port_tile_ports(tile_global_port)[tile_info_id];
+ /* Find the coordinates for the wanted tiles */
+ vtr::Point start_coord(1, 1);
+ vtr::Point end_coord(grids.width() - 1, grids.height() - 1);
+ vtr::Point range = tile_annotation.global_port_tile_coordinates(tile_global_port)[tile_info_id];
+ bool out_of_range = false;
- /* Bypass the tiles whose names do not match */
- if (std::string(grids[ix][iy].type->name) != tile_annotation.global_port_tile_name(tile_global_port)) {
- continue;
+ /* -1 means all the x should be considered */
+ if (size_t(-1) != range.x()) {
+ if ((range.x() < start_coord.x()) || (range.x() > end_coord.x())) {
+ out_of_range = true;
+ } else {
+ /* Set the range */
+ start_coord.set_x(range.x());
+ end_coord.set_x(range.x());
}
-
- /* Create nets and finish connection build-up */
- build_top_module_global_net_for_given_grid_module(module_manager,
- top_module,
- top_module_port,
- tile_annotation,
- tile_global_port,
- grids,
- vtr::Point(ix, iy),
- NUM_SIDES,
- grid_instance_ids);
-
}
- }
- /* Walk through all the grids on the perimeter, which are I/O grids */
- for (const e_side& io_side : FPGA_SIDES_CLOCKWISE) {
- for (const vtr::Point& io_coordinate : io_coordinates[io_side]) {
- /* Bypass EMPTY grid */
- if (true == is_empty_type(grids[io_coordinate.x()][io_coordinate.y()].type)) {
- continue;
- }
+ /* -1 means all the y should be considered */
+ if (size_t(-1) != range.y()) {
+ if ((range.y() < start_coord.y()) || (range.y() > end_coord.y())) {
+ out_of_range = true;
+ } else {
+ /* Set the range */
+ start_coord.set_y(range.y());
+ end_coord.set_y(range.y());
+ }
+ }
+
+ /* Error out immediately if the coordinate is not valid! */
+ if (true == out_of_range) {
+ VTR_LOG_ERROR("Coordinate (%lu, %lu) in tile annotation for tile '%s' is out of range (%lu:%lu, %lu:%lu)!",
+ range.x(), range.y(), tile_name.c_str(),
+ start_coord.x(), end_coord.x(), start_coord.y(), end_coord.y());
+ return CMD_EXEC_FATAL_ERROR;
+ }
+
+ /* Spot the port from child modules from core grids */
+ for (size_t ix = start_coord.x(); ix < end_coord.x(); ++ix) {
+ for (size_t iy = start_coord.y(); iy < end_coord.y(); ++iy) {
+ /* Bypass EMPTY tiles */
+ if (true == is_empty_type(grids[ix][iy].type)) {
+ continue;
+ }
+ /* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
+ if ( (0 < grids[ix][iy].width_offset)
+ || (0 < grids[ix][iy].height_offset)) {
+ continue;
+ }
+
+ /* Bypass the tiles whose names do not match */
+ if (std::string(grids[ix][iy].type->name) != tile_name) {
+ continue;
+ }
+
+ /* Create nets and finish connection build-up */
+ status = build_top_module_global_net_for_given_grid_module(module_manager,
+ top_module,
+ top_module_port,
+ tile_annotation,
+ tile_global_port,
+ tile_port,
+ grids,
+ vtr::Point(ix, iy),
+ NUM_SIDES,
+ grid_instance_ids);
+ if (CMD_EXEC_FATAL_ERROR == status) {
+ return status;
+ }
+ }
+ }
+
+ /* Walk through all the grids on the perimeter, which are I/O grids */
+ for (const e_side& io_side : FPGA_SIDES_CLOCKWISE) {
+ for (const vtr::Point& io_coordinate : io_coordinates[io_side]) {
+ /* Bypass EMPTY grid */
+ if (true == is_empty_type(grids[io_coordinate.x()][io_coordinate.y()].type)) {
+ continue;
+ }
- /* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
- if ( (0 < grids[io_coordinate.x()][io_coordinate.y()].width_offset)
- || (0 < grids[io_coordinate.x()][io_coordinate.y()].height_offset)) {
- continue;
- }
+ /* Skip width or height > 1 tiles (mostly heterogeneous blocks) */
+ if ( (0 < grids[io_coordinate.x()][io_coordinate.y()].width_offset)
+ || (0 < grids[io_coordinate.x()][io_coordinate.y()].height_offset)) {
+ continue;
+ }
- /* Bypass the tiles whose names do not match */
- if (std::string(grids[io_coordinate.x()][io_coordinate.y()].type->name) != tile_annotation.global_port_tile_name(tile_global_port)) {
- continue;
- }
+ /* Bypass the tiles whose names do not match */
+ if (std::string(grids[io_coordinate.x()][io_coordinate.y()].type->name) != tile_name) {
+ continue;
+ }
- /* Create nets and finish connection build-up */
- build_top_module_global_net_for_given_grid_module(module_manager,
- top_module,
- top_module_port,
- tile_annotation,
- tile_global_port,
- grids,
- io_coordinate,
- io_side,
- grid_instance_ids);
+ /* Check if the coordinate satisfy the tile coordinate defintion
+ * - Bypass if the x is a specific number (!= -1), and io_coordinate is different
+ * - Bypass if the y is a specific number (!= -1), and io_coordinate is different
+ */
+ if ((size_t(-1) != range.x()) && (range.x() != io_coordinate.x())) {
+ continue;
+ }
+ if ((size_t(-1) != range.y()) && (range.y() != io_coordinate.y())) {
+ continue;
+ }
+
+ /* Create nets and finish connection build-up */
+ status = build_top_module_global_net_for_given_grid_module(module_manager,
+ top_module,
+ top_module_port,
+ tile_annotation,
+ tile_global_port,
+ tile_port,
+ grids,
+ io_coordinate,
+ io_side,
+ grid_instance_ids);
+ if (CMD_EXEC_FATAL_ERROR == status) {
+ return status;
+ }
+ }
}
}
}
- return CMD_EXEC_SUCCESS;
+ return status;
}
} /* end namespace openfpga */
diff --git a/openfpga/src/fpga_bitstream/fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/fabric_bitstream.cpp
index 6ea5c8168..785327661 100644
--- a/openfpga/src/fpga_bitstream/fabric_bitstream.cpp
+++ b/openfpga/src/fpga_bitstream/fabric_bitstream.cpp
@@ -21,6 +21,9 @@ FabricBitstream::FabricBitstream() {
num_regions_ = 0;
invalid_region_ids_.clear();
+
+ use_address_ = false;
+ use_wl_address_ = false;
}
/**************************************************
diff --git a/openfpga/src/utils/check_tile_annotation.cpp b/openfpga/src/utils/check_tile_annotation.cpp
index 75d1eeaf5..df209644d 100644
--- a/openfpga/src/utils/check_tile_annotation.cpp
+++ b/openfpga/src/utils/check_tile_annotation.cpp
@@ -102,107 +102,125 @@ int check_tile_annotation_conflicts_with_physical_tile(const TileAnnotation& til
int num_err = 0;
for (const TileGlobalPortId& tile_global_port : tile_annotation.global_ports()) {
- /* Must find a valid physical tile in the same name */
- size_t found_matched_physical_tile = 0;
- size_t found_matched_physical_tile_port = 0;
- for (const t_physical_tile_type& physical_tile : physical_tile_types) {
- if (std::string(physical_tile.name) != tile_annotation.global_port_tile_name(tile_global_port)) {
- continue;
- }
+ for (size_t tile_info_id = 0; tile_info_id < tile_annotation.global_port_tile_names(tile_global_port).size(); ++tile_info_id) {
+ /* Must find a valid physical tile in the same name */
+ size_t found_matched_physical_tile = 0;
+ size_t found_matched_physical_tile_port = 0;
- /* Found a match, increment the counter */
- found_matched_physical_tile++;
+ std::string required_tile_name = tile_annotation.global_port_tile_names(tile_global_port)[tile_info_id];
+ BasicPort required_tile_port = tile_annotation.global_port_tile_ports(tile_global_port)[tile_info_id];
- /* Must found a valid port where both port name and port size must match!!! */
- for (const t_physical_tile_port& tile_port : physical_tile.ports) {
- if (std::string(tile_port.name) != tile_annotation.global_port_tile_port(tile_global_port).get_name()) {
+ for (const t_physical_tile_type& physical_tile : physical_tile_types) {
+ if (std::string(physical_tile.name) != required_tile_name) {
continue;
}
- if (size_t(tile_port.num_pins) != tile_annotation.global_port_tile_port(tile_global_port).get_width()) {
- continue;
+
+ /* Found a match, increment the counter */
+ found_matched_physical_tile++;
+
+ /* Must found a valid port where both port name and port size must match!!! */
+ for (const t_physical_tile_port& tile_port : physical_tile.ports) {
+ if (std::string(tile_port.name) != required_tile_port.get_name()) {
+ continue;
+ }
+
+ BasicPort ref_tile_port(tile_port.name, tile_port.num_pins);
+ /* Port size must be in range!!! */
+ if (false == ref_tile_port.contained(required_tile_port)) {
+ VTR_LOG_ERROR("Tile annotation port '%s[%lu:%lu]' is out of the range of physical tile port '%s[%lu:%lu]'!",
+ required_tile_port.get_name().c_str(),
+ required_tile_port.get_lsb(),
+ required_tile_port.get_msb(),
+ ref_tile_port.get_name().c_str(),
+ ref_tile_port.get_lsb(),
+ ref_tile_port.get_msb());
+ num_err++;
+ continue;
+ }
+
+
+ /* Check if port property matches */
+ int grid_pin_index = tile_port.absolute_first_pin_index;
+
+ if (tile_port.is_clock != tile_annotation.global_port_is_clock(tile_global_port)) {
+ VTR_LOGF_ERROR(__FILE__, __LINE__,
+ "Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' does not match physical tile port %s.%s in clock property (one is defined as clock while the other is not)!\n",
+ required_tile_name.c_str(),
+ required_tile_port.get_name().c_str(),
+ required_tile_port.get_lsb(),
+ required_tile_port.get_msb(),
+ tile_annotation.global_port_name(tile_global_port).c_str(),
+ physical_tile.name, tile_port.name);
+ num_err++;
+ }
+
+ if ((false == tile_port.is_clock)
+ && (false == tile_port.is_non_clock_global)) {
+ VTR_LOGF_ERROR(__FILE__, __LINE__,
+ "Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' match physical tile port %s.%s but is not defined as a non-clock global port!\n",
+ required_tile_name.c_str(),
+ required_tile_port.get_name().c_str(),
+ required_tile_port.get_lsb(),
+ required_tile_port.get_msb(),
+ tile_annotation.global_port_name(tile_global_port).c_str(),
+ physical_tile.name, tile_port.name);
+ num_err++;
+ }
+
+ float pin_Fc = find_physical_tile_pin_Fc(&physical_tile, grid_pin_index);
+ if (0. != pin_Fc) {
+ VTR_LOGF_ERROR(__FILE__, __LINE__,
+ "Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' match physical tile port %s.%s but its Fc is not zero '%g' !\n",
+ required_tile_name.c_str(),
+ required_tile_port.get_name().c_str(),
+ required_tile_port.get_lsb(),
+ required_tile_port.get_msb(),
+ tile_annotation.global_port_name(tile_global_port).c_str(),
+ physical_tile.name, tile_port.name, pin_Fc);
+
+ }
+
+ found_matched_physical_tile_port++;
}
-
- /* Check if port property matches */
- int grid_pin_index = tile_port.absolute_first_pin_index;
-
- if (tile_port.is_clock != tile_annotation.global_port_is_clock(tile_global_port)) {
- VTR_LOGF_ERROR(__FILE__, __LINE__,
- "Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' does not match physical tile port %s.%s in clock property (one is defined as clock while the other is not)!\n",
- tile_annotation.global_port_tile_name(tile_global_port).c_str(),
- tile_annotation.global_port_tile_port(tile_global_port).get_name().c_str(),
- tile_annotation.global_port_tile_port(tile_global_port).get_lsb(),
- tile_annotation.global_port_tile_port(tile_global_port).get_msb(),
- tile_annotation.global_port_name(tile_global_port).c_str(),
- physical_tile.name, tile_port.name);
- num_err++;
- }
-
- if ((false == tile_port.is_clock)
- && (false == tile_port.is_non_clock_global)) {
- VTR_LOGF_ERROR(__FILE__, __LINE__,
- "Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' match physical tile port %s.%s but is not defined as a non-clock global port!\n",
- tile_annotation.global_port_tile_name(tile_global_port).c_str(),
- tile_annotation.global_port_tile_port(tile_global_port).get_name().c_str(),
- tile_annotation.global_port_tile_port(tile_global_port).get_lsb(),
- tile_annotation.global_port_tile_port(tile_global_port).get_msb(),
- tile_annotation.global_port_name(tile_global_port).c_str(),
- physical_tile.name, tile_port.name);
- num_err++;
- }
-
- float pin_Fc = find_physical_tile_pin_Fc(&physical_tile, grid_pin_index);
- if (0. != pin_Fc) {
- VTR_LOGF_ERROR(__FILE__, __LINE__,
- "Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' match physical tile port %s.%s but its Fc is not zero '%g' !\n",
- tile_annotation.global_port_tile_name(tile_global_port).c_str(),
- tile_annotation.global_port_tile_port(tile_global_port).get_name().c_str(),
- tile_annotation.global_port_tile_port(tile_global_port).get_lsb(),
- tile_annotation.global_port_tile_port(tile_global_port).get_msb(),
- tile_annotation.global_port_name(tile_global_port).c_str(),
- physical_tile.name, tile_port.name, pin_Fc);
-
- }
-
- found_matched_physical_tile_port++;
}
- }
- /* If we found no match, error out */
- if (0 == found_matched_physical_tile) {
- VTR_LOGF_ERROR(__FILE__, __LINE__,
- "Tile name '%s' in tile annotation '%s' does not match any physical tile!\n",
- tile_annotation.global_port_tile_name(tile_global_port).c_str(),
- tile_annotation.global_port_name(tile_global_port).c_str());
- num_err++;
- }
- if (0 == found_matched_physical_tile_port) {
- VTR_LOGF_ERROR(__FILE__, __LINE__,
- "Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' does not match any physical tile port!\n",
- tile_annotation.global_port_tile_name(tile_global_port).c_str(),
- tile_annotation.global_port_tile_port(tile_global_port).get_name().c_str(),
- tile_annotation.global_port_tile_port(tile_global_port).get_lsb(),
- tile_annotation.global_port_tile_port(tile_global_port).get_msb(),
- tile_annotation.global_port_name(tile_global_port).c_str());
- num_err++;
- }
+ /* If we found no match, error out */
+ if (0 == found_matched_physical_tile) {
+ VTR_LOGF_ERROR(__FILE__, __LINE__,
+ "Tile name '%s' in tile annotation '%s' does not match any physical tile!\n",
+ required_tile_name.c_str(),
+ tile_annotation.global_port_name(tile_global_port).c_str());
+ num_err++;
+ }
+ if (0 == found_matched_physical_tile_port) {
+ VTR_LOGF_ERROR(__FILE__, __LINE__,
+ "Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' does not match any physical tile port!\n",
+ required_tile_name.c_str(),
+ required_tile_port.get_name().c_str(),
+ required_tile_port.get_lsb(),
+ required_tile_port.get_msb(),
+ tile_annotation.global_port_name(tile_global_port).c_str());
+ num_err++;
+ }
- /* If we found more than 1 match, error out */
- if (1 < found_matched_physical_tile) {
- VTR_LOGF_ERROR(__FILE__, __LINE__,
- "Tile name '%s' in tile annotation '%s' match more than 1 physical tile!\n",
- tile_annotation.global_port_tile_name(tile_global_port).c_str(),
- tile_annotation.global_port_name(tile_global_port).c_str());
- num_err++;
- }
- if (1 < found_matched_physical_tile_port) {
- VTR_LOGF_ERROR(__FILE__, __LINE__,
- "Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' match more than 1physical tile port!\n",
- tile_annotation.global_port_tile_name(tile_global_port).c_str(),
- tile_annotation.global_port_tile_port(tile_global_port).get_name().c_str(),
- tile_annotation.global_port_tile_port(tile_global_port).get_lsb(),
- tile_annotation.global_port_tile_port(tile_global_port).get_msb(),
- tile_annotation.global_port_name(tile_global_port).c_str());
- num_err++;
+ /* If we found more than 1 match, error out */
+ if (1 < found_matched_physical_tile) {
+ VTR_LOGF_ERROR(__FILE__, __LINE__,
+ "Tile name '%s' in tile annotation '%s' match more than 1 physical tile!\n",
+ required_tile_name.c_str(),
+ tile_annotation.global_port_name(tile_global_port).c_str());
+ num_err++;
+ }
+ if (1 < found_matched_physical_tile_port) {
+ VTR_LOGF_ERROR(__FILE__, __LINE__,
+ "Tile port '%s.%s[%ld:%ld]' in tile annotation '%s' match more than 1 physical tile port!\n",
+ required_tile_name.c_str(),
+ required_tile_port.get_name().c_str(),
+ required_tile_port.get_lsb(),
+ required_tile_port.get_msb(),
+ tile_annotation.global_port_name(tile_global_port).c_str());
+ num_err++;
+ }
}
}
diff --git a/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.act b/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.act
new file mode 100644
index 000000000..8f1ec666a
--- /dev/null
+++ b/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.act
@@ -0,0 +1,9 @@
+clk 0.500000 2.000000
+a 0.502000 0.197200
+b 0.485400 0.202800
+c 0.248000 0.176800
+a_reg 0.502000 0.197200
+b_reg 0.485400 0.202800
+n10 0.248000 0.043259
+n13 0.502000 0.098994
+n17 0.485400 0.098439
diff --git a/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.blif b/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.blif
new file mode 100644
index 000000000..19207fd81
--- /dev/null
+++ b/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.blif
@@ -0,0 +1,16 @@
+# Benchmark "and2_pipelined" written by ABC on Sun Jan 10 10:26:01 2021
+.model and2_pipelined
+.inputs clk a b
+.outputs c
+
+.latch n10 c 2
+.latch n13 a_reg 2
+.latch n17 b_reg 2
+
+.names a_reg b_reg n10
+11 1
+.names a n13
+1 1
+.names b n17
+1 1
+.end
diff --git a/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.v b/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.v
new file mode 100644
index 000000000..1efccbba0
--- /dev/null
+++ b/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.v
@@ -0,0 +1,34 @@
+/////////////////////////////////////////
+// Functionality: a pipelined 2-input AND
+// where inputs and outputs are registered
+// Author: Xifan Tang
+////////////////////////////////////////
+`timescale 1ns / 1ps
+
+module and2_pipelined(
+ clk,
+ a,
+ b,
+ c);
+
+input wire clk;
+input wire a;
+input wire b;
+output wire c;
+
+reg a_reg;
+reg b_reg;
+reg c_reg;
+
+always @(posedge clk) begin
+ a_reg <= a;
+ b_reg <= b;
+end
+
+always @(posedge clk) begin
+ c_reg <= a_reg & b_reg;
+end
+
+assign c = c_reg;
+
+endmodule
diff --git a/openfpga_flow/misc/quicklogic_yosys_flow_ap3.ys b/openfpga_flow/misc/quicklogic_yosys_flow_ap3.ys
new file mode 100644
index 000000000..cccd220b9
--- /dev/null
+++ b/openfpga_flow/misc/quicklogic_yosys_flow_ap3.ys
@@ -0,0 +1,6 @@
+# Yosys synthesis script for ${TOP_MODULE}
+# Read verilog files
+${READ_VERILOG_FILE}
+
+synth_quicklogic -blif ${OUTPUT_BLIF} -openfpga -top ${TOP_MODULE}
+
diff --git a/openfpga_flow/openfpga_arch/README.md b/openfpga_flow/openfpga_arch/README.md
index ba6e307ca..5d1e8cafa 100644
--- a/openfpga_flow/openfpga_arch/README.md
+++ b/openfpga_flow/openfpga_arch/README.md
@@ -21,6 +21,7 @@ Note that an OpenFPGA architecture can be applied to multiple VPR architecture f
- behavioral: If behavioral Verilog modeling is specified
- local\_encoder: If local encoders are used in routing multiplexer design
- spyio/spypad: If spy I/Os are used
+- registerable\_io: If I/Os are registerable (can be either combinational or sequential)
- stdcell: If circuit designs are built with standard cells only
- tree\_mux: If routing multiplexers are built with a tree-like structure
- : The technology node which the delay numbers are extracted from.
diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClk_cc_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClk_cc_openfpga.xml
index d3f4baf4b..ed9abccff 100644
--- a/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClk_cc_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClk_cc_openfpga.xml
@@ -169,7 +169,9 @@
-
+
+
+
diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClk_registerable_io_cc_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClk_registerable_io_cc_openfpga.xml
new file mode 100644
index 000000000..1e5412069
--- /dev/null
+++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClk_registerable_io_cc_openfpga.xml
@@ -0,0 +1,198 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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_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_arch/k4_frac_N8_reset_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml b/openfpga_flow/openfpga_arch/k4_frac_N8_reset_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
index 0ad0bd1a6..69654611a 100644
--- a/openfpga_flow/openfpga_arch/k4_frac_N8_reset_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k4_frac_N8_reset_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
@@ -217,8 +217,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/openfpga_shell_scripts/fix_device_global_tile_clock_example_script.openfpga b/openfpga_flow/openfpga_shell_scripts/fix_device_global_tile_clock_example_script.openfpga
new file mode 100644
index 000000000..b5fd710b6
--- /dev/null
+++ b/openfpga_flow/openfpga_shell_scripts/fix_device_global_tile_clock_example_script.openfpga
@@ -0,0 +1,76 @@
+# Run VPR for the 'and' design
+# When the global clock is defined as a port of a tile, clock routing in VPR should be skipped
+# This is due to the Fc_in of clock port is set to 0 for global wiring
+#--write_rr_graph example_rr_graph.xml
+vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} --device ${OPENFPGA_VPR_DEVICE_LAYOUT}
+
+# Read OpenFPGA architecture definition
+read_openfpga_arch -f ${OPENFPGA_ARCH_FILE}
+
+# Read OpenFPGA simulation settings
+read_openfpga_simulation_setting -f ${OPENFPGA_SIM_SETTING_FILE}
+
+# Annotate the OpenFPGA architecture to VPR data base
+# to debug use --verbose options
+link_openfpga_arch --activity_file ${ACTIVITY_FILE} --sort_gsb_chan_node_in_edges
+
+# Check and correct any naming conflicts in the BLIF netlist
+check_netlist_naming_conflict --fix --report ./netlist_renaming.xml
+
+# Apply fix-up to clustering nets based on routing results
+pb_pin_fixup --verbose
+
+# Apply fix-up to Look-Up Table truth tables based on packing results
+lut_truth_table_fixup
+
+# Build the module graph
+# - Enabled compression on routing architecture modules
+# - Enable pin duplication on grid modules
+build_fabric --compress_routing #--verbose
+
+# Write the fabric hierarchy of module graph to a file
+# This is used by hierarchical PnR flows
+write_fabric_hierarchy --file ./fabric_hierarchy.txt
+
+# Repack the netlist to physical pbs
+# This must be done before bitstream generator and testbench generation
+# Strongly recommend it is done after all the fix-up have been applied
+repack #--verbose
+
+# Build the bitstream
+# - Output the fabric-independent bitstream to a file
+build_architecture_bitstream --verbose --write_file fabric_independent_bitstream.xml
+
+# Build fabric-dependent bitstream
+build_fabric_bitstream --verbose
+
+# Write fabric-dependent bitstream
+write_fabric_bitstream --file fabric_bitstream.xml --format xml
+
+# Write the Verilog netlist for FPGA fabric
+# - Enable the use of explicit port mapping in Verilog netlist
+write_fabric_verilog --file ./SRC --explicit_port_mapping --include_timing --print_user_defined_template --verbose
+
+# Write the Verilog testbench for FPGA fabric
+# - We suggest the use of same output directory as fabric Verilog netlists
+# - Must specify the reference benchmark file if you want to output any testbenches
+# - Enable top-level testbench which is a full verification including programming circuit and core logic of FPGA
+# - Enable pre-configured top-level testbench which is a fast verification skipping programming phase
+# - Simulation ini file is optional and is needed only when you need to interface different HDL simulators using openfpga flow-run scripts
+write_verilog_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} --print_top_testbench --print_preconfig_top_testbench --print_simulation_ini ./SimulationDeck/simulation_deck.ini --include_signal_init --support_icarus_simulator --explicit_port_mapping
+
+# Write the SDC files for PnR backend
+# - Turn on every options here
+write_pnr_sdc --file ./SDC
+
+# Write SDC to disable timing for configure ports
+write_sdc_disable_timing_configure_ports --file ./SDC/disable_configure_ports.sdc
+
+# Write the SDC to run timing analysis for a mapped FPGA fabric
+write_analysis_sdc --file ./SDC_analysis
+
+# Finish and exit OpenFPGA
+exit
+
+# Note :
+# To run verification at the end of the flow maintain source in ./SRC directory
diff --git a/openfpga_flow/openfpga_shell_scripts/quicklogic_flow_example_script.openfpga b/openfpga_flow/openfpga_shell_scripts/quicklogic_flow_example_script.openfpga
new file mode 100644
index 000000000..5adab1c51
--- /dev/null
+++ b/openfpga_flow/openfpga_shell_scripts/quicklogic_flow_example_script.openfpga
@@ -0,0 +1,77 @@
+# Run VPR for the 'and' design
+#--write_rr_graph example_rr_graph.xml
+vpr ${VPR_ARCH_FILE} ${VPR_TESTBENCH_BLIF} --clock_modeling route
+
+# Read OpenFPGA architecture definition
+read_openfpga_arch -f ${OPENFPGA_ARCH_FILE}
+
+# Read OpenFPGA simulation settings
+read_openfpga_simulation_setting -f ${OPENFPGA_SIM_SETTING_FILE}
+
+# Annotate the OpenFPGA architecture to VPR data base
+# to debug use --verbose options
+link_openfpga_arch --activity_file ${ACTIVITY_FILE} --sort_gsb_chan_node_in_edges
+
+# Check and correct any naming conflicts in the BLIF netlist
+check_netlist_naming_conflict --fix --report ./netlist_renaming.xml
+
+# Apply fix-up to clustering nets based on routing results
+pb_pin_fixup --verbose
+
+# Apply fix-up to Look-Up Table truth tables based on packing results
+lut_truth_table_fixup
+
+# Build the module graph
+# - Enabled compression on routing architecture modules
+# - Enable pin duplication on grid modules
+build_fabric --compress_routing #--verbose
+
+# Write the fabric hierarchy of module graph to a file
+# This is used by hierarchical PnR flows
+write_fabric_hierarchy --file ./fabric_hierarchy.txt
+
+# Repack the netlist to physical pbs
+# This must be done before bitstream generator and testbench generation
+# Strongly recommend it is done after all the fix-up have been applied
+repack #--verbose
+
+# Build the bitstream
+# - Output the fabric-independent bitstream to a file
+build_architecture_bitstream --verbose --write_file fabric_independent_bitstream.xml
+
+# Build fabric-dependent bitstream
+build_fabric_bitstream --verbose
+
+# Write fabric-dependent bitstream
+write_fabric_bitstream --file fabric_bitstream.xml --format xml
+
+# Write the Verilog netlist for FPGA fabric
+# - Enable the use of explicit port mapping in Verilog netlist
+write_fabric_verilog --file ./SRC --explicit_port_mapping --include_timing --print_user_defined_template --verbose
+
+# Write the Verilog testbench for FPGA fabric
+# - We suggest the use of same output directory as fabric Verilog netlists
+# - Must specify the reference benchmark file if you want to output any testbenches
+# - Enable top-level testbench which is a full verification including programming circuit and core logic of FPGA
+# - Enable pre-configured top-level testbench which is a fast verification skipping programming phase
+# - Simulation ini file is optional and is needed only when you need to interface different HDL simulators using openfpga flow-run scripts
+write_verilog_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} --print_top_testbench --print_preconfig_top_testbench --print_simulation_ini ./SimulationDeck/simulation_deck.ini --include_signal_init --support_icarus_simulator
+
+# Write the SDC files for PnR backend
+# - Turn on every options here
+write_pnr_sdc --file ./SDC
+
+# Write SDC to constrain timing of configuration chain
+write_configuration_chain_sdc --file ./SDC/ccff_timing.sdc --time_unit ns --max_delay 5 --min_delay 2.5
+
+# Write SDC to disable timing for configure ports
+write_sdc_disable_timing_configure_ports --file ./SDC/disable_configure_ports.sdc
+
+# Write the SDC to run timing analysis for a mapped FPGA fabric
+write_analysis_sdc --file ./SDC_analysis
+
+# Finish and exit OpenFPGA
+exit
+
+# Note :
+# To run verification at the end of the flow maintain source in ./SRC directory
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=
diff --git a/openfpga_flow/tasks/basic_tests/global_tile_ports/global_tile_clock/config/task.conf b/openfpga_flow/tasks/basic_tests/global_tile_ports/global_tile_clock/config/task.conf
index fd95b7ca9..abc1be003 100644
--- a/openfpga_flow/tasks/basic_tests/global_tile_ports/global_tile_clock/config/task.conf
+++ b/openfpga_flow/tasks/basic_tests/global_tile_ports/global_tile_clock/config/task.conf
@@ -26,6 +26,7 @@ arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_GlobalTileClk_
[BENCHMARKS]
bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch/and2_latch.v
+bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.v
[SYNTHESIS_PARAM]
bench0_top = and2
@@ -34,5 +35,8 @@ bench0_chan_width = 300
bench1_top = and2_latch
bench1_chan_width = 300
+bench2_top = and2_pipelined
+bench2_chan_width = 300
+
[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
end_flow_with_test=
diff --git a/openfpga_flow/tasks/fpga_verilog/io/registerable_io/config/task.conf b/openfpga_flow/tasks/fpga_verilog/io/registerable_io/config/task.conf
new file mode 100644
index 000000000..700f8e3c7
--- /dev/null
+++ b/openfpga_flow/tasks/fpga_verilog/io/registerable_io/config/task.conf
@@ -0,0 +1,35 @@
+# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
+# 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/fix_device_global_tile_clock_example_script.openfpga
+openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClk_registerable_io_cc_openfpga.xml
+openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
+openfpga_vpr_device_layout=2x2
+
+[ARCHITECTURES]
+arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_GlobalTileClk_registerable_io_40nm.xml
+
+[BENCHMARKS]
+bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_pipelined/and2_pipelined.v
+
+[SYNTHESIS_PARAM]
+bench0_top = and2_pipelined
+bench0_chan_width = 300
+
+[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
+end_flow_with_test=
diff --git a/openfpga_flow/tasks/quicklogic_tests/flow_test/config/task.conf b/openfpga_flow/tasks/quicklogic_tests/flow_test/config/task.conf
new file mode 100644
index 000000000..67d074bd0
--- /dev/null
+++ b/openfpga_flow/tasks/quicklogic_tests/flow_test/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=yosys_vpr
+
+[OpenFPGA_SHELL]
+openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/quicklogic_flow_example_script.openfpga
+openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_cc_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/counter/counter.v
+
+[SYNTHESIS_PARAM]
+bench0_top = counter
+bench0_chan_width = 100
+bench0_yosys=${PATH:OPENFPGA_PATH}/openfpga_flow/misc/quicklogic_yosys_flow_ap3.ys
+
+[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
+end_flow_with_test=
+vpr_fpga_verilog_formal_verification_top_netlist=
diff --git a/openfpga_flow/vpr_arch/README.md b/openfpga_flow/vpr_arch/README.md
index 4ab3a92e4..87723c7e3 100644
--- a/openfpga_flow/vpr_arch/README.md
+++ b/openfpga_flow/vpr_arch/README.md
@@ -15,6 +15,7 @@ Please reveal the following architecture features in the names to help quickly s
- aib: If the Advanced Interface Bus (AIB) is used in place of some I/Os.
- multi\_io\_capacity: If I/O capacity is different on each side of FPGAs.
- reduced\_io: If I/Os only appear a certain or multiple sides of FPGAs
+- registerable\_io: If I/Os are registerable (can be either combinational or sequential)
- : The technology node which the delay numbers are extracted from.
- TileOrgz: How tile is organized.
* Top-left (Tl): the pins of a tile are placed on the top side and left side only
diff --git a/openfpga_flow/vpr_arch/k4_N4_tileable_GlobalTileClk_registerable_io_40nm.xml b/openfpga_flow/vpr_arch/k4_N4_tileable_GlobalTileClk_registerable_io_40nm.xml
new file mode 100644
index 000000000..c3c68f421
--- /dev/null
+++ b/openfpga_flow/vpr_arch/k4_N4_tileable_GlobalTileClk_registerable_io_40nm.xml
@@ -0,0 +1,329 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ io.outpad io.inpad io.clk
+ io.outpad io.inpad io.clk
+ io.outpad io.inpad io.clk
+ io.outpad io.inpad io.clk
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1 1 1 1 1
+ 1 1 1 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 261e-12
+ 261e-12
+ 261e-12
+ 261e-12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/openfpga_flow/vpr_arch/k4_frac_N8_tileable_reset_softadder_register_scan_chain_nonLR_caravel_io_skywater130nm.xml b/openfpga_flow/vpr_arch/k4_frac_N8_tileable_reset_softadder_register_scan_chain_nonLR_caravel_io_skywater130nm.xml
new file mode 100644
index 000000000..07c6ba848
--- /dev/null
+++ b/openfpga_flow/vpr_arch/k4_frac_N8_tileable_reset_softadder_register_scan_chain_nonLR_caravel_io_skywater130nm.xml
@@ -0,0 +1,737 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ io_top.outpad io_top.inpad
+
+
+
+
+
+
+
+
+
+
+
+ io_right.outpad io_right.inpad
+
+
+
+
+
+
+
+
+
+
+
+ io_bottom.outpad io_bottom.inpad
+
+
+
+
+
+
+
+
+
+
+
+ io_left.outpad io_left.inpad
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ clb.clk clb.reset
+ clb.reg_in clb.sc_in clb.cin clb.O[7:0] clb.I0 clb.I0i clb.I1 clb.I1i clb.I2 clb.I2i clb.I3 clb.I3i
+ clb.O[15:8] clb.I4 clb.I4i clb.I5 clb.I5i clb.I6 clb.I6i clb.I7 clb.I7i
+ clb.reg_out clb.sc_out clb.cout
+
+
+
+
+
+
+
+
+
+
+