diff --git a/docs/source/manual/arch_lang/annotate_vpr_arch.rst b/docs/source/manual/arch_lang/annotate_vpr_arch.rst
index a23b4f0c6..9fd1024a7 100644
--- a/docs/source/manual/arch_lang/annotate_vpr_arch.rst
+++ b/docs/source/manual/arch_lang/annotate_vpr_arch.rst
@@ -62,12 +62,37 @@ Here is an example:
.. code-block:: xml
+
...
+For subtile port merge support (see an illustrative example in :numref:`fig_subtile_port_merge`):
+
+- ``tile=""`` is the name of tile, that is defined in VPR architecture
+
+- ``port=""`` is the name of a port of the tile, that is defined in VPR architecture
+
+.. warning:: This is an option for power users. Suggest to enable for those global input ports, such as clock and reset, whose ``Fc`` is set to 0 in VPR architecture!!!
+
+.. note:: When defined, the given port of all the subtiles of a tile will be merged into one port. For example, a tile consists of 8 subtile ``A`` and 6 subtile ``B`` and all the subtiles have a port ``clk``, in the FPGA fabric, all the ``clk`` of the subtiles ``A`` and ``B`` will be wired to a common port ``clk`` at tile level.
+
+
+.. note:: When merged, the port will have a default side of ``TOP`` and index of ``0`` on all the attributes, such as width, height etc.
+
+.. _fig_subtile_port_merge:
+
+.. figure:: ./figures/subtile_port_merge.png
+ :width: 100%
+ :alt: Difference in netlists with and without subtile port merging
+
+ Difference in netlists with and without subtile port merging
+
+
+For global port support:
+
- ``name=""`` is the port name to appear in the top-level FPGA fabric.
- ``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.
@@ -111,7 +136,7 @@ A more illustrative example:
.. _fig_global_tile_ports:
.. figure:: ./figures/global_tile_ports.png
- :scale: 100%
+ :width: 100%
:alt: Difference between global port definition through circuit model and tile annotation
Difference between global port definition through circuit model and tile annotation
diff --git a/docs/source/manual/arch_lang/figures/subtile_port_merge.png b/docs/source/manual/arch_lang/figures/subtile_port_merge.png
new file mode 100644
index 000000000..16f7c6021
Binary files /dev/null and b/docs/source/manual/arch_lang/figures/subtile_port_merge.png differ
diff --git a/libs/libarchopenfpga/CMakeLists.txt b/libs/libarchopenfpga/CMakeLists.txt
index 93c20710d..13b4431f1 100644
--- a/libs/libarchopenfpga/CMakeLists.txt
+++ b/libs/libarchopenfpga/CMakeLists.txt
@@ -20,6 +20,7 @@ set_target_properties(libarchopenfpga PROPERTIES PREFIX "") #Avoid extra 'lib' p
#Specify link-time dependancies
target_link_libraries(libarchopenfpga
libopenfpgautil
+ libopenfpgashell
libvtrutil
libarchfpga
libpugiutil)
diff --git a/libs/libarchopenfpga/src/read_xml_tile_annotation.cpp b/libs/libarchopenfpga/src/read_xml_tile_annotation.cpp
index 6b27d0017..135e38361 100644
--- a/libs/libarchopenfpga/src/read_xml_tile_annotation.cpp
+++ b/libs/libarchopenfpga/src/read_xml_tile_annotation.cpp
@@ -125,6 +125,22 @@ static void read_xml_tile_global_port_annotation(
}
}
+/********************************************************************
+ * Parse XML description for an interconnection annotation
+ * under a XML node
+ *******************************************************************/
+static void read_xml_tile_merge_port_annotation(
+ pugi::xml_node& xml_tile, const pugiutil::loc_data& loc_data,
+ openfpga::TileAnnotation& tile_annotation) {
+ const std::string& tile_attr =
+ get_attribute(xml_tile, "tile", loc_data).as_string();
+
+ const std::string& port_attr =
+ get_attribute(xml_tile, "port", loc_data).as_string();
+
+ tile_annotation.add_merge_subtile_ports(tile_attr, port_attr);
+}
+
/********************************************************************
* Top function to parse XML description about tile annotation
*******************************************************************/
@@ -146,11 +162,17 @@ openfpga::TileAnnotation read_xml_tile_annotations(
*/
for (pugi::xml_node xml_tile_global_port : xml_annotations.children()) {
/* Error out if the XML child has an invalid name! */
- if (xml_tile_global_port.name() != std::string("global_port")) {
- bad_tag(xml_tile_global_port, loc_data, xml_annotations, {"global_port"});
+ if (xml_tile_global_port.name() == std::string("global_port")) {
+ read_xml_tile_global_port_annotation(xml_tile_global_port, loc_data,
+ tile_annotations);
+ } else if (xml_tile_global_port.name() ==
+ std::string("merge_subtile_ports")) {
+ read_xml_tile_merge_port_annotation(xml_tile_global_port, loc_data,
+ tile_annotations);
+ } else {
+ bad_tag(xml_tile_global_port, loc_data, xml_annotations,
+ {"global_port or merge_subtile_ports"});
}
- read_xml_tile_global_port_annotation(xml_tile_global_port, loc_data,
- tile_annotations);
}
return tile_annotations;
diff --git a/libs/libarchopenfpga/src/tile_annotation.cpp b/libs/libarchopenfpga/src/tile_annotation.cpp
index 7cf41f02e..2ffacd1d0 100644
--- a/libs/libarchopenfpga/src/tile_annotation.cpp
+++ b/libs/libarchopenfpga/src/tile_annotation.cpp
@@ -3,7 +3,11 @@
***********************************************************************/
#include "tile_annotation.h"
+#include
+
+#include "command_exit_codes.h"
#include "vtr_assert.h"
+#include "vtr_log.h"
/* namespace openfpga begins */
namespace openfpga {
@@ -20,6 +24,27 @@ TileAnnotation::global_port_range TileAnnotation::global_ports() const {
return vtr::make_range(global_port_ids_.begin(), global_port_ids_.end());
}
+std::vector TileAnnotation::tiles_to_merge_ports() const {
+ std::vector tile_names;
+ for (auto it = tile_ports_to_merge_.begin(); it != tile_ports_to_merge_.end();
+ it++) {
+ tile_names.push_back(it->first);
+ }
+ return tile_names;
+}
+
+std::vector TileAnnotation::tile_ports_to_merge(
+ const std::string& tile_name) const {
+ std::vector port_names;
+ const auto& result = tile_ports_to_merge_.find(tile_name);
+ if (result == tile_ports_to_merge_.end()) {
+ VTR_LOG_WARN("Tile '%s' does not contain any ports to merge!\n",
+ tile_name.c_str());
+ return port_names;
+ }
+ return result->second;
+}
+
/************************************************************************
* Public Accessors
***********************************************************************/
@@ -77,6 +102,16 @@ std::string TileAnnotation::global_port_clock_arch_tree_name(
return global_port_clock_arch_tree_names_[global_port_id];
}
+bool TileAnnotation::is_tile_port_to_merge(const std::string& tile_name,
+ const std::string& port_name) const {
+ const auto& result = tile_ports_to_merge_.find(tile_name);
+ if (result == tile_ports_to_merge_.end()) {
+ return false;
+ }
+ return result->second.end() !=
+ std::find(result->second.begin(), result->second.end(), port_name);
+}
+
/************************************************************************
* Public Mutators
***********************************************************************/
@@ -178,4 +213,25 @@ bool TileAnnotation::valid_global_port_attributes(
return ((0 == attribute_counter) || (1 == attribute_counter));
}
+int TileAnnotation::add_merge_subtile_ports(const std::string& tile_name,
+ const std::string& port_name) {
+ auto result = tile_ports_to_merge_.find(tile_name);
+ if (result == tile_ports_to_merge_.end()) {
+ /* Empty list: add a new element */
+ tile_ports_to_merge_[tile_name].push_back(port_name);
+ } else {
+ /* Check if the port name is already in the list, if yes, error out */
+ if (result->second.end() ==
+ std::find(result->second.begin(), result->second.end(), port_name)) {
+ tile_ports_to_merge_[tile_name].push_back(port_name);
+ } else {
+ VTR_LOG_ERROR(
+ "Port '%s' has already been defined twice for tile '%s' to be merged!",
+ port_name.c_str(), tile_name.c_str());
+ return CMD_EXEC_FATAL_ERROR;
+ }
+ }
+ return CMD_EXEC_SUCCESS;
+}
+
} // namespace openfpga
diff --git a/libs/libarchopenfpga/src/tile_annotation.h b/libs/libarchopenfpga/src/tile_annotation.h
index ddf951109..36af8a9b4 100644
--- a/libs/libarchopenfpga/src/tile_annotation.h
+++ b/libs/libarchopenfpga/src/tile_annotation.h
@@ -39,6 +39,9 @@ class TileAnnotation {
public: /* Public accessors: aggregators */
global_port_range global_ports() const;
+ std::vector tiles_to_merge_ports() const;
+ std::vector tile_ports_to_merge(
+ const std::string& tile_name) const;
public: /* Public accessors */
std::string global_port_name(const TileGlobalPortId& global_port_id) const;
@@ -56,6 +59,10 @@ class TileAnnotation {
size_t global_port_default_value(
const TileGlobalPortId& global_port_id) const;
+ /** @brief Check if a given tile port should be merged or not */
+ bool is_tile_port_to_merge(const std::string& tile_name,
+ const std::string& port_name) const;
+
public: /* Public mutators */
/* By default, we do not set it as a clock.
* Users should set it through the set_global_port_is_clock() function
@@ -77,6 +84,9 @@ class TileAnnotation {
void set_global_port_default_value(const TileGlobalPortId& global_port_id,
const size_t& default_value);
+ int add_merge_subtile_ports(const std::string& tile_name,
+ const std::string& port_name);
+
public: /* Public validator */
bool valid_global_port_id(const TileGlobalPortId& global_port_id) const;
/* Validate attributes of a given global port
@@ -102,6 +112,10 @@ class TileAnnotation {
/* A fast lookup for port names */
std::map global_port_name2ids_;
+
+ /* Merge port information for tiles */
+ std::map>
+ tile_ports_to_merge_; // tile_name -> port_name
};
} // namespace openfpga
diff --git a/libs/libarchopenfpga/src/write_xml_tile_annotation.cpp b/libs/libarchopenfpga/src/write_xml_tile_annotation.cpp
index af6bab25a..9db2e01b7 100644
--- a/libs/libarchopenfpga/src/write_xml_tile_annotation.cpp
+++ b/libs/libarchopenfpga/src/write_xml_tile_annotation.cpp
@@ -87,6 +87,24 @@ static void write_xml_tile_annotation_global_port(
<< "";
}
+/********************************************************************
+ * A writer to output a device variation in a technology library to XML format
+ *******************************************************************/
+static void write_xml_tile_annotation_subtile_port_to_merge(
+ std::fstream& fp, const char* fname, const std::string& tile_name,
+ const std::string& port_name) {
+ /* Validate the file stream */
+ openfpga::check_file_stream(fname, fp);
+
+ fp << "\t\t"
+ << "";
+}
+
/********************************************************************
* A writer to output tile annotations to XML format
*******************************************************************/
@@ -109,6 +127,13 @@ void write_xml_tile_annotations(std::fstream& fp, const char* fname,
write_xml_tile_annotation_global_port(fp, fname, tile_annotation,
global_port_id);
}
+ for (std::string tile_name : tile_annotation.tiles_to_merge_ports()) {
+ for (std::string port_name :
+ tile_annotation.tile_ports_to_merge(tile_name)) {
+ write_xml_tile_annotation_subtile_port_to_merge(fp, fname, tile_name,
+ port_name);
+ }
+ }
/* Write the root node for pb_type annotations */
fp << "\t"
diff --git a/libs/libnamemanager/test/module_rename_assistant.cpp b/libs/libnamemanager/test/module_rename_assistant.cpp
index a4e662f02..49de367c3 100644
--- a/libs/libnamemanager/test/module_rename_assistant.cpp
+++ b/libs/libnamemanager/test/module_rename_assistant.cpp
@@ -36,7 +36,7 @@ static std::vector format_argv(const std::string& cmd_name,
* We want a renamed version for fabric B is
*
*/
-int rename_module_names_for_fabricB_from_fabricA(
+static int rename_module_names_for_fabricB_from_fabricA(
const openfpga::ModuleNameMap& refA_module_names,
const openfpga::ModuleNameMap& renamedA_module_names,
const openfpga::ModuleNameMap& refB_module_names,
diff --git a/openfpga/src/base/openfpga_build_fabric_template.h b/openfpga/src/base/openfpga_build_fabric_template.h
index d3d94c3e7..63e623398 100644
--- a/openfpga/src/base/openfpga_build_fabric_template.h
+++ b/openfpga/src/base/openfpga_build_fabric_template.h
@@ -130,6 +130,16 @@ int build_fabric_template(T& openfpga_ctx, const Command& cmd,
return CMD_EXEC_FATAL_ERROR;
}
}
+ /* Conflicts: duplicate_grid_pin does not support any port merge */
+ if (cmd_context.option_enable(cmd, opt_duplicate_grid_pin)) {
+ if (openfpga_ctx.arch().tile_annotations.tiles_to_merge_ports().size() >
+ 0) {
+ VTR_LOG_ERROR(
+ "Option '%s' requires no tile ports to be merged due to a conflict!\n",
+ cmd.option_name(opt_duplicate_grid_pin).c_str());
+ return CMD_EXEC_FATAL_ERROR;
+ }
+ }
if (true == cmd_context.option_enable(cmd, opt_compress_routing)) {
compress_routing_hierarchy_template(
diff --git a/openfpga/src/fabric/build_device_module.cpp b/openfpga/src/fabric/build_device_module.cpp
index 8a4b176d7..012e3a529 100644
--- a/openfpga/src/fabric/build_device_module.cpp
+++ b/openfpga/src/fabric/build_device_module.cpp
@@ -87,8 +87,9 @@ int build_device_module_graph(
status = build_grid_modules(
module_manager, decoder_lib, vpr_device_ctx,
openfpga_ctx.vpr_device_annotation(), openfpga_ctx.arch().circuit_lib,
- openfpga_ctx.mux_lib(), openfpga_ctx.arch().config_protocol.type(),
- sram_model, duplicate_grid_pin, group_config_block, verbose);
+ openfpga_ctx.mux_lib(), openfpga_ctx.arch().tile_annotations,
+ openfpga_ctx.arch().config_protocol.type(), sram_model, duplicate_grid_pin,
+ group_config_block, verbose);
if (CMD_EXEC_FATAL_ERROR == status) {
return status;
}
@@ -120,13 +121,13 @@ int build_device_module_graph(
return status;
}
/* Build the modules */
- build_tile_modules(module_manager, decoder_lib, openfpga_ctx.fabric_tile(),
- vpr_device_ctx.grid,
- openfpga_ctx.vpr_device_annotation(),
- openfpga_ctx.device_rr_gsb(), vpr_device_ctx.rr_graph,
- openfpga_ctx.arch().circuit_lib, sram_model,
- openfpga_ctx.arch().config_protocol.type(),
- name_module_using_index, frame_view, verbose);
+ build_tile_modules(
+ module_manager, decoder_lib, openfpga_ctx.fabric_tile(),
+ vpr_device_ctx.grid, openfpga_ctx.vpr_device_annotation(),
+ openfpga_ctx.device_rr_gsb(), vpr_device_ctx.rr_graph,
+ openfpga_ctx.arch().tile_annotations, openfpga_ctx.arch().circuit_lib,
+ sram_model, openfpga_ctx.arch().config_protocol.type(),
+ name_module_using_index, frame_view, verbose);
}
/* Build FPGA fabric top-level module */
diff --git a/openfpga/src/fabric/build_grid_module_duplicated_pins.cpp b/openfpga/src/fabric/build_grid_module_duplicated_pins.cpp
index 77f4024db..cae215259 100644
--- a/openfpga/src/fabric/build_grid_module_duplicated_pins.cpp
+++ b/openfpga/src/fabric/build_grid_module_duplicated_pins.cpp
@@ -54,7 +54,8 @@ namespace openfpga {
void add_grid_module_duplicated_pb_type_ports(
ModuleManager& module_manager, const ModuleId& grid_module,
const VprDeviceAnnotation& vpr_device_annotation,
- t_physical_tile_type_ptr grid_type_descriptor, const e_side& border_side) {
+ t_physical_tile_type_ptr grid_type_descriptor,
+ const TileAnnotation& tile_annotation, const e_side& border_side) {
/* Ensure that we have a valid grid_type_descriptor */
VTR_ASSERT(false == is_empty_type(grid_type_descriptor));
@@ -109,6 +110,17 @@ void add_grid_module_duplicated_pb_type_ports(
(0. == find_physical_tile_pin_Fc(grid_type_descriptor, ipin)))) {
std::string port_name = generate_grid_port_name(
iwidth, iheight, subtile_index, side, pin_info);
+ /* If the port is required to be merged, we deposit zero as subtile
+ * index */
+ if (tile_annotation.is_tile_port_to_merge(
+ std::string(grid_type_descriptor->name),
+ pin_info.get_name())) {
+ if (subtile_index == 0) {
+ port_name = generate_grid_port_name(0, 0, 0, TOP, pin_info);
+ } else {
+ continue;
+ }
+ }
BasicPort grid_port(port_name, 0, 0);
/* Add the port to the module */
module_manager.add_port(grid_module, grid_port,
@@ -297,7 +309,8 @@ void add_grid_module_nets_connect_duplicated_pb_type_ports(
ModuleManager& module_manager, const ModuleId& grid_module,
const ModuleId& child_module, const size_t& child_instance,
const t_sub_tile& sub_tile, const VprDeviceAnnotation& vpr_device_annotation,
- t_physical_tile_type_ptr grid_type_descriptor, const e_side& border_side) {
+ t_physical_tile_type_ptr grid_type_descriptor,
+ const TileAnnotation& tile_annotation, const e_side& border_side) {
/* Ensure that we have a valid grid_type_descriptor */
VTR_ASSERT(false == is_empty_type(grid_type_descriptor));
@@ -314,8 +327,8 @@ void add_grid_module_nets_connect_duplicated_pb_type_ports(
add_grid_module_net_connect_pb_graph_pin(
module_manager, grid_module, child_module, child_instance,
child_inst_subtile_index, vpr_device_annotation, grid_type_descriptor,
- &(top_pb_graph_node->input_pins[iport][ipin]), border_side,
- INPUT2INPUT_INTERC);
+ tile_annotation, &(top_pb_graph_node->input_pins[iport][ipin]),
+ border_side, INPUT2INPUT_INTERC);
}
}
@@ -336,8 +349,8 @@ void add_grid_module_nets_connect_duplicated_pb_type_ports(
add_grid_module_net_connect_pb_graph_pin(
module_manager, grid_module, child_module, child_instance,
child_inst_subtile_index, vpr_device_annotation, grid_type_descriptor,
- &(top_pb_graph_node->clock_pins[iport][ipin]), border_side,
- INPUT2INPUT_INTERC);
+ tile_annotation, &(top_pb_graph_node->clock_pins[iport][ipin]),
+ border_side, INPUT2INPUT_INTERC);
}
}
}
diff --git a/openfpga/src/fabric/build_grid_module_duplicated_pins.h b/openfpga/src/fabric/build_grid_module_duplicated_pins.h
index 66e1a5634..4f2eafee2 100644
--- a/openfpga/src/fabric/build_grid_module_duplicated_pins.h
+++ b/openfpga/src/fabric/build_grid_module_duplicated_pins.h
@@ -7,6 +7,7 @@
#include "module_manager.h"
#include "openfpga_side_manager.h"
#include "physical_types.h"
+#include "tile_annotation.h"
#include "vpr_device_annotation.h"
/********************************************************************
@@ -19,13 +20,15 @@ namespace openfpga {
void add_grid_module_duplicated_pb_type_ports(
ModuleManager& module_manager, const ModuleId& grid_module,
const VprDeviceAnnotation& vpr_device_annotation,
- t_physical_tile_type_ptr grid_type_descriptor, const e_side& border_side);
+ t_physical_tile_type_ptr grid_type_descriptor,
+ const TileAnnotation& tile_annotation, const e_side& border_side);
void add_grid_module_nets_connect_duplicated_pb_type_ports(
ModuleManager& module_manager, const ModuleId& grid_module,
const ModuleId& child_module, const size_t& child_instance,
const t_sub_tile& sub_tile, const VprDeviceAnnotation& vpr_device_annotation,
- t_physical_tile_type_ptr grid_type_descriptor, const e_side& border_side);
+ t_physical_tile_type_ptr grid_type_descriptor,
+ const TileAnnotation& tile_annotation, const e_side& border_side);
} /* end namespace openfpga */
diff --git a/openfpga/src/fabric/build_grid_module_utils.cpp b/openfpga/src/fabric/build_grid_module_utils.cpp
index c79262805..3b3f14203 100644
--- a/openfpga/src/fabric/build_grid_module_utils.cpp
+++ b/openfpga/src/fabric/build_grid_module_utils.cpp
@@ -45,7 +45,8 @@ void add_grid_module_net_connect_pb_graph_pin(
const ModuleId& child_module, const size_t& child_instance,
const size_t& child_inst_subtile_index,
const VprDeviceAnnotation& vpr_device_annotation,
- t_physical_tile_type_ptr grid_type_descriptor, t_pb_graph_pin* pb_graph_pin,
+ t_physical_tile_type_ptr grid_type_descriptor,
+ const TileAnnotation& tile_annotation, t_pb_graph_pin* pb_graph_pin,
const e_side& border_side, const e_pin2pin_interc_type& pin2pin_interc_type) {
/* Find the pin side for I/O grids*/
std::vector grid_pin_sides;
@@ -91,6 +92,13 @@ void add_grid_module_net_connect_pb_graph_pin(
subtile_index < grid_type_descriptor->capacity);
std::string grid_port_name = generate_grid_port_name(
pin_width, pin_height, subtile_index, side, pin_info);
+ /* If the port is required to be merged, we only consider the source port to
+ * be the subtile index of 0 */
+ if (tile_annotation.is_tile_port_to_merge(
+ std::string(grid_type_descriptor->name), pin_info.get_name())) {
+ /* Exception: use top side for these merged ports */
+ grid_port_name = generate_grid_port_name(0, 0, 0, TOP, pin_info);
+ }
ModulePortId grid_module_port_id =
module_manager.find_module_port(grid_module, grid_port_name);
VTR_ASSERT(true == module_manager.valid_module_port_id(
diff --git a/openfpga/src/fabric/build_grid_module_utils.h b/openfpga/src/fabric/build_grid_module_utils.h
index c1f0549dd..a8d5f9d12 100644
--- a/openfpga/src/fabric/build_grid_module_utils.h
+++ b/openfpga/src/fabric/build_grid_module_utils.h
@@ -8,6 +8,7 @@
#include "module_manager.h"
#include "openfpga_interconnect_types.h"
#include "physical_types.h"
+#include "tile_annotation.h"
#include "vpr_device_annotation.h"
/********************************************************************
@@ -25,7 +26,8 @@ void add_grid_module_net_connect_pb_graph_pin(
const ModuleId& child_module, const size_t& child_instance,
const size_t& child_inst_subtile_index,
const VprDeviceAnnotation& vpr_device_annotation,
- t_physical_tile_type_ptr grid_type_descriptor, t_pb_graph_pin* pb_graph_pin,
+ t_physical_tile_type_ptr grid_type_descriptor,
+ const TileAnnotation& tile_annotation, t_pb_graph_pin* pb_graph_pin,
const e_side& border_side,
const enum e_pin2pin_interc_type& pin2pin_interc_type);
diff --git a/openfpga/src/fabric/build_grid_modules.cpp b/openfpga/src/fabric/build_grid_modules.cpp
index bf8ca86ac..ad49cc63c 100644
--- a/openfpga/src/fabric/build_grid_modules.cpp
+++ b/openfpga/src/fabric/build_grid_modules.cpp
@@ -41,7 +41,8 @@ namespace openfpga {
static void add_grid_module_pb_type_ports(
ModuleManager& module_manager, const ModuleId& grid_module,
const VprDeviceAnnotation& vpr_device_annotation,
- t_physical_tile_type_ptr grid_type_descriptor, const e_side& border_side) {
+ t_physical_tile_type_ptr grid_type_descriptor,
+ const TileAnnotation& tile_annotation, const e_side& border_side) {
/* Ensure that we have a valid grid_type_descriptor */
VTR_ASSERT(nullptr != grid_type_descriptor);
@@ -90,6 +91,16 @@ static void add_grid_module_pb_type_ports(
subtile_index < grid_type_descriptor->capacity);
std::string port_name = generate_grid_port_name(
iwidth, iheight, subtile_index, side, pin_info);
+ /* If the port is required to be merged, we use a special index
+ * index */
+ if (tile_annotation.is_tile_port_to_merge(
+ std::string(grid_type_descriptor->name), pin_info.get_name())) {
+ if (subtile_index == 0) {
+ port_name = generate_grid_port_name(0, 0, 0, TOP, pin_info);
+ } else {
+ continue;
+ }
+ }
BasicPort grid_port(port_name, 0, 0);
/* Add the port to the module */
module_manager.add_port(grid_module, grid_port,
@@ -111,7 +122,8 @@ static void add_grid_module_nets_connect_pb_type_ports(
ModuleManager& module_manager, const ModuleId& grid_module,
const ModuleId& child_module, const size_t& child_instance,
const t_sub_tile& sub_tile, const VprDeviceAnnotation& vpr_device_annotation,
- t_physical_tile_type_ptr grid_type_descriptor, const e_side& border_side) {
+ t_physical_tile_type_ptr grid_type_descriptor,
+ const TileAnnotation& tile_annotation, const e_side& border_side) {
/* Ensure that we have a valid grid_type_descriptor */
VTR_ASSERT(nullptr != grid_type_descriptor);
@@ -129,8 +141,8 @@ static void add_grid_module_nets_connect_pb_type_ports(
add_grid_module_net_connect_pb_graph_pin(
module_manager, grid_module, child_module, child_instance,
child_inst_subtile_index, vpr_device_annotation, grid_type_descriptor,
- &(top_pb_graph_node->input_pins[iport][ipin]), border_side,
- INPUT2INPUT_INTERC);
+ tile_annotation, &(top_pb_graph_node->input_pins[iport][ipin]),
+ border_side, INPUT2INPUT_INTERC);
}
}
@@ -140,8 +152,8 @@ static void add_grid_module_nets_connect_pb_type_ports(
add_grid_module_net_connect_pb_graph_pin(
module_manager, grid_module, child_module, child_instance,
child_inst_subtile_index, vpr_device_annotation, grid_type_descriptor,
- &(top_pb_graph_node->output_pins[iport][ipin]), border_side,
- OUTPUT2OUTPUT_INTERC);
+ tile_annotation, &(top_pb_graph_node->output_pins[iport][ipin]),
+ border_side, OUTPUT2OUTPUT_INTERC);
}
}
@@ -151,8 +163,8 @@ static void add_grid_module_nets_connect_pb_type_ports(
add_grid_module_net_connect_pb_graph_pin(
module_manager, grid_module, child_module, child_instance,
child_inst_subtile_index, vpr_device_annotation, grid_type_descriptor,
- &(top_pb_graph_node->clock_pins[iport][ipin]), border_side,
- INPUT2INPUT_INTERC);
+ tile_annotation, &(top_pb_graph_node->clock_pins[iport][ipin]),
+ border_side, INPUT2INPUT_INTERC);
}
}
}
@@ -1151,8 +1163,9 @@ static int build_physical_tile_module(
const CircuitLibrary& circuit_lib,
const e_config_protocol_type& sram_orgz_type,
const CircuitModelId& sram_model, t_physical_tile_type_ptr phy_block_type,
- const e_side& border_side, const bool& duplicate_grid_pin,
- const bool& group_config_block, const bool& verbose) {
+ const TileAnnotation& tile_annotation, const e_side& border_side,
+ const bool& duplicate_grid_pin, const bool& group_config_block,
+ const bool& verbose) {
int status = CMD_EXEC_SUCCESS;
/* Create a Module for the top-level physical block, and add to module manager
*/
@@ -1231,7 +1244,7 @@ static int build_physical_tile_module(
/* Default way to add these ports by following the definition in pb_types */
add_grid_module_pb_type_ports(module_manager, grid_module,
vpr_device_annotation, phy_block_type,
- border_side);
+ tile_annotation, border_side);
/* Add module nets to connect the pb_type ports to sub modules */
for (const t_sub_tile& sub_tile : phy_block_type->sub_tiles) {
VTR_ASSERT(sub_tile.equivalent_sites.size() == 1);
@@ -1248,15 +1261,15 @@ static int build_physical_tile_module(
module_manager.child_module_instances(grid_module, pb_module)) {
add_grid_module_nets_connect_pb_type_ports(
module_manager, grid_module, pb_module, child_instance, sub_tile,
- vpr_device_annotation, phy_block_type, border_side);
+ vpr_device_annotation, phy_block_type, tile_annotation, border_side);
}
}
} else {
VTR_ASSERT_SAFE(true == duplicate_grid_pin);
/* Add these ports with duplication */
- add_grid_module_duplicated_pb_type_ports(module_manager, grid_module,
- vpr_device_annotation,
- phy_block_type, border_side);
+ add_grid_module_duplicated_pb_type_ports(
+ module_manager, grid_module, vpr_device_annotation, phy_block_type,
+ tile_annotation, border_side);
/* Add module nets to connect the duplicated pb_type ports to sub modules */
for (const t_sub_tile& sub_tile : phy_block_type->sub_tiles) {
@@ -1274,7 +1287,7 @@ static int build_physical_tile_module(
module_manager.child_module_instances(grid_module, pb_module)) {
add_grid_module_nets_connect_duplicated_pb_type_ports(
module_manager, grid_module, pb_module, child_instance, sub_tile,
- vpr_device_annotation, phy_block_type, border_side);
+ vpr_device_annotation, phy_block_type, tile_annotation, border_side);
}
}
}
@@ -1357,6 +1370,7 @@ int build_grid_modules(
ModuleManager& module_manager, DecoderLibrary& decoder_lib,
const DeviceContext& device_ctx, const VprDeviceAnnotation& device_annotation,
const CircuitLibrary& circuit_lib, const MuxLibrary& mux_lib,
+ const TileAnnotation& tile_annotation,
const e_config_protocol_type& sram_orgz_type,
const CircuitModelId& sram_model, const bool& duplicate_grid_pin,
const bool& group_config_block, const bool& verbose) {
@@ -1414,8 +1428,8 @@ int build_grid_modules(
for (const e_side& io_type_side : io_type_sides) {
status = build_physical_tile_module(
module_manager, decoder_lib, device_annotation, circuit_lib,
- sram_orgz_type, sram_model, &physical_tile, io_type_side,
- duplicate_grid_pin, group_config_block, verbose);
+ sram_orgz_type, sram_model, &physical_tile, tile_annotation,
+ io_type_side, duplicate_grid_pin, group_config_block, verbose);
if (status != CMD_EXEC_SUCCESS) {
return CMD_EXEC_FATAL_ERROR;
}
@@ -1424,7 +1438,7 @@ int build_grid_modules(
/* For CLB and heterogenenous blocks */
status = build_physical_tile_module(
module_manager, decoder_lib, device_annotation, circuit_lib,
- sram_orgz_type, sram_model, &physical_tile, NUM_SIDES,
+ sram_orgz_type, sram_model, &physical_tile, tile_annotation, NUM_SIDES,
duplicate_grid_pin, group_config_block, verbose);
if (status != CMD_EXEC_SUCCESS) {
return CMD_EXEC_FATAL_ERROR;
diff --git a/openfpga/src/fabric/build_grid_modules.h b/openfpga/src/fabric/build_grid_modules.h
index d83cc3ac3..996b9bda2 100644
--- a/openfpga/src/fabric/build_grid_modules.h
+++ b/openfpga/src/fabric/build_grid_modules.h
@@ -7,6 +7,7 @@
#include "decoder_library.h"
#include "module_manager.h"
#include "mux_library.h"
+#include "tile_annotation.h"
#include "vpr_context.h"
#include "vpr_device_annotation.h"
@@ -21,6 +22,7 @@ int build_grid_modules(
ModuleManager& module_manager, DecoderLibrary& decoder_lib,
const DeviceContext& device_ctx, const VprDeviceAnnotation& device_annotation,
const CircuitLibrary& circuit_lib, const MuxLibrary& mux_lib,
+ const TileAnnotation& tile_annotation,
const e_config_protocol_type& sram_orgz_type,
const CircuitModelId& sram_model, const bool& duplicate_grid_pin,
const bool& group_config_block, const bool& verbose);
diff --git a/openfpga/src/fabric/build_tile_modules.cpp b/openfpga/src/fabric/build_tile_modules.cpp
index 6fafbcf3d..caf82f075 100644
--- a/openfpga/src/fabric/build_tile_modules.cpp
+++ b/openfpga/src/fabric/build_tile_modules.cpp
@@ -1004,9 +1004,10 @@ static int build_tile_port_and_nets_from_pb(
ModuleManager& module_manager, const ModuleId& tile_module,
const DeviceGrid& grids, const size_t& layer,
const VprDeviceAnnotation& vpr_device_annotation, const RRGraphView& rr_graph,
- const vtr::Point& pb_coord, const std::vector& pb_instances,
- const FabricTile& fabric_tile, const FabricTileId& curr_fabric_tile_id,
- const size_t& ipb, const bool& frame_view, const bool& verbose) {
+ const TileAnnotation& tile_annotation, const vtr::Point& pb_coord,
+ const std::vector& pb_instances, const FabricTile& fabric_tile,
+ const FabricTileId& curr_fabric_tile_id, const size_t& ipb,
+ const bool& frame_view, const bool& verbose) {
size_t pb_instance = pb_instances[ipb];
t_physical_tile_type_ptr phy_tile = grids.get_physical_type(
t_physical_tile_loc(pb_coord.x(), pb_coord.y(), layer));
@@ -1065,6 +1066,14 @@ static int build_tile_port_and_nets_from_pb(
subtile_index < phy_tile->capacity);
std::string port_name = generate_grid_port_name(
iwidth, iheight, subtile_index, side, pin_info);
+ if (tile_annotation.is_tile_port_to_merge(std::string(phy_tile->name),
+ pin_info.get_name())) {
+ if (subtile_index == 0) {
+ port_name = generate_grid_port_name(0, 0, 0, TOP, pin_info);
+ } else {
+ continue;
+ }
+ }
BasicPort pb_port(port_name, 0, 0);
ModulePortId pb_module_port_id =
module_manager.find_module_port(pb_module, port_name);
@@ -1193,8 +1202,8 @@ static int build_tile_module_ports_and_nets(
const DeviceGrid& grids, const size_t& layer,
const VprDeviceAnnotation& vpr_device_annotation,
const DeviceRRGSB& device_rr_gsb, const RRGraphView& rr_graph_view,
- const FabricTile& fabric_tile, const FabricTileId& fabric_tile_id,
- const std::vector& pb_instances,
+ const TileAnnotation& tile_annotation, const FabricTile& fabric_tile,
+ const FabricTileId& fabric_tile_id, const std::vector& pb_instances,
const std::map>& cb_instances,
const std::vector& sb_instances, const bool& name_module_using_index,
const bool& frame_view, const bool& verbose) {
@@ -1259,8 +1268,8 @@ static int build_tile_module_ports_and_nets(
fabric_tile.pb_coordinates(fabric_tile_id)[ipb];
status_code = build_tile_port_and_nets_from_pb(
module_manager, tile_module, grids, layer, vpr_device_annotation,
- rr_graph_view, pb_coord, pb_instances, fabric_tile, fabric_tile_id, ipb,
- frame_view, verbose);
+ rr_graph_view, tile_annotation, pb_coord, pb_instances, fabric_tile,
+ fabric_tile_id, ipb, frame_view, verbose);
if (status_code != CMD_EXEC_SUCCESS) {
return CMD_EXEC_FATAL_ERROR;
}
@@ -1303,7 +1312,8 @@ static int build_tile_module(
const DeviceGrid& grids, const size_t& layer,
const VprDeviceAnnotation& vpr_device_annotation,
const DeviceRRGSB& device_rr_gsb, const RRGraphView& rr_graph_view,
- const CircuitLibrary& circuit_lib, const CircuitModelId& sram_model,
+ const TileAnnotation& tile_annotation, const CircuitLibrary& circuit_lib,
+ const CircuitModelId& sram_model,
const e_config_protocol_type& sram_orgz_type,
const bool& name_module_using_index, const bool& frame_view,
const bool& verbose) {
@@ -1451,8 +1461,9 @@ static int build_tile_module(
/* Add module nets and ports */
status_code = build_tile_module_ports_and_nets(
module_manager, tile_module, grids, layer, vpr_device_annotation,
- device_rr_gsb, rr_graph_view, fabric_tile, fabric_tile_id, pb_instances,
- cb_instances, sb_instances, name_module_using_index, frame_view, verbose);
+ device_rr_gsb, rr_graph_view, tile_annotation, fabric_tile, fabric_tile_id,
+ pb_instances, cb_instances, sb_instances, name_module_using_index,
+ frame_view, verbose);
/* Add global ports to the pb_module:
* This is a much easier job after adding sub modules (instances),
@@ -1521,6 +1532,7 @@ int build_tile_modules(ModuleManager& module_manager,
const VprDeviceAnnotation& vpr_device_annotation,
const DeviceRRGSB& device_rr_gsb,
const RRGraphView& rr_graph_view,
+ const TileAnnotation& tile_annotation,
const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const e_config_protocol_type& sram_orgz_type,
@@ -1536,8 +1548,9 @@ int build_tile_modules(ModuleManager& module_manager,
for (FabricTileId fabric_tile_id : fabric_tile.unique_tiles()) {
status_code = build_tile_module(
module_manager, decoder_lib, fabric_tile, fabric_tile_id, grids, layer,
- vpr_device_annotation, device_rr_gsb, rr_graph_view, circuit_lib,
- sram_model, sram_orgz_type, name_module_using_index, frame_view, verbose);
+ vpr_device_annotation, device_rr_gsb, rr_graph_view, tile_annotation,
+ circuit_lib, sram_model, sram_orgz_type, name_module_using_index,
+ frame_view, verbose);
if (status_code != CMD_EXEC_SUCCESS) {
return CMD_EXEC_FATAL_ERROR;
}
diff --git a/openfpga/src/fabric/build_tile_modules.h b/openfpga/src/fabric/build_tile_modules.h
index 62f9cbe99..83f219610 100644
--- a/openfpga/src/fabric/build_tile_modules.h
+++ b/openfpga/src/fabric/build_tile_modules.h
@@ -15,6 +15,7 @@
#include "fabric_tile.h"
#include "module_manager.h"
#include "rr_graph_view.h"
+#include "tile_annotation.h"
#include "vpr_device_annotation.h"
/********************************************************************
@@ -30,6 +31,7 @@ int build_tile_modules(ModuleManager& module_manager,
const VprDeviceAnnotation& vpr_device_annotation,
const DeviceRRGSB& device_rr_gsb,
const RRGraphView& rr_graph_view,
+ const TileAnnotation& tile_annotation,
const CircuitLibrary& circuit_lib,
const CircuitModelId& sram_model,
const e_config_protocol_type& sram_orgz_type,
diff --git a/openfpga/src/fabric/build_top_module_child_tile_instance.cpp b/openfpga/src/fabric/build_top_module_child_tile_instance.cpp
index b4bc5e8c2..3c1c86c1c 100644
--- a/openfpga/src/fabric/build_top_module_child_tile_instance.cpp
+++ b/openfpga/src/fabric/build_top_module_child_tile_instance.cpp
@@ -1404,6 +1404,15 @@ static int build_top_module_global_net_for_given_tile_module(
std::string grid_port_name =
generate_grid_port_name(grid_pin_width, grid_pin_height,
subtile_index, pin_side, grid_pin_info);
+ if (tile_annotation.is_tile_port_to_merge(
+ std::string(physical_tile->name), grid_pin_info.get_name())) {
+ if (subtile_index == 0) {
+ grid_port_name =
+ generate_grid_port_name(0, 0, 0, TOP, grid_pin_info);
+ } else {
+ continue;
+ }
+ }
std::string tile_grid_port_name =
generate_tile_module_port_name(grid_instance_name, grid_port_name);
ModulePortId tile_grid_port_id =
diff --git a/openfpga/src/fabric/build_top_module_connection.cpp b/openfpga/src/fabric/build_top_module_connection.cpp
index d49a6f1cf..98b256fe0 100644
--- a/openfpga/src/fabric/build_top_module_connection.cpp
+++ b/openfpga/src/fabric/build_top_module_connection.cpp
@@ -950,6 +950,16 @@ static int build_top_module_global_net_for_given_grid_module(
std::string grid_port_name =
generate_grid_port_name(grid_pin_width, grid_pin_height,
subtile_index, pin_side, grid_pin_info);
+ if (tile_annotation.is_tile_port_to_merge(
+ std::string(physical_tile->name), grid_pin_info.get_name())) {
+ if (subtile_index == 0) {
+ grid_port_name =
+ generate_grid_port_name(0, 0, 0, TOP, grid_pin_info);
+ } else {
+ continue;
+ }
+ }
+
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,
diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClkMergeSubtilePort_registerable_io_cc_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClkMergeSubtilePort_registerable_io_cc_openfpga.xml
new file mode 100644
index 000000000..a7c1a8bfa
--- /dev/null
+++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClkMergeSubtilePort_registerable_io_cc_openfpga.xml
@@ -0,0 +1,215 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 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_shell_scripts/global_tile_clock_options_full_testbench_example_script.openfpga b/openfpga_flow/openfpga_shell_scripts/global_tile_clock_options_full_testbench_example_script.openfpga
new file mode 100644
index 000000000..956451380
--- /dev/null
+++ b/openfpga_flow/openfpga_shell_scripts/global_tile_clock_options_full_testbench_example_script.openfpga
@@ -0,0 +1,63 @@
+# 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 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 ${OPENFPGA_GROUP_CONFIG_BLOCK_OPTIONS} ${OPENFPGA_GROUP_TILE_CONFIG_OPTIONS} #--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.bit --format plain_text
+
+# 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_full_testbench --file ./SRC --reference_benchmark_file_path ${REFERENCE_VERILOG_TESTBENCH} --explicit_port_mapping --include_signal_init --bitstream fabric_bitstream.bit
+
+# 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/regression_test_scripts/basic_reg_test.sh b/openfpga_flow/regression_test_scripts/basic_reg_test.sh
index 4835a66cd..dd945b427 100755
--- a/openfpga_flow/regression_test_scripts/basic_reg_test.sh
+++ b/openfpga_flow/regression_test_scripts/basic_reg_test.sh
@@ -211,6 +211,8 @@ run-task basic_tests/module_naming/renaming_rules_on_indexed_names $@
echo -e "Testing global port definition from tiles";
run-task basic_tests/global_tile_ports/global_tile_clock $@
run-task basic_tests/global_tile_ports/global_tile_clock_subtile $@
+run-task basic_tests/global_tile_ports/global_tile_clock_subtile_port_merge $@
+run-task basic_tests/global_tile_ports/global_tile_clock_subtile_port_merge_fabric_tile_group_config $@
run-task basic_tests/global_tile_ports/global_tile_reset $@
run-task basic_tests/global_tile_ports/global_tile_4clock $@
run-task basic_tests/global_tile_ports/global_tile_4clock_pin $@
diff --git a/openfpga_flow/tasks/basic_tests/global_tile_ports/global_tile_clock_subtile_port_merge/config/task.conf b/openfpga_flow/tasks/basic_tests/global_tile_ports/global_tile_clock_subtile_port_merge/config/task.conf
new file mode 100644
index 000000000..adbbaa2cb
--- /dev/null
+++ b/openfpga_flow/tasks/basic_tests/global_tile_ports/global_tile_clock_subtile_port_merge/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/global_tile_clock_full_testbench_example_script.openfpga
+openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClkMergeSubtilePort_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_hybrid_io
+
+[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]
+bench_read_verilog_options_common = -nolatches
+bench0_top = and2_pipelined
+
+[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
+end_flow_with_test=
diff --git a/openfpga_flow/tasks/basic_tests/global_tile_ports/global_tile_clock_subtile_port_merge_fabric_tile_group_config/config/task.conf b/openfpga_flow/tasks/basic_tests/global_tile_ports/global_tile_clock_subtile_port_merge_fabric_tile_group_config/config/task.conf
new file mode 100644
index 000000000..dc9eacdb7
--- /dev/null
+++ b/openfpga_flow/tasks/basic_tests/global_tile_ports/global_tile_clock_subtile_port_merge_fabric_tile_group_config/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 = 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/global_tile_clock_options_full_testbench_example_script.openfpga
+openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_GlobalTileClkMergeSubtilePort_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_hybrid_io
+openfpga_group_tile_config_options=--group_tile ${PATH:TASK_DIR}/config/tile_config.xml
+openfpga_group_config_block_options=--group_config_block
+
+[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]
+bench_read_verilog_options_common = -nolatches
+bench0_top = and2_pipelined
+
+[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
+end_flow_with_test=
diff --git a/openfpga_flow/tasks/basic_tests/global_tile_ports/global_tile_clock_subtile_port_merge_fabric_tile_group_config/config/tile_config.xml b/openfpga_flow/tasks/basic_tests/global_tile_ports/global_tile_clock_subtile_port_merge_fabric_tile_group_config/config/tile_config.xml
new file mode 100644
index 000000000..1a1f3f6e8
--- /dev/null
+++ b/openfpga_flow/tasks/basic_tests/global_tile_ports/global_tile_clock_subtile_port_merge_fabric_tile_group_config/config/tile_config.xml
@@ -0,0 +1 @@
+