diff --git a/docs/source/manual/arch_lang/direct_interconnect.rst b/docs/source/manual/arch_lang/direct_interconnect.rst
index 21b91b74b..d970194e7 100644
--- a/docs/source/manual/arch_lang/direct_interconnect.rst
+++ b/docs/source/manual/arch_lang/direct_interconnect.rst
@@ -1,12 +1,12 @@
.. _direct_interconnect:
-Inter-Tile Direct Interconnection extensions
---------------------------------------------
+Direct Interconnect
+-------------------
-This section introduces extensions on the architecture description file about existing interconnection description.
+This section introduces extensions on the architecture description file about direct connections between programmable blocks.
-Directlist
-~~~~~~~~~~
+Syntax
+~~~~~~
The original direct connections in the directlist section are documented here_. Its description is given below:
@@ -20,20 +20,26 @@ The original direct connections in the directlist section are documented here_.
.. note:: These options are required
-Our extension include three more options:
+In the OpenFPGA architecture file, you may define additional attributes for each VPR's direct connection:
.. code-block:: xml
-
-
+
+
-.. note:: these options are optional. However, if `interconnection_type` is set `x_dir` and `y_dir` are required.
+.. note:: these options are optional. However, if ``interconnection_type`` is set to ``inter_column`` or ``inter_row``, then ``x_dir`` and ``y_dir`` are required.
.. option:: interconnection_type=""
- the type of interconnection should be a string.
- Available types are ``NONE`` | ``column`` | ``row``, specifies if it applies on a column or a row ot if it doesn't apply.
+ Available types are ``inner_column_or_row`` | ``part_of_cb`` | ``inter_column`` | ``inter_row``
+
+ - ``inner_column_or_row`` indicates the direct connections are between tiles in the same column or row. This is the default value.
+ - ``part_of_cb`` indicates the direct connections will drive routing multiplexers in connection blocks. Therefore, it is no longer a strict point-to-point direct connection.
+ - ``inter_column`` indicates the direct connections are between tiles in two columns
+ - ``inter_row`` indicates the direct connections are between tiles in two rows
+
+.. note:: The following syntax is only applicable to ``inter_column`` and ``inter_row``
.. option:: x_dir=""
@@ -42,15 +48,15 @@ Our extension include three more options:
- x_dir="positive":
- - interconnection_type="column": a column will be connected to a column on the ``right``, if it exists.
+ - interconnection_type="inter_column": a column will be connected to a column on the ``right``, if it exists.
- - interconnection_type="row": the most on the ``right`` cell from a row connection will connect the most on the ``left`` cell of next row, if it exists.
+ - interconnection_type="inter_row": the most on the ``right`` cell from a row connection will connect the most on the ``left`` cell of next row, if it exists.
- x_dir="negative":
- - interconnection_type="column": a column will be connected to a column on the ``left``, if it exists.
+ - interconnection_type="inter_column": a column will be connected to a column on the ``left``, if it exists.
- - interconnection_type="row": the most on the ``left`` cell from a row connection will connect the most on the ``right`` cell of next row, if it exists.
+ - interconnection_type="inter_row": the most on the ``left`` cell from a row connection will connect the most on the ``right`` cell of next row, if it exists.
.. option:: y_dir=""
@@ -59,27 +65,96 @@ Our extension include three more options:
- y_dir="positive":
- - interconnection_type="column": the ``bottom`` cell of a column will be connected to the next column ``top`` cell, if it exists.
+ - interconnection_type="inter_column": the ``bottom`` cell of a column will be connected to the next column ``top`` cell, if it exists.
- - interconnection_type="row": a row will be connected on an ``above`` row, if it exists.
+ - interconnection_type="inter_row": a row will be connected on an ``above`` row, if it exists.
- y_dir="negative":
- - interconnection_type="column": the ``top`` cell of a column will be connected to the next column ``bottom`` cell, if it exists.
+ - interconnection_type="inter_column": the ``top`` cell of a column will be connected to the next column ``bottom`` cell, if it exists.
- - interconnection_type="row": a row will be connected on a row ``below``, if it exists.
+ - interconnection_type="inter_row": a row will be connected on a row ``below``, if it exists.
-Example
-~~~~~~~
+Enhanced Connection Block
+~~~~~~~~~~~~~~~~~~~~~~~~~
-For this example, we will study a scan-chain implementation. The description could be:
+The direct connection can also drive routing multiplexers of connection blocks. When such connection occures in a connection block, it is called enhanced connection block.
+:numref:`fig_ecb` illustrates the difference between a regular connection block and an enhanced connection block.
+
+.. _fig_ecb:
+
+.. figure:: ./figures/ecb.png
+
+ Enhanced connection block vs. Regular connection block
+
+In such scenario, the type ``part_of_cb`` is required.
+
+.. warning:: Restrictions may be applied when building the direct connections as part of a connection block.
+
+Direct connections can be inside a tile or across two tiles. Currently, across more than two tiles are not supported!
+:numref:`fig_ecb_allowed_direct_connection`` illustrates the region (in red) where any input pin is allowed to be driven by any output pin.
+
+.. _fig_ecb_allowed_direct_connection:
+
+.. figure:: ./figures/ecb_allowed_direct_connection.png
+
+ Allowed connections inside a tile for enhanced connection block (see the highlighted region)
+
+:numref:`fig_ecb_allowed_direct_connection_inner_tile_example`` shows a few feedback connections which can be built inside connection blocks. Note that feedback connections are fully allowed between any pins on the same side of a programmable block.
+
+.. _fig_ecb_allowed_direct_connection_inner_tile_example:
+
+.. figure:: ./figures/ecb_allowed_direct_connection_inner_tile_example.png
+
+ Example of feedback connections inside a tile for enhanced connection block
+
+For instance, VPR architecture defines feedback connections like:
.. code-block:: xml
-
+
+
+
+:numref:`fig_ecb_allowed_direct_connection_inter_tile_example`` shows a few inter-tile connections which can be built inside connection blocks. Note that inter-tile connections are subjected to the restrictions depicted in :numref:`fig_ecb_allowed_direct_connection``
+
+.. _fig_ecb_allowed_direct_connection_inter_tile_example:
+
+.. figure:: ./figures/ecb_allowed_direct_connection_inter_tile_example.png
+
+ Example of connections across two tiles for enhanced connection block
+
+:numref:`fig_ecb_forbid_direct_connection_example`` illustrates some inner-tile and inter-tile connections which are not allowed. Note that feedback connections across different sides are restricted!
+
+.. _fig_ecb_forbid_direct_connection_example:
+
+.. figure:: ./figures/ecb_forbid_direct_connection_example.png
+
+ Restrictions on building direct connections as part of a connection block
+
+Inter-tile Connections
+~~~~~~~~~~~~~~~~~~~~~~
+
+For this example, we will study a scan-chain implementation. The description could be:
+
+In VPR architecture:
+
+.. code-block:: xml
+
+
+
+
+
+In OpenFPGA architecture:
+
+.. code-block:: xml
+
+
+
+
+
:numref:`fig_p2p_exple` is the graphical representation of the above scan-chain description on a 4x4 FPGA.
.. _fig_p2p_exple:
@@ -91,9 +166,6 @@ For this example, we will study a scan-chain implementation. The description cou
In this figure, the red arrows represent the initial direct connection. The green arrows represent the point to point connection to connect all the columns of CLB.
-Truth table
-~~~~~~~~~~~
-
A point to point connection can be applied in different ways than showed in the example section. To help the designer implement his point to point connection, a truth table with our new parameters id provided below.
:numref:`fig_p2p_trtable` provides all possible variable combination and the connection it will generate.
diff --git a/docs/source/manual/arch_lang/figures/ecb.png b/docs/source/manual/arch_lang/figures/ecb.png
new file mode 100644
index 000000000..5a6afd99c
Binary files /dev/null and b/docs/source/manual/arch_lang/figures/ecb.png differ
diff --git a/docs/source/manual/arch_lang/figures/ecb_allowed_direct_connection.png b/docs/source/manual/arch_lang/figures/ecb_allowed_direct_connection.png
new file mode 100644
index 000000000..bc8e07855
Binary files /dev/null and b/docs/source/manual/arch_lang/figures/ecb_allowed_direct_connection.png differ
diff --git a/docs/source/manual/arch_lang/figures/ecb_allowed_direct_connection_inner_tile_example.png b/docs/source/manual/arch_lang/figures/ecb_allowed_direct_connection_inner_tile_example.png
new file mode 100644
index 000000000..e084cfdff
Binary files /dev/null and b/docs/source/manual/arch_lang/figures/ecb_allowed_direct_connection_inner_tile_example.png differ
diff --git a/docs/source/manual/arch_lang/figures/ecb_allowed_direct_connection_inter_tile_example.png b/docs/source/manual/arch_lang/figures/ecb_allowed_direct_connection_inter_tile_example.png
new file mode 100644
index 000000000..156e8cb20
Binary files /dev/null and b/docs/source/manual/arch_lang/figures/ecb_allowed_direct_connection_inter_tile_example.png differ
diff --git a/docs/source/manual/arch_lang/figures/ecb_forbid_direct_connection_example.png b/docs/source/manual/arch_lang/figures/ecb_forbid_direct_connection_example.png
new file mode 100644
index 000000000..3a2391283
Binary files /dev/null and b/docs/source/manual/arch_lang/figures/ecb_forbid_direct_connection_example.png differ
diff --git a/libs/libarchopenfpga/src/arch_direct.cpp b/libs/libarchopenfpga/src/arch_direct.cpp
index 33565deeb..41ed809b6 100644
--- a/libs/libarchopenfpga/src/arch_direct.cpp
+++ b/libs/libarchopenfpga/src/arch_direct.cpp
@@ -71,7 +71,7 @@ ArchDirectId ArchDirect::add_direct(const std::string& name) {
direct_ids_.push_back(direct);
names_.push_back(name);
circuit_models_.push_back(CircuitModelId::INVALID());
- types_.emplace_back(NUM_DIRECT_TYPES);
+ types_.emplace_back(e_direct_type::NUM_DIRECT_TYPES);
directions_.emplace_back(vtr::Point(
NUM_DIRECT_DIRECTIONS, NUM_DIRECT_DIRECTIONS));
diff --git a/libs/libarchopenfpga/src/arch_direct.h b/libs/libarchopenfpga/src/arch_direct.h
index 5508095eb..2dbe6fce8 100644
--- a/libs/libarchopenfpga/src/arch_direct.h
+++ b/libs/libarchopenfpga/src/arch_direct.h
@@ -14,15 +14,16 @@
* These types are supplementary to the original VPR direct connections
* Here we extend to the cross-row and cross-column connections
********************************************************************/
-enum e_direct_type {
- INNER_COLUMN,
- INNER_ROW,
+enum class e_direct_type {
+ INNER_COLUMN_OR_ROW,
+ PART_OF_CB,
INTER_COLUMN,
INTER_ROW,
NUM_DIRECT_TYPES
};
-constexpr std::array DIRECT_TYPE_STRING = {
- {"inner_column", "inner_row", "inter_column", "inter_row"}};
+constexpr std::array
+ DIRECT_TYPE_STRING = {
+ {"inner_column_or_row", "part_of_cb", "inter_column", "inter_row"}};
enum e_direct_direction { POSITIVE_DIR, NEGATIVE_DIR, NUM_DIRECT_DIRECTIONS };
constexpr std::array
diff --git a/libs/libarchopenfpga/src/read_xml_routing_circuit.cpp b/libs/libarchopenfpga/src/read_xml_routing_circuit.cpp
index 1ac6675b8..0a48531c0 100644
--- a/libs/libarchopenfpga/src/read_xml_routing_circuit.cpp
+++ b/libs/libarchopenfpga/src/read_xml_routing_circuit.cpp
@@ -11,6 +11,7 @@
/* Headers from vtr util library */
#include "vtr_assert.h"
+#include "vtr_log.h"
/* Headers from libarchfpga */
#include "arch_error.h"
@@ -198,15 +199,20 @@ std::map read_xml_routing_segment_circuit(
* Convert string to the enumerate of direct type
*******************************************************************/
static e_direct_type string_to_direct_type(const std::string& type_string) {
- if (std::string("column") == type_string) {
- return INTER_COLUMN;
+ if (std::string("part_of_cb") == type_string) {
+ return e_direct_type::PART_OF_CB;
+ }
+ if (std::string("inner_column_or_row") == type_string) {
+ return e_direct_type::INNER_COLUMN_OR_ROW;
+ }
+ if (std::string("inter_column") == type_string) {
+ return e_direct_type::INTER_COLUMN;
+ }
+ if (std::string("inter_row") == type_string) {
+ return e_direct_type::INTER_ROW;
}
- if (std::string("row") == type_string) {
- return INTER_ROW;
- }
-
- return NUM_DIRECT_TYPES;
+ return e_direct_type::NUM_DIRECT_TYPES;
}
/********************************************************************
@@ -255,13 +261,6 @@ ArchDirect read_xml_direct_circuit(pugi::xml_node& Node,
std::string direct_name =
get_attribute(xml_direct, "name", loc_data).as_string();
- /* Get the routing segment circuit model name */
- std::string direct_model_name =
- get_attribute(xml_direct, "circuit_model_name", loc_data).as_string();
-
- CircuitModelId direct_model = find_routing_circuit_model(
- xml_direct, loc_data, circuit_lib, direct_model_name, CIRCUIT_MODEL_WIRE);
-
/* Add to the Arch direct database */
ArchDirectId direct = arch_direct.add_direct(direct_name);
if (false == arch_direct.valid_direct_id(direct)) {
@@ -269,28 +268,48 @@ ArchDirect read_xml_direct_circuit(pugi::xml_node& Node,
"Direct name '%s' has been defined more than once!\n",
direct_name.c_str());
}
- arch_direct.set_circuit_model(direct, direct_model);
/* Add more information*/
std::string direct_type_name =
get_attribute(xml_direct, "type", loc_data, pugiutil::ReqOpt::OPTIONAL)
- .as_string("none");
- /* If not defined, we go to the next */
- if (std::string("none") == direct_type_name) {
- continue;
- }
+ .as_string(
+ DIRECT_TYPE_STRING[size_t(e_direct_type::INNER_COLUMN_OR_ROW)]);
e_direct_type direct_type = string_to_direct_type(direct_type_name);
- if (NUM_DIRECT_TYPES == direct_type) {
+ if (e_direct_type::NUM_DIRECT_TYPES == direct_type) {
archfpga_throw(
loc_data.filename_c_str(), loc_data.line(xml_direct),
- "Direct type '%s' is not support! Acceptable values are [column|row]\n",
+ "Direct type '%s' is not support! Acceptable values are "
+ "[inner_column_or_row|part_of_cb|inter_column|inter_row]\n",
direct_type_name.c_str());
}
arch_direct.set_type(direct, direct_type);
+ /* Get the routing segment circuit model name */
+ std::string direct_model_name =
+ get_attribute(xml_direct, "circuit_model_name", loc_data).as_string();
+
+ /* If a direct connection is part of a connection block, the circuit model
+ * should be a MUX */
+ e_circuit_model_type expected_circuit_model_type = CIRCUIT_MODEL_WIRE;
+ if (arch_direct.type(direct) == e_direct_type::PART_OF_CB) {
+ VTR_LOG("Direct '%s' will modelled as part of a connection block.\n",
+ direct_name.c_str());
+ expected_circuit_model_type = CIRCUIT_MODEL_MUX;
+ }
+ CircuitModelId direct_model = find_routing_circuit_model(
+ xml_direct, loc_data, circuit_lib, direct_model_name,
+ expected_circuit_model_type);
+ arch_direct.set_circuit_model(direct, direct_model);
+
+ /* The following syntax is only available for inter-column/row */
+ if (arch_direct.type(direct) != e_direct_type::INTER_COLUMN &&
+ arch_direct.type(direct) != e_direct_type::INTER_ROW) {
+ continue;
+ }
+
std::string x_dir_name =
get_attribute(xml_direct, "x_dir", loc_data).as_string();
std::string y_dir_name =
diff --git a/libs/libarchopenfpga/src/write_xml_routing_circuit.cpp b/libs/libarchopenfpga/src/write_xml_routing_circuit.cpp
index 74eb8beac..691bfff6d 100644
--- a/libs/libarchopenfpga/src/write_xml_routing_circuit.cpp
+++ b/libs/libarchopenfpga/src/write_xml_routing_circuit.cpp
@@ -57,7 +57,7 @@ static void write_xml_direct_component_circuit(
fp, "circuit_model_name",
circuit_lib.model_name(arch_direct.circuit_model(direct_id)).c_str());
write_xml_attribute(fp, "type",
- DIRECT_TYPE_STRING[arch_direct.type(direct_id)]);
+ DIRECT_TYPE_STRING[size_t(arch_direct.type(direct_id))]);
write_xml_attribute(fp, "x_dir",
DIRECT_DIRECTION_STRING[arch_direct.x_dir(direct_id)]);
write_xml_attribute(fp, "y_dir",
diff --git a/openfpga/src/annotation/annotate_rr_graph.cpp b/openfpga/src/annotation/annotate_rr_graph.cpp
index 3a904aefd..291d9cd9b 100644
--- a/openfpga/src/annotation/annotate_rr_graph.cpp
+++ b/openfpga/src/annotation/annotate_rr_graph.cpp
@@ -398,6 +398,9 @@ static RRGSB build_rr_gsb(const DeviceContext& vpr_device_ctx,
temp_ipin_rr_nodes.clear();
}
+ /* Build OPIN node lists for connection blocks */
+ rr_gsb.build_cb_opin_nodes(vpr_device_ctx.rr_graph);
+
return rr_gsb;
}
@@ -701,14 +704,26 @@ static void annotate_direct_circuit_models(
}
/* Check the circuit model type */
- if (CIRCUIT_MODEL_WIRE !=
- openfpga_arch.circuit_lib.model_type(circuit_model)) {
+ if (openfpga_arch.arch_direct.type(direct_id) !=
+ e_direct_type::PART_OF_CB &&
+ CIRCUIT_MODEL_WIRE !=
+ openfpga_arch.circuit_lib.model_type(circuit_model)) {
VTR_LOG_ERROR(
"Require circuit model type '%s' for a direct connection '%s'!\nPlease "
"check your OpenFPGA architecture XML!\n",
CIRCUIT_MODEL_TYPE_STRING[CIRCUIT_MODEL_WIRE], direct_name.c_str());
exit(1);
}
+ if (openfpga_arch.arch_direct.type(direct_id) ==
+ e_direct_type::PART_OF_CB &&
+ CIRCUIT_MODEL_MUX !=
+ openfpga_arch.circuit_lib.model_type(circuit_model)) {
+ VTR_LOG_ERROR(
+ "Require circuit model type '%s' for a direct connection '%s'!\nPlease "
+ "check your OpenFPGA architecture XML!\n",
+ CIRCUIT_MODEL_TYPE_STRING[CIRCUIT_MODEL_MUX], direct_name.c_str());
+ exit(1);
+ }
/* Now update the device annotation */
vpr_device_annotation.add_direct_annotation(idirect, direct_id);
diff --git a/openfpga/src/fabric/build_routing_module_utils.cpp b/openfpga/src/fabric/build_routing_module_utils.cpp
index e1f3db9ad..b8f9b4c0d 100644
--- a/openfpga/src/fabric/build_routing_module_utils.cpp
+++ b/openfpga/src/fabric/build_routing_module_utils.cpp
@@ -320,19 +320,58 @@ ModulePortId find_connection_block_module_ipin_port(
return ipin_port_id;
}
+/*********************************************************************
+ * Generate a port for a connection block
+ ********************************************************************/
+ModulePortId find_connection_block_module_opin_port(
+ const ModuleManager& module_manager, const ModuleId& cb_module,
+ const DeviceGrid& grids, const VprDeviceAnnotation& vpr_device_annotation,
+ const RRGraphView& rr_graph, const RRGSB& rr_gsb,
+ const RRNodeId& src_rr_node) {
+ /* Ensure the src_rr_node is an input pin of a CLB */
+ VTR_ASSERT(OPIN == rr_graph.node_type(src_rr_node));
+ /* Search all the sides of a SB, see this drive_rr_node is an INPUT of this SB
+ */
+ enum e_side cb_opin_side = NUM_SIDES;
+ int cb_opin_index = -1;
+ rr_gsb.get_node_side_and_index(rr_graph, src_rr_node, IN_PORT, cb_opin_side,
+ cb_opin_index);
+ /* We need to be sure that drive_rr_node is part of the CB */
+ VTR_ASSERT((-1 != cb_opin_index) && (NUM_SIDES != cb_opin_side));
+ std::string port_name = generate_cb_module_grid_port_name(
+ cb_opin_side, grids, vpr_device_annotation, rr_graph,
+ rr_gsb.get_opin_node(cb_opin_side, cb_opin_index));
+
+ /* Must find a valid port id in the Switch Block module */
+ ModulePortId opin_port_id =
+ module_manager.find_module_port(cb_module, port_name);
+ VTR_ASSERT(true ==
+ module_manager.valid_module_port_id(cb_module, opin_port_id));
+ return opin_port_id;
+}
+
/*********************************************************************
* Generate a list of routing track middle output ports
* for routing multiplexer inside the connection block
********************************************************************/
std::vector find_connection_block_module_input_ports(
const ModuleManager& module_manager, const ModuleId& cb_module,
+ const DeviceGrid& grids, const VprDeviceAnnotation& vpr_device_annotation,
const RRGraphView& rr_graph, const RRGSB& rr_gsb, const t_rr_type& cb_type,
const std::vector& input_rr_nodes) {
std::vector input_ports;
for (auto input_rr_node : input_rr_nodes) {
- input_ports.push_back(find_connection_block_module_chan_port(
- module_manager, cb_module, rr_graph, rr_gsb, cb_type, input_rr_node));
+ if (OPIN == rr_graph.node_type(input_rr_node)) {
+ input_ports.push_back(ModulePinInfo(
+ find_connection_block_module_opin_port(module_manager, cb_module, grids,
+ vpr_device_annotation, rr_graph,
+ rr_gsb, input_rr_node),
+ 0));
+ } else {
+ input_ports.push_back(find_connection_block_module_chan_port(
+ module_manager, cb_module, rr_graph, rr_gsb, cb_type, input_rr_node));
+ }
}
return input_ports;
diff --git a/openfpga/src/fabric/build_routing_module_utils.h b/openfpga/src/fabric/build_routing_module_utils.h
index 8c3907dfa..f2995f27e 100644
--- a/openfpga/src/fabric/build_routing_module_utils.h
+++ b/openfpga/src/fabric/build_routing_module_utils.h
@@ -62,8 +62,15 @@ ModulePortId find_connection_block_module_ipin_port(
const RRGraphView& rr_graph, const RRGSB& rr_gsb,
const RRNodeId& src_rr_node);
+ModulePortId find_connection_block_module_opin_port(
+ const ModuleManager& module_manager, const ModuleId& cb_module,
+ const DeviceGrid& grids, const VprDeviceAnnotation& vpr_device_annotation,
+ const RRGraphView& rr_graph, const RRGSB& rr_gsb,
+ const RRNodeId& src_rr_node);
+
std::vector find_connection_block_module_input_ports(
const ModuleManager& module_manager, const ModuleId& cb_module,
+ const DeviceGrid& grids, const VprDeviceAnnotation& vpr_device_annotation,
const RRGraphView& rr_graph, const RRGSB& rr_gsb, const t_rr_type& cb_type,
const std::vector& input_rr_nodes);
diff --git a/openfpga/src/fabric/build_routing_modules.cpp b/openfpga/src/fabric/build_routing_modules.cpp
index bed03d5fd..6b7cf92a1 100644
--- a/openfpga/src/fabric/build_routing_modules.cpp
+++ b/openfpga/src/fabric/build_routing_modules.cpp
@@ -691,8 +691,9 @@ static void build_connection_block_mux_module(
/* TODO: Generate input ports that are wired to the input bus of the routing
* multiplexer */
std::vector cb_input_port_ids =
- find_connection_block_module_input_ports(
- module_manager, cb_module, rr_graph, rr_gsb, cb_type, driver_rr_nodes);
+ find_connection_block_module_input_ports(module_manager, cb_module, grids,
+ device_annotation, rr_graph,
+ rr_gsb, cb_type, driver_rr_nodes);
/* Link input bus port to Switch Block inputs */
std::vector mux_model_input_ports =
@@ -978,9 +979,7 @@ static void build_connection_block_module(
enum e_side cb_ipin_side = cb_ipin_sides[iside];
for (size_t inode = 0; inode < rr_gsb.get_num_ipin_nodes(cb_ipin_side);
++inode) {
- const RRNodeId& ipin_node = rr_gsb.get_ipin_node(cb_ipin_side, inode);
- vtr::Point port_coord(rr_graph.node_xlow(ipin_node),
- rr_graph.node_ylow(ipin_node));
+ RRNodeId ipin_node = rr_gsb.get_ipin_node(cb_ipin_side, inode);
std::string port_name = generate_cb_module_grid_port_name(
cb_ipin_side, grids, device_annotation, rr_graph, ipin_node);
BasicPort module_port(port_name,
@@ -993,6 +992,29 @@ static void build_connection_block_module(
}
}
+ /* Add the output pins of grids which are input ports of the connection block,
+ * if there is any */
+ std::vector opin_module_port_ids;
+ std::vector cb_opin_sides = rr_gsb.get_cb_opin_sides(cb_type);
+ for (size_t iside = 0; iside < cb_opin_sides.size(); ++iside) {
+ enum e_side cb_opin_side = cb_opin_sides[iside];
+ for (size_t inode = 0;
+ inode < rr_gsb.get_num_cb_opin_nodes(cb_type, cb_opin_side); ++inode) {
+ RRNodeId opin_node =
+ rr_gsb.get_cb_opin_node(cb_type, cb_opin_side, inode);
+ std::string port_name = generate_cb_module_grid_port_name(
+ cb_opin_side, grids, device_annotation, rr_graph, opin_node);
+ BasicPort module_port(port_name,
+ 1); /* Every grid output has a port size of 1 */
+ /* Grid outputs are inputs of switch blocks */
+ ModulePortId module_port_id = module_manager.add_port(
+ cb_module, module_port, ModuleManager::MODULE_INPUT_PORT);
+ /* Add side to the port */
+ module_manager.set_port_side(cb_module, module_port_id, cb_opin_side);
+ opin_module_port_ids.push_back(module_port_id);
+ }
+ }
+
/* Create a cache (fast look up) for module nets whose source are input ports
*/
std::map input_port_to_module_nets;
@@ -1034,6 +1056,13 @@ static void build_connection_block_module(
chan_lower_input_port_id, chan_lower_input_port.pins()[pin_id])] = net;
}
+ for (ModulePortId opin_module_port_id : opin_module_port_ids) {
+ ModuleNetId net = create_module_source_pin_net(
+ module_manager, cb_module, cb_module, 0, opin_module_port_id, 0);
+ /* Cache the module net */
+ input_port_to_module_nets[ModulePinInfo(opin_module_port_id, 0)] = net;
+ }
+
/* Add sub modules of routing multiplexers or direct interconnect*/
for (size_t iside = 0; iside < cb_ipin_sides.size(); ++iside) {
enum e_side cb_ipin_side = cb_ipin_sides[iside];
diff --git a/openfpga/src/fabric/build_tile_modules.cpp b/openfpga/src/fabric/build_tile_modules.cpp
index 277295868..74797aa39 100644
--- a/openfpga/src/fabric/build_tile_modules.cpp
+++ b/openfpga/src/fabric/build_tile_modules.cpp
@@ -471,6 +471,158 @@ static int build_tile_module_port_and_nets_between_cb_and_pb(
}
}
}
+ /* Iterate over the output pins of the Connection Block */
+ std::vector cb_opin_sides = module_cb.get_cb_opin_sides(cb_type);
+ for (size_t iside = 0; iside < cb_opin_sides.size(); ++iside) {
+ enum e_side cb_opin_side = cb_opin_sides[iside];
+ for (size_t inode = 0;
+ inode < module_cb.get_num_cb_opin_nodes(cb_type, cb_opin_side);
+ ++inode) {
+ /* Collect source-related information */
+ RRNodeId module_opin_node =
+ module_cb.get_cb_opin_node(cb_type, cb_opin_side, inode);
+ vtr::Point cb_src_port_coord(
+ rr_graph.node_xlow(module_opin_node),
+ rr_graph.node_ylow(module_opin_node));
+ std::string src_cb_port_name = generate_cb_module_grid_port_name(
+ cb_opin_side, grids, vpr_device_annotation, rr_graph, module_opin_node);
+ ModulePortId src_cb_port_id =
+ module_manager.find_module_port(src_cb_module, src_cb_port_name);
+ VTR_ASSERT(true == module_manager.valid_module_port_id(src_cb_module,
+ src_cb_port_id));
+ BasicPort src_cb_port =
+ module_manager.module_port(src_cb_module, src_cb_port_id);
+
+ /* Collect sink-related information */
+ /* Note that we use the instance cb pin here!!!
+ * because it has the correct coordinator for the grid!!!
+ */
+ RRNodeId instance_opin_node =
+ rr_gsb.get_cb_opin_node(cb_type, cb_opin_side, inode);
+ vtr::Point grid_coordinate(
+ rr_graph.node_xlow(instance_opin_node),
+ rr_graph.node_ylow(instance_opin_node));
+ std::string sink_grid_module_name =
+ generate_grid_block_module_name_in_top_module(
+ std::string(GRID_MODULE_NAME_PREFIX), grids, grid_coordinate);
+ ModuleId sink_grid_module =
+ module_manager.find_module(sink_grid_module_name);
+ VTR_ASSERT(true == module_manager.valid_module_id(sink_grid_module));
+ size_t sink_grid_pin_index = rr_graph.node_pin_num(instance_opin_node);
+
+ t_physical_tile_type_ptr grid_type_descriptor = grids.get_physical_type(
+ t_physical_tile_loc(grid_coordinate.x(), grid_coordinate.y(), layer));
+ size_t sink_grid_pin_width =
+ grid_type_descriptor->pin_width_offset[sink_grid_pin_index];
+ size_t sink_grid_pin_height =
+ grid_type_descriptor->pin_height_offset[sink_grid_pin_index];
+ BasicPort sink_grid_pin_info =
+ vpr_device_annotation.physical_tile_pin_port_info(grid_type_descriptor,
+ sink_grid_pin_index);
+ VTR_ASSERT(true == sink_grid_pin_info.is_valid());
+ int subtile_index = vpr_device_annotation.physical_tile_pin_subtile_index(
+ grid_type_descriptor, sink_grid_pin_index);
+ VTR_ASSERT(OPEN != subtile_index &&
+ subtile_index < grid_type_descriptor->capacity);
+ std::string sink_grid_port_name = generate_grid_port_name(
+ sink_grid_pin_width, sink_grid_pin_height, subtile_index,
+ get_rr_graph_single_node_side(
+ rr_graph, rr_gsb.get_cb_opin_node(cb_type, cb_opin_side, inode)),
+ sink_grid_pin_info);
+ ModulePortId sink_grid_port_id =
+ module_manager.find_module_port(sink_grid_module, sink_grid_port_name);
+ VTR_ASSERT(true == module_manager.valid_module_port_id(
+ sink_grid_module, sink_grid_port_id));
+ BasicPort sink_grid_port =
+ module_manager.module_port(sink_grid_module, sink_grid_port_id);
+
+ /* Check if the grid is inside the tile, if not, create ports */
+ if (fabric_tile.pb_in_tile(fabric_tile_id, grid_coordinate)) {
+ if (!frame_view) {
+ size_t sink_grid_instance =
+ pb_instances[fabric_tile.find_pb_index_in_tile(fabric_tile_id,
+ grid_coordinate)];
+
+ /* Source and sink port should match in size */
+ VTR_ASSERT(src_cb_port.get_width() == sink_grid_port.get_width());
+
+ /* Create a net for each pin. Note that the sink and source tags are
+ * reverted in the following code!!! */
+ for (size_t pin_id = 0; pin_id < src_cb_port.pins().size();
+ ++pin_id) {
+ ModuleNetId net = create_module_source_pin_net(
+ module_manager, tile_module, sink_grid_module, sink_grid_instance,
+ sink_grid_port_id, sink_grid_port.pins()[pin_id]);
+ /* Configure the net sink */
+ module_manager.add_module_net_sink(tile_module, net, src_cb_module,
+ src_cb_instance, src_cb_port_id,
+ src_cb_port.pins()[pin_id]);
+ }
+ }
+ } else {
+ /* Special: No need to create a new port! Since we only support OPINs
+ * from Switch blocks. Walk through all the switch blocks and find the
+ * new port that it is created when connecting pb and sb */
+ if (!frame_view) {
+ /* This is the source sb that is added to the top module */
+ const RRGSB& module_sb = device_rr_gsb.get_gsb(module_gsb_coordinate);
+ vtr::Point module_sb_coordinate(module_sb.get_sb_x(),
+ module_sb.get_sb_y());
+
+ /* Collect sink-related information */
+ std::string sink_sb_module_name =
+ generate_switch_block_module_name(module_sb_coordinate);
+ ModuleId sink_sb_module =
+ module_manager.find_module(sink_sb_module_name);
+ VTR_ASSERT(true == module_manager.valid_module_id(sink_sb_module));
+ size_t isb = fabric_tile.find_sb_index_in_tile(fabric_tile_id,
+ module_sb_coordinate);
+ std::string temp_sb_module_name = generate_switch_block_module_name(
+ fabric_tile.sb_coordinates(fabric_tile_id)[isb]);
+ if (name_module_using_index) {
+ temp_sb_module_name =
+ generate_switch_block_module_name_using_index(isb);
+ }
+ /* FIXME: may find a way to determine the side. Currently using
+ * cb_opin_side is fine */
+ vtr::Point sink_sb_port_coord(
+ rr_graph.node_xlow(module_sb.get_opin_node(cb_opin_side, inode)),
+ rr_graph.node_ylow(module_sb.get_opin_node(cb_opin_side, inode)));
+ std::string sink_sb_port_name = generate_sb_module_grid_port_name(
+ cb_opin_side,
+ get_rr_graph_single_node_side(
+ rr_graph, module_sb.get_opin_node(cb_opin_side, inode)),
+ grids, vpr_device_annotation, rr_graph,
+ module_sb.get_opin_node(cb_opin_side, inode));
+ ModulePortId sink_sb_port_id =
+ module_manager.find_module_port(sink_sb_module, sink_sb_port_name);
+ VTR_ASSERT(true == module_manager.valid_module_port_id(
+ sink_sb_module, sink_sb_port_id));
+ BasicPort sink_sb_port =
+ module_manager.module_port(sink_sb_module, sink_sb_port_id);
+
+ sink_sb_port.set_name(generate_tile_module_port_name(
+ temp_sb_module_name, sink_sb_port.get_name()));
+ ModulePortId src_tile_port_id = module_manager.find_module_port(
+ tile_module, sink_sb_port.get_name());
+
+ /* Create a net for each pin */
+ VTR_ASSERT(src_cb_port.pins().size() == sink_sb_port.pins().size());
+ for (size_t pin_id = 0; pin_id < src_cb_port.pins().size();
+ ++pin_id) {
+ ModuleNetId net = create_module_source_pin_net(
+ module_manager, tile_module, tile_module, 0, src_tile_port_id,
+ sink_sb_port.pins()[pin_id]);
+ /* Configure the net sink */
+ module_manager.add_module_net_sink(tile_module, net, src_cb_module,
+ src_cb_instance, src_cb_port_id,
+ src_cb_port.pins()[pin_id]);
+ }
+ }
+ }
+ }
+ }
+
return CMD_EXEC_SUCCESS;
}
diff --git a/openfpga/src/fabric/build_top_module_connection.cpp b/openfpga/src/fabric/build_top_module_connection.cpp
index 98b256fe0..84c901945 100644
--- a/openfpga/src/fabric/build_top_module_connection.cpp
+++ b/openfpga/src/fabric/build_top_module_connection.cpp
@@ -563,6 +563,90 @@ static void add_top_module_nets_connect_grids_and_cb(
}
}
}
+
+ /* Iterate over the input pins of the Connection Block */
+ std::vector cb_opin_sides = module_cb.get_cb_opin_sides(cb_type);
+ for (size_t iside = 0; iside < cb_opin_sides.size(); ++iside) {
+ enum e_side cb_opin_side = cb_opin_sides[iside];
+ for (size_t inode = 0;
+ inode < module_cb.get_num_cb_opin_nodes(cb_type, cb_opin_side);
+ ++inode) {
+ /* Collect source-related information */
+ RRNodeId module_opin_node =
+ module_cb.get_cb_opin_node(cb_type, cb_opin_side, inode);
+ vtr::Point cb_src_port_coord(
+ rr_graph.node_xlow(module_opin_node),
+ rr_graph.node_ylow(module_opin_node));
+ std::string src_cb_port_name = generate_cb_module_grid_port_name(
+ cb_opin_side, grids, vpr_device_annotation, rr_graph, module_opin_node);
+ ModulePortId src_cb_port_id =
+ module_manager.find_module_port(src_cb_module, src_cb_port_name);
+ VTR_ASSERT(true == module_manager.valid_module_port_id(src_cb_module,
+ src_cb_port_id));
+ BasicPort src_cb_port =
+ module_manager.module_port(src_cb_module, src_cb_port_id);
+
+ /* Collect sink-related information */
+ /* Note that we use the instance cb pin here!!!
+ * because it has the correct coordinator for the grid!!!
+ */
+ RRNodeId instance_opin_node =
+ rr_gsb.get_cb_opin_node(cb_type, cb_opin_side, inode);
+ vtr::Point grid_coordinate(
+ rr_graph.node_xlow(instance_opin_node),
+ rr_graph.node_ylow(instance_opin_node));
+ std::string sink_grid_module_name =
+ generate_grid_block_module_name_in_top_module(
+ std::string(GRID_MODULE_NAME_PREFIX), grids, grid_coordinate);
+ ModuleId sink_grid_module =
+ module_manager.find_module(sink_grid_module_name);
+ VTR_ASSERT(true == module_manager.valid_module_id(sink_grid_module));
+ size_t sink_grid_instance =
+ grid_instance_ids[grid_coordinate.x()][grid_coordinate.y()];
+ size_t sink_grid_pin_index = rr_graph.node_pin_num(instance_opin_node);
+
+ t_physical_tile_type_ptr grid_type_descriptor = grids.get_physical_type(
+ t_physical_tile_loc(grid_coordinate.x(), grid_coordinate.y(), layer));
+ size_t sink_grid_pin_width =
+ grid_type_descriptor->pin_width_offset[sink_grid_pin_index];
+ size_t sink_grid_pin_height =
+ grid_type_descriptor->pin_height_offset[sink_grid_pin_index];
+ BasicPort sink_grid_pin_info =
+ vpr_device_annotation.physical_tile_pin_port_info(grid_type_descriptor,
+ sink_grid_pin_index);
+ VTR_ASSERT(true == sink_grid_pin_info.is_valid());
+ int subtile_index = vpr_device_annotation.physical_tile_pin_subtile_index(
+ grid_type_descriptor, sink_grid_pin_index);
+ VTR_ASSERT(OPEN != subtile_index &&
+ subtile_index < grid_type_descriptor->capacity);
+ std::string sink_grid_port_name = generate_grid_port_name(
+ sink_grid_pin_width, sink_grid_pin_height, subtile_index,
+ get_rr_graph_single_node_side(
+ rr_graph, rr_gsb.get_cb_opin_node(cb_type, cb_opin_side, inode)),
+ sink_grid_pin_info);
+ ModulePortId sink_grid_port_id =
+ module_manager.find_module_port(sink_grid_module, sink_grid_port_name);
+ VTR_ASSERT(true == module_manager.valid_module_port_id(
+ sink_grid_module, sink_grid_port_id));
+ BasicPort sink_grid_port =
+ module_manager.module_port(sink_grid_module, sink_grid_port_id);
+
+ /* Source and sink port should match in size */
+ VTR_ASSERT(src_cb_port.get_width() == sink_grid_port.get_width());
+
+ /* Create a net for each pin. Note that the src/sink tag is reverted in
+ * the following code. */
+ for (size_t pin_id = 0; pin_id < src_cb_port.pins().size(); ++pin_id) {
+ ModuleNetId net = create_module_source_pin_net(
+ module_manager, top_module, sink_grid_module, sink_grid_instance,
+ sink_grid_port_id, sink_grid_port.pins()[pin_id]);
+ /* Configure the net sink */
+ module_manager.add_module_net_sink(top_module, net, src_cb_module,
+ src_cb_instance, src_cb_port_id,
+ src_cb_port.pins()[pin_id]);
+ }
+ }
+ }
}
/********************************************************************
diff --git a/openfpga/src/fpga_sdc/pnr_sdc_routing_writer.cpp b/openfpga/src/fpga_sdc/pnr_sdc_routing_writer.cpp
index 1f56da15e..1002da4b0 100644
--- a/openfpga/src/fpga_sdc/pnr_sdc_routing_writer.cpp
+++ b/openfpga/src/fpga_sdc/pnr_sdc_routing_writer.cpp
@@ -317,8 +317,9 @@ static void print_pnr_sdc_constrain_cb_mux_timing(
/* Find the module port corresponding to the fan-in rr_nodes of the output
* rr_node */
std::vector module_input_ports =
- find_connection_block_module_input_ports(
- module_manager, cb_module, rr_graph, rr_gsb, cb_type, input_rr_nodes);
+ find_connection_block_module_input_ports(module_manager, cb_module, grids,
+ device_annotation, rr_graph,
+ rr_gsb, cb_type, input_rr_nodes);
/* Find timing constraints for each path (edge) */
std::map switch_delays;
diff --git a/openfpga/src/tile_direct/build_tile_direct.cpp b/openfpga/src/tile_direct/build_tile_direct.cpp
index 73b5fd77a..357c0a25c 100644
--- a/openfpga/src/tile_direct/build_tile_direct.cpp
+++ b/openfpga/src/tile_direct/build_tile_direct.cpp
@@ -197,7 +197,7 @@ static vtr::Point find_inter_direct_destination_coordinate(
* Our search space will start from the next column
* and ends at the RIGHT side of fabric
*/
- if (INTER_COLUMN == arch_direct.type(arch_direct_id)) {
+ if (e_direct_type::INTER_COLUMN == arch_direct.type(arch_direct_id)) {
if (POSITIVE_DIR == arch_direct.x_dir(arch_direct_id)) {
/* Our first search space will be in x-direction:
*
@@ -262,7 +262,7 @@ static vtr::Point find_inter_direct_destination_coordinate(
* Our search space will start from the next column
* and ends at the RIGHT side of fabric
*/
- if (INTER_ROW == arch_direct.type(arch_direct_id)) {
+ if (e_direct_type::INTER_ROW == arch_direct.type(arch_direct_id)) {
if (POSITIVE_DIR == arch_direct.y_dir(arch_direct_id)) {
/* Our first search space will be in y-direction:
*
@@ -326,10 +326,11 @@ static vtr::Point find_inter_direct_destination_coordinate(
for (size_t ix : first_search_space) {
std::vector> next_col_row_coords;
for (size_t iy : second_search_space) {
- if (INTER_COLUMN == arch_direct.type(arch_direct_id)) {
+ if (e_direct_type::INTER_COLUMN == arch_direct.type(arch_direct_id)) {
next_col_row_coords.push_back(vtr::Point(ix, iy));
} else {
- VTR_ASSERT(INTER_ROW == arch_direct.type(arch_direct_id));
+ VTR_ASSERT(e_direct_type::INTER_ROW ==
+ arch_direct.type(arch_direct_id));
/* For cross-row connection, our search space is flipped */
next_col_row_coords.push_back(vtr::Point(iy, ix));
}
@@ -549,8 +550,8 @@ static void build_inter_column_row_tile_direct(
/* Go through the direct connection list, see if we need intra-column/row
* connection here */
- if ((INTER_COLUMN != arch_direct.type(arch_direct_id)) &&
- (INTER_ROW != arch_direct.type(arch_direct_id))) {
+ if ((e_direct_type::INTER_COLUMN != arch_direct.type(arch_direct_id)) &&
+ (e_direct_type::INTER_ROW != arch_direct.type(arch_direct_id))) {
return;
}
/* For cross-column connection, we will search the first valid grid in each
@@ -568,7 +569,7 @@ static void build_inter_column_row_tile_direct(
* +------+
*
*/
- if (INTER_COLUMN == arch_direct.type(arch_direct_id)) {
+ if (e_direct_type::INTER_COLUMN == arch_direct.type(arch_direct_id)) {
for (size_t ix = 1; ix < device_ctx.grid.width() - 1; ++ix) {
std::vector> next_col_src_grid_coords;
/* For negative y- direction, we should start from y = ny */
@@ -671,7 +672,7 @@ static void build_inter_column_row_tile_direct(
}
/* Reach here, it must be a cross-row connection */
- VTR_ASSERT(INTER_ROW == arch_direct.type(arch_direct_id));
+ VTR_ASSERT(e_direct_type::INTER_ROW == arch_direct.type(arch_direct_id));
/* For cross-row connection, we will search the first valid grid in each
* column from x = 1 to x = nx
*
@@ -804,9 +805,14 @@ TileDirect build_device_tile_direct(const DeviceContext& device_ctx,
exit(1);
}
/* Build from original VPR arch definition */
- build_inner_column_row_tile_direct(tile_direct,
- device_ctx.arch->Directs[idirect],
- device_ctx, arch_direct_id, verbose);
+ if (e_direct_type::INNER_COLUMN_OR_ROW ==
+ arch_direct.type(arch_direct_id)) {
+ build_inner_column_row_tile_direct(tile_direct,
+ device_ctx.arch->Directs[idirect],
+ device_ctx, arch_direct_id, verbose);
+ /* Skip those direct connections which belong part of a connection block
+ */
+ }
/* Build from OpenFPGA arch definition */
build_inter_column_row_tile_direct(
tile_direct, device_ctx.arch->Directs[idirect], device_ctx, arch_direct,
diff --git a/openfpga_flow/openfpga_arch/README.md b/openfpga_flow/openfpga_arch/README.md
index b23e837ec..a2cc2f6ee 100644
--- a/openfpga_flow/openfpga_arch/README.md
+++ b/openfpga_flow/openfpga_arch/README.md
@@ -37,5 +37,6 @@ Note that an OpenFPGA architecture can be applied to multiple VPR architecture f
* is the number of clocks
* When specified, multiple clocks are in separated pins with different names
- abspath: All the paths in the architecture file are absolute and hardcoded.
+- ecb: *Enhanced Connection Block* where connection blocks includes feedback connections
Other features are used in naming should be listed here.
diff --git a/openfpga_flow/openfpga_arch/k4_N4_ecb_40nm_cc_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_ecb_40nm_cc_openfpga.xml
new file mode 100644
index 000000000..12842a05b
--- /dev/null
+++ b/openfpga_flow/openfpga_arch/k4_N4_ecb_40nm_cc_openfpga.xml
@@ -0,0 +1,253 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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_N4_adder_chain_40nm_cc_abspath_openfpga.xml b/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_40nm_cc_abspath_openfpga.xml
index 254f3fcac..a3b49f374 100644
--- a/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_40nm_cc_abspath_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_40nm_cc_abspath_openfpga.xml
@@ -210,7 +210,7 @@
-
+
diff --git a/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_40nm_cc_openfpga.xml b/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_40nm_cc_openfpga.xml
index 8cb766b67..51af075ea 100644
--- a/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_40nm_cc_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_40nm_cc_openfpga.xml
@@ -210,7 +210,7 @@
-
+
diff --git a/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_mem1K_40nm_frame_openfpga.xml b/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_mem1K_40nm_frame_openfpga.xml
index aaddef305..32996800e 100644
--- a/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_mem1K_40nm_frame_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_mem1K_40nm_frame_openfpga.xml
@@ -222,7 +222,7 @@
-
+
diff --git a/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_mem1K_L124X_L12Y_40nm_frame_openfpga.xml b/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_mem1K_L124X_L12Y_40nm_frame_openfpga.xml
index f489b97f5..6d3e3c45f 100644
--- a/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_mem1K_L124X_L12Y_40nm_frame_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_mem1K_L124X_L12Y_40nm_frame_openfpga.xml
@@ -228,7 +228,7 @@
-
+
diff --git a/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_mem1K_L124_40nm_frame_openfpga.xml b/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_mem1K_L124_40nm_frame_openfpga.xml
index 444615016..b6752970f 100644
--- a/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_mem1K_L124_40nm_frame_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_mem1K_L124_40nm_frame_openfpga.xml
@@ -226,7 +226,7 @@
-
+
diff --git a/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_mem1K_frac_dsp32_40nm_frame_openfpga.xml b/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_mem1K_frac_dsp32_40nm_frame_openfpga.xml
index 0fcbfba3f..203d8e179 100644
--- a/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_mem1K_frac_dsp32_40nm_frame_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k4_frac_N4_adder_chain_mem1K_frac_dsp32_40nm_frame_openfpga.xml
@@ -232,7 +232,7 @@
-
+
diff --git a/openfpga_flow/openfpga_arch/k4_frac_N8_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml b/openfpga_flow/openfpga_arch/k4_frac_N8_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
index 81ae2b79d..50b4c6e6b 100644
--- a/openfpga_flow/openfpga_arch/k4_frac_N8_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k4_frac_N8_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
@@ -213,8 +213,8 @@
-
-
+
+
diff --git a/openfpga_flow/openfpga_arch/k4_frac_N8_register_scan_chain_embedded_io_skywater130nm_fdhd_cc_openfpga.xml b/openfpga_flow/openfpga_arch/k4_frac_N8_register_scan_chain_embedded_io_skywater130nm_fdhd_cc_openfpga.xml
index c19f4c2cf..f4b3b0733 100644
--- a/openfpga_flow/openfpga_arch/k4_frac_N8_register_scan_chain_embedded_io_skywater130nm_fdhd_cc_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k4_frac_N8_register_scan_chain_embedded_io_skywater130nm_fdhd_cc_openfpga.xml
@@ -217,8 +217,8 @@
-
-
+
+
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 86cf97c3c..bd122d3c9 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
@@ -215,7 +215,7 @@
-
+
diff --git a/openfpga_flow/openfpga_arch/k4_frac_N8_reset_softadderSuperLUT_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml b/openfpga_flow/openfpga_arch/k4_frac_N8_reset_softadderSuperLUT_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
index 0e503f00a..f889f2de6 100644
--- a/openfpga_flow/openfpga_arch/k4_frac_N8_reset_softadderSuperLUT_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k4_frac_N8_reset_softadderSuperLUT_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
@@ -230,7 +230,7 @@
-
+
diff --git a/openfpga_flow/openfpga_arch/k4_frac_N8_reset_softadder_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml b/openfpga_flow/openfpga_arch/k4_frac_N8_reset_softadder_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
index fa4ddb9be..8b89cf9a0 100644
--- a/openfpga_flow/openfpga_arch/k4_frac_N8_reset_softadder_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k4_frac_N8_reset_softadder_register_scan_chain_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
@@ -227,7 +227,7 @@
-
+
diff --git a/openfpga_flow/openfpga_arch/k4_frac_N8_reset_softadder_register_scan_chain_dsp8_caravel_io_skywater130nm_fdhd_cc_openfpga.xml b/openfpga_flow/openfpga_arch/k4_frac_N8_reset_softadder_register_scan_chain_dsp8_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
index 35ac32ced..7e659a631 100644
--- a/openfpga_flow/openfpga_arch/k4_frac_N8_reset_softadder_register_scan_chain_dsp8_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k4_frac_N8_reset_softadder_register_scan_chain_dsp8_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
@@ -235,7 +235,7 @@
-
+
diff --git a/openfpga_flow/openfpga_arch/k4_frac_N8_reset_softadder_register_scan_chain_frac_dsp16_caravel_io_skywater130nm_fdhd_cc_openfpga.xml b/openfpga_flow/openfpga_arch/k4_frac_N8_reset_softadder_register_scan_chain_frac_dsp16_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
index 3beae9929..b2d6da19d 100644
--- a/openfpga_flow/openfpga_arch/k4_frac_N8_reset_softadder_register_scan_chain_frac_dsp16_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k4_frac_N8_reset_softadder_register_scan_chain_frac_dsp16_caravel_io_skywater130nm_fdhd_cc_openfpga.xml
@@ -236,7 +236,7 @@
-
+
diff --git a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_40nm_openfpga.xml b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_40nm_openfpga.xml
index be02a50e5..09dcb1b50 100644
--- a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_40nm_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_40nm_openfpga.xml
@@ -211,7 +211,7 @@
-
+
diff --git a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_dpram8K_dsp36_40nm_openfpga.xml b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_dpram8K_dsp36_40nm_openfpga.xml
index a64e19c82..1f7f137c3 100644
--- a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_dpram8K_dsp36_40nm_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_dpram8K_dsp36_40nm_openfpga.xml
@@ -233,7 +233,7 @@
-
+
diff --git a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_dpram8K_dsp36_fracff_40nm_openfpga.xml b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_dpram8K_dsp36_fracff_40nm_openfpga.xml
index 0812ecff9..831cf161e 100644
--- a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_dpram8K_dsp36_fracff_40nm_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_dpram8K_dsp36_fracff_40nm_openfpga.xml
@@ -234,7 +234,7 @@
-
+
diff --git a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_frac_mem32K_frac_dsp36_40nm_GlobalTile8Clk_openfpga.xml b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_frac_mem32K_frac_dsp36_40nm_GlobalTile8Clk_openfpga.xml
index 1997ab1f3..974a92928 100644
--- a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_frac_mem32K_frac_dsp36_40nm_GlobalTile8Clk_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_frac_mem32K_frac_dsp36_40nm_GlobalTile8Clk_openfpga.xml
@@ -237,7 +237,7 @@
-
+
diff --git a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_frac_mem32K_frac_dsp36_40nm_openfpga.xml b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_frac_mem32K_frac_dsp36_40nm_openfpga.xml
index 1d4a2cdb9..9cc2a0dfb 100644
--- a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_frac_mem32K_frac_dsp36_40nm_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_frac_mem32K_frac_dsp36_40nm_openfpga.xml
@@ -237,7 +237,7 @@
-
+
diff --git a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_mem16K_40nm_openfpga.xml b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_mem16K_40nm_openfpga.xml
index 1ac39cda0..d0567bb2f 100644
--- a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_mem16K_40nm_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_mem16K_40nm_openfpga.xml
@@ -223,7 +223,7 @@
-
+
diff --git a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_mem16K_aib_40nm_openfpga.xml b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_mem16K_aib_40nm_openfpga.xml
index 2ff4c6a0c..476850d6e 100644
--- a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_mem16K_aib_40nm_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_mem16K_aib_40nm_openfpga.xml
@@ -233,7 +233,7 @@
-
+
diff --git a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_mem1K_40nm_openfpga.xml b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_mem1K_40nm_openfpga.xml
index dfe1c060e..55237a608 100644
--- a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_mem1K_40nm_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_chain_mem1K_40nm_openfpga.xml
@@ -223,7 +223,7 @@
-
+
diff --git a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_chain_40nm_openfpga.xml b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_chain_40nm_openfpga.xml
index 3684157b6..50b7f9a34 100644
--- a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_chain_40nm_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_chain_40nm_openfpga.xml
@@ -211,8 +211,8 @@
-
-
+
+
diff --git a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_scan_chain_40nm_openfpga.xml b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_scan_chain_40nm_openfpga.xml
index 44470f17b..dbb527899 100644
--- a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_scan_chain_40nm_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_scan_chain_40nm_openfpga.xml
@@ -216,9 +216,9 @@
-
-
-
+
+
+
diff --git a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_scan_chain_depop50_40nm_openfpga.xml b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_scan_chain_depop50_40nm_openfpga.xml
index 624868489..21622bc56 100644
--- a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_scan_chain_depop50_40nm_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_scan_chain_depop50_40nm_openfpga.xml
@@ -217,7 +217,7 @@
-
+
diff --git a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_scan_chain_depop50_spypad_40nm_openfpga.xml b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_scan_chain_depop50_spypad_40nm_openfpga.xml
index 48f45f94c..440d0a2ae 100644
--- a/openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_scan_chain_depop50_spypad_40nm_openfpga.xml
+++ b/openfpga_flow/openfpga_arch/k6_frac_N10_adder_register_scan_chain_depop50_spypad_40nm_openfpga.xml
@@ -232,7 +232,7 @@
-
+
diff --git a/openfpga_flow/regression_test_scripts/basic_reg_test.sh b/openfpga_flow/regression_test_scripts/basic_reg_test.sh
index 635cb2767..c4b3ebcb8 100755
--- a/openfpga_flow/regression_test_scripts/basic_reg_test.sh
+++ b/openfpga_flow/regression_test_scripts/basic_reg_test.sh
@@ -175,6 +175,8 @@ echo -e "Testing K4N4 support clock generation by internal resources";
run-task basic_tests/k4_series/k4n4_clk_gen $@
echo -e "Testing K4N4 support reset generation by internal resources";
run-task basic_tests/k4_series/k4n4_rst_gen $@
+echo -e "Testing enhanced connection blocks"
+run-task basic_tests/k4_series/k4n4_ecb $@
echo -e "Testing different tile organizations";
echo -e "Testing tiles with pins only on top and left sides";
@@ -199,6 +201,7 @@ run-task basic_tests/tile_organization/homo_fabric_tile_global_tile_clock $@
run-task basic_tests/tile_organization/homo_fabric_tile_adder_chain $@
run-task basic_tests/tile_organization/homo_fabric_tile_clkntwk $@
run-task basic_tests/tile_organization/hetero_fabric_tile $@
+run-task basic_tests/tile_organization/homo_fabric_tile_ecb_2x2_preconfig $@
echo -e "Testing group config block";
run-task basic_tests/group_config_block/group_config_block_homo_full_testbench $@
diff --git a/openfpga_flow/tasks/basic_tests/k4_series/k4n4_ecb/config/task.conf b/openfpga_flow/tasks/basic_tests/k4_series/k4n4_ecb/config/task.conf
new file mode 100644
index 000000000..87f77596d
--- /dev/null
+++ b/openfpga_flow/tasks/basic_tests/k4_series/k4n4_ecb/config/task.conf
@@ -0,0 +1,37 @@
+# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
+# 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 = false
+spice_output=false
+verilog_output=true
+timeout_each_job = 20*60
+fpga_flow=vpr_blif
+
+[OpenFPGA_SHELL]
+openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/fix_heterogeneous_device_pbPinFixup_example_script.openfpga
+openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_ecb_40nm_cc_openfpga.xml
+openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml
+openfpga_vpr_device_layout=2x2
+
+[ARCHITECTURES]
+arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_ecb_tileable_TileOrgzBr_40nm.xml
+
+[BENCHMARKS]
+bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.blif
+
+[SYNTHESIS_PARAM]
+bench0_top = and2
+bench0_act = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.act
+bench0_verilog = ${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
+
+[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
+end_flow_with_test=
+vpr_fpga_verilog_formal_verification_top_netlist=
diff --git a/openfpga_flow/tasks/basic_tests/tile_organization/homo_fabric_tile_ecb_2x2_preconfig/config/task.conf b/openfpga_flow/tasks/basic_tests/tile_organization/homo_fabric_tile_ecb_2x2_preconfig/config/task.conf
new file mode 100644
index 000000000..8f1b5aa53
--- /dev/null
+++ b/openfpga_flow/tasks/basic_tests/tile_organization/homo_fabric_tile_ecb_2x2_preconfig/config/task.conf
@@ -0,0 +1,41 @@
+# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
+# 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 = false
+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/group_tile_preconfig_testbench_example_script.openfpga
+openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_ecb_40nm_cc_openfpga.xml
+openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/fixed_sim_openfpga.xml
+openfpga_vpr_extra_options=--skip_sync_clustering_and_routing_results on
+openfpga_pb_pin_fixup_command=pb_pin_fixup
+openfpga_vpr_device=2x2
+openfpga_vpr_route_chan_width=20
+openfpga_group_tile_config_file=${PATH:TASK_DIR}/config/tile_config.xml
+openfpga_verilog_testbench_options=--explicit_port_mapping
+
+[ARCHITECTURES]
+arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_ecb_tileable_TileOrgzBr_40nm.xml
+
+[BENCHMARKS]
+bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/or2/or2.v
+
+[SYNTHESIS_PARAM]
+bench_read_verilog_options_common = -nolatches
+bench0_top = or2
+
+[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
+end_flow_with_test=
+vpr_fpga_verilog_formal_verification_top_netlist=
diff --git a/openfpga_flow/tasks/basic_tests/tile_organization/homo_fabric_tile_ecb_2x2_preconfig/config/tile_config.xml b/openfpga_flow/tasks/basic_tests/tile_organization/homo_fabric_tile_ecb_2x2_preconfig/config/tile_config.xml
new file mode 100644
index 000000000..1a1f3f6e8
--- /dev/null
+++ b/openfpga_flow/tasks/basic_tests/tile_organization/homo_fabric_tile_ecb_2x2_preconfig/config/tile_config.xml
@@ -0,0 +1 @@
+
diff --git a/openfpga_flow/vpr_arch/README.md b/openfpga_flow/vpr_arch/README.md
index 65f3c3d55..7f8a000b5 100644
--- a/openfpga_flow/vpr_arch/README.md
+++ b/openfpga_flow/vpr_arch/README.md
@@ -33,6 +33,7 @@ Please reveal the following architecture features in the names to help quickly s
* Top-right (Tr): the pins of a tile are placed on the top side and right side only
* Bottom-right (Br): the pins of a tile are placed on the bottom side and right side only
- GlobalTileClk: How many clocks are defined through global ports from physical tiles. is the number of clocks
+- ecb: *Enhanced Connection Block* where connection blocks includes feedback connections
Other features are used in naming should be listed here.
diff --git a/openfpga_flow/vpr_arch/k4_N4_ecb_tileable_TileOrgzBr_40nm.xml b/openfpga_flow/vpr_arch/k4_N4_ecb_tileable_TileOrgzBr_40nm.xml
new file mode 100644
index 000000000..4597207bb
--- /dev/null
+++ b/openfpga_flow/vpr_arch/k4_N4_ecb_tileable_TileOrgzBr_40nm.xml
@@ -0,0 +1,373 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ io.outpad io.inpad
+ io.outpad io.inpad
+ io.outpad io.inpad
+ io.outpad io.inpad
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ clb.clk
+ clb.I2[0:3] clb.I3[0:3] clb.O[2:3]
+
+ clb.I0[0:3] clb.I1[0:3] clb.O[0:1]
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1 1 1 1 1
+ 1 1 1 1
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 261e-12
+ 261e-12
+ 261e-12
+ 261e-12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+