diff --git a/docs/source/manual/arch_lang/circuit_library.rst b/docs/source/manual/arch_lang/circuit_library.rst
index c11a8c611..726d29c56 100644
--- a/docs/source/manual/arch_lang/circuit_library.rst
+++ b/docs/source/manual/arch_lang/circuit_library.rst
@@ -201,7 +201,7 @@ A circuit model may consist of a number of ports. The port list is mandatory in
.. note:: Different types of ``circuit_model`` have different XML syntax, with which users can highly customize their circuit topologies. See refer to examples of :ref:``circuit_model_example`` for more details.
-.. note:: Note that we have a list of reserved port names, which indicate the usage of these ports when building FPGA fabrics. Please do not use ``mem_out``, ``mem_inv``, ``bl``, ``wl``, ``blb``, ``wlb``, ``ccff_head`` and ``ccff_tail``.
+.. note:: Note that we have a list of reserved port names, which indicate the usage of these ports when building FPGA fabrics. Please do not use ``mem_out``, ``mem_inv``, ``bl``, ``wl``, ``blb``, ``wlb``, ``wlr``, ``ccff_head`` and ``ccff_tail``.
FPGA I/O Port
^^^^^^^^^^^^^
diff --git a/docs/source/manual/arch_lang/circuit_model_examples.rst b/docs/source/manual/arch_lang/circuit_model_examples.rst
index 7113be1c0..437cea837 100644
--- a/docs/source/manual/arch_lang/circuit_model_examples.rst
+++ b/docs/source/manual/arch_lang/circuit_model_examples.rst
@@ -333,6 +333,36 @@ The following XML codes describes the SRAM cell shown in :numref:`fig_sram_blwl`
.. note:: When the ``memory_bank`` type of configuration procotol is specified, SRAM modules should have a BL and a WL.
+.. _circuit_model_sram_blwlr_example:
+
+SRAM with BL/WL/WLR
+```````````````````
+.. _fig_sram_blwlr:
+
+.. figure:: ./figures/sram_blwlr.svg
+ :scale: 100%
+
+ An example of a SRAM with Bit-Line (BL), Word-Line (WL) and WL read control signals
+
+The following XML codes describes the SRAM cell shown in :numref:`fig_sram_blwlr`.
+
+.. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+
+
+.. note:: OpenFPGA always assume that a ``WL`` port should be the write enable signal, a ``WLR`` port should be the read enable signal, while a ``BL`` port is the data input.
+
+.. note:: When the ``memory_bank`` type of configuration procotol is specified, SRAM modules should have a BL and a WL. WLR is optional
+
.. _circuit_model_config_latch_example:
Configurable Latch
diff --git a/docs/source/manual/arch_lang/figures/sram_blwlr.svg b/docs/source/manual/arch_lang/figures/sram_blwlr.svg
new file mode 100644
index 000000000..838dd54ed
--- /dev/null
+++ b/docs/source/manual/arch_lang/figures/sram_blwlr.svg
@@ -0,0 +1,213 @@
+
+
+
diff --git a/libopenfpga/libarchopenfpga/src/circuit_types.h b/libopenfpga/libarchopenfpga/src/circuit_types.h
index 3a2604a42..12b881db0 100644
--- a/libopenfpga/libarchopenfpga/src/circuit_types.h
+++ b/libopenfpga/libarchopenfpga/src/circuit_types.h
@@ -101,10 +101,11 @@ enum e_circuit_model_port_type {
CIRCUIT_MODEL_PORT_BLB,
CIRCUIT_MODEL_PORT_WL,
CIRCUIT_MODEL_PORT_WLB,
+ CIRCUIT_MODEL_PORT_WLR,
NUM_CIRCUIT_MODEL_PORT_TYPES
};
/* Strings correspond to each port type */
-constexpr std::array CIRCUIT_MODEL_PORT_TYPE_STRING = {{"input", "output", "inout", "clock", "sram", "bl", "blb", "wl", "wlb"}};
+constexpr std::array CIRCUIT_MODEL_PORT_TYPE_STRING = {{"input", "output", "inout", "clock", "sram", "bl", "blb", "wl", "wlb", "wlr"}};
enum e_circuit_model_delay_type {
CIRCUIT_MODEL_DELAY_RISE,
diff --git a/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h b/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h
index 732247178..af151a7a5 100644
--- a/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h
+++ b/libopenfpga/libopenfpgautil/src/openfpga_reserved_words.h
@@ -33,6 +33,7 @@ constexpr char* CONNECTION_BLOCK_MEM_INSTANCE_PREFIX = "mem_";
constexpr char* MEMORY_MODULE_POSTFIX = "_mem";
constexpr char* MEMORY_BL_PORT_NAME = "bl";
constexpr char* MEMORY_WL_PORT_NAME = "wl";
+constexpr char* MEMORY_WLR_PORT_NAME = "wlr";
/* Multiplexer naming constant strings */
constexpr char* MUX_BASIS_MODULE_POSTFIX = "_basis";
@@ -48,6 +49,8 @@ constexpr char* DECODER_DATA_OUT_PORT_NAME = "data_out";
constexpr char* DECODER_DATA_OUT_INV_PORT_NAME = "data_out_inv";
constexpr char* DECODER_BL_ADDRESS_PORT_NAME = "bl_address";
constexpr char* DECODER_WL_ADDRESS_PORT_NAME = "wl_address";
+constexpr char* DECODER_READBACK_PORT_NAME = "readback";
+constexpr char* DECODER_DATA_READ_ENABLE_PORT_NAME = "data_out_ren";
/* Inverted port naming */
constexpr char* INV_PORT_POSTFIX = "_inv";
diff --git a/openfpga/src/base/openfpga_naming.cpp b/openfpga/src/base/openfpga_naming.cpp
index c898066b3..3dab1ca7f 100644
--- a/openfpga/src/base/openfpga_naming.cpp
+++ b/openfpga/src/base/openfpga_naming.cpp
@@ -719,9 +719,11 @@ std::string generate_sram_port_name(const e_config_protocol_type& sram_orgz_type
*/
if (CIRCUIT_MODEL_PORT_BL == port_type) {
port_name = std::string(MEMORY_BL_PORT_NAME);
- } else {
- VTR_ASSERT( CIRCUIT_MODEL_PORT_WL == port_type );
+ } else if (CIRCUIT_MODEL_PORT_WL == port_type) {
port_name = std::string(MEMORY_WL_PORT_NAME);
+ } else {
+ VTR_ASSERT( CIRCUIT_MODEL_PORT_WLR == port_type );
+ port_name = std::string(MEMORY_WLR_PORT_NAME);
}
break;
case CONFIG_MEM_FRAME_BASED:
diff --git a/openfpga/src/fabric/build_decoder_modules.cpp b/openfpga/src/fabric/build_decoder_modules.cpp
index 949058ba8..85ed342aa 100644
--- a/openfpga/src/fabric/build_decoder_modules.cpp
+++ b/openfpga/src/fabric/build_decoder_modules.cpp
@@ -184,6 +184,19 @@ ModuleId build_wl_memory_decoder_module(ModuleManager& module_manager,
module_manager.add_port(module_id, data_inv_port, ModuleManager::MODULE_OUTPUT_PORT);
}
+ /* Add readback port */
+ if (true == decoder_lib.use_readback(decoder)) {
+ BasicPort readback_port(std::string(DECODER_READBACK_PORT_NAME), 1);
+ module_manager.add_port(module_id, readback_port, ModuleManager::MODULE_INPUT_PORT);
+ }
+
+ /* Add data read-enable port */
+ if (true == decoder_lib.use_readback(decoder)) {
+ BasicPort data_ren_port(std::string(DECODER_DATA_READ_ENABLE_PORT_NAME), data_size);
+ module_manager.add_port(module_id, data_ren_port, ModuleManager::MODULE_OUTPUT_PORT);
+ module_manager.set_port_is_register(module_id, data_ren_port.get_name(), true);
+ }
+
return module_id;
}
diff --git a/openfpga/src/fabric/build_memory_modules.cpp b/openfpga/src/fabric/build_memory_modules.cpp
index 8a354da75..a8f7fceb4 100644
--- a/openfpga/src/fabric/build_memory_modules.cpp
+++ b/openfpga/src/fabric/build_memory_modules.cpp
@@ -366,12 +366,15 @@ void build_memory_flatten_module(ModuleManager& module_manager,
/* Get the BL/WL ports from the SRAM */
std::vector sram_bl_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_BL, true);
std::vector sram_wl_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_WL, true);
+ /* Optional: Get the WLR ports from the SRAM */
+ std::vector sram_wlr_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_WLR, true);
/* Get the output ports from the SRAM */
std::vector sram_output_ports = circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_OUTPUT, true);
- /* Ensure that we have only 1 BL, 1 WL and 2 output ports*/
+ /* Ensure that we have only 1 BL, 1 WL and 2 output ports, as well as an optional WLR*/
VTR_ASSERT(1 == sram_bl_ports.size());
VTR_ASSERT(1 == sram_wl_ports.size());
+ VTR_ASSERT(2 > sram_wlr_ports.size());
VTR_ASSERT(2 == sram_output_ports.size());
/* Create a module and add to the module manager */
@@ -389,6 +392,12 @@ void build_memory_flatten_module(ModuleManager& module_manager,
BasicPort wl_port(std::string(MEMORY_WL_PORT_NAME), num_mems);
ModulePortId mem_wl_port = module_manager.add_port(mem_module, wl_port, ModuleManager::MODULE_INPUT_PORT);
+ BasicPort wlr_port(std::string(MEMORY_WLR_PORT_NAME), num_mems);
+ ModulePortId mem_wlr_port = ModulePortId::INVALID();
+ if (!sram_wlr_ports.empty()) {
+ mem_wlr_port = module_manager.add_port(mem_module, wlr_port, ModuleManager::MODULE_INPUT_PORT);
+ }
+
/* Add each output port: port width should match the number of memories */
for (size_t iport = 0; iport < sram_output_ports.size(); ++iport) {
std::string port_name;
@@ -419,6 +428,9 @@ void build_memory_flatten_module(ModuleManager& module_manager,
for (const CircuitPortId& port : sram_wl_ports) {
add_module_input_nets_to_mem_modules(module_manager, mem_module, mem_wl_port, circuit_lib, port, sram_mem_module, i, sram_mem_instance);
}
+ for (const CircuitPortId& port : sram_wlr_ports) {
+ add_module_input_nets_to_mem_modules(module_manager, mem_module, mem_wlr_port, circuit_lib, port, sram_mem_module, i, sram_mem_instance);
+ }
/* Wire outputs of child module to outputs of parent module */
add_module_output_nets_to_mem_modules(module_manager, mem_module, circuit_lib, sram_output_ports, sram_mem_module, i, sram_mem_instance);
}
@@ -644,9 +656,9 @@ void build_frame_memory_module(ModuleManager& module_manager,
* If we find one, we use the module.
* Otherwise, we create one and add it to the decoder library
*/
- DecoderId decoder_id = frame_decoder_lib.find_decoder(addr_size, data_size, true, false, use_data_inv);
+ DecoderId decoder_id = frame_decoder_lib.find_decoder(addr_size, data_size, true, false, use_data_inv, false);
if (DecoderId::INVALID() == decoder_id) {
- decoder_id = frame_decoder_lib.add_decoder(addr_size, data_size, true, false, use_data_inv);
+ decoder_id = frame_decoder_lib.add_decoder(addr_size, data_size, true, false, use_data_inv, false);
}
VTR_ASSERT(DecoderId::INVALID() != decoder_id);
diff --git a/openfpga/src/fabric/build_top_module_memory.cpp b/openfpga/src/fabric/build_top_module_memory.cpp
index bcc093062..c9ee2b722 100644
--- a/openfpga/src/fabric/build_top_module_memory.cpp
+++ b/openfpga/src/fabric/build_top_module_memory.cpp
@@ -870,6 +870,12 @@ void add_top_module_sram_ports(ModuleManager& module_manager,
BasicPort wl_addr_port(std::string(DECODER_WL_ADDRESS_PORT_NAME), wl_addr_size);
module_manager.add_port(module_id, wl_addr_port, ModuleManager::MODULE_INPUT_PORT);
+ /* Optional: If we have WLR port, we should add a read-back port */
+ if (!circuit_lib.model_ports_by_type(sram_model, CIRCUIT_MODEL_PORT_WLR).empty()) {
+ BasicPort readback_port(std::string(DECODER_READBACK_PORT_NAME), config_protocol.num_regions());
+ module_manager.add_port(module_id, readback_port, ModuleManager::MODULE_INPUT_PORT);
+ }
+
/* Data input should be dependent on the number of configuration regions*/
BasicPort din_port(std::string(DECODER_DATA_IN_PORT_NAME), config_protocol.num_regions());
module_manager.add_port(module_id, din_port, ModuleManager::MODULE_INPUT_PORT);
@@ -1056,9 +1062,9 @@ void add_top_module_nets_cmos_memory_bank_config_bus(ModuleManager& module_manag
* Otherwise, we create one and add it to the decoder library
*/
DecoderId bl_decoder_id = decoder_lib.find_decoder(bl_addr_size, num_bls,
- true, true, false);
+ true, true, false, false);
if (DecoderId::INVALID() == bl_decoder_id) {
- bl_decoder_id = decoder_lib.add_decoder(bl_addr_size, num_bls, true, true, false);
+ bl_decoder_id = decoder_lib.add_decoder(bl_addr_size, num_bls, true, true, false, false);
}
VTR_ASSERT(DecoderId::INVALID() != bl_decoder_id);
@@ -1084,9 +1090,9 @@ void add_top_module_nets_cmos_memory_bank_config_bus(ModuleManager& module_manag
* Otherwise, we create one and add it to the decoder library
*/
DecoderId wl_decoder_id = decoder_lib.find_decoder(wl_addr_size, num_wls,
- true, false, false);
+ true, false, false, false);
if (DecoderId::INVALID() == wl_decoder_id) {
- wl_decoder_id = decoder_lib.add_decoder(wl_addr_size, num_wls, true, false, false);
+ wl_decoder_id = decoder_lib.add_decoder(wl_addr_size, num_wls, true, false, false, false);
}
VTR_ASSERT(DecoderId::INVALID() != wl_decoder_id);
@@ -1533,9 +1539,9 @@ void add_top_module_nets_cmos_memory_frame_decoder_config_bus(ModuleManager& mod
/* Search the decoder library and try to find one
* If not found, create a new module and add it to the module manager
*/
- DecoderId decoder_id = decoder_lib.find_decoder(addr_size, data_size, true, false, false);
+ DecoderId decoder_id = decoder_lib.find_decoder(addr_size, data_size, true, false, false, false);
if (DecoderId::INVALID() == decoder_id) {
- decoder_id = decoder_lib.add_decoder(addr_size, data_size, true, false, false);
+ decoder_id = decoder_lib.add_decoder(addr_size, data_size, true, false, false, false);
}
VTR_ASSERT(DecoderId::INVALID() != decoder_id);
diff --git a/openfpga/src/fabric/build_top_module_memory_bank.cpp b/openfpga/src/fabric/build_top_module_memory_bank.cpp
index c1bfac4b2..7c60a03d8 100644
--- a/openfpga/src/fabric/build_top_module_memory_bank.cpp
+++ b/openfpga/src/fabric/build_top_module_memory_bank.cpp
@@ -137,6 +137,16 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma
/* Data in port should match the number of configuration regions */
VTR_ASSERT(din_port_info.get_width() == module_manager.regions(top_module).size());
+ /* Find readback port from the top-level module */
+ ModulePortId readback_port = module_manager.find_module_port(top_module, std::string(DECODER_READBACK_PORT_NAME));
+ BasicPort readback_port_info;
+
+ /* Readback port if available, should be a 1-bit port */
+ if (readback_port) {
+ readback_port_info = module_manager.module_port(top_module, readback_port);
+ VTR_ASSERT(readback_port_info.get_width() == 1);
+ }
+
/* Find BL and WL address port from the top-level module */
ModulePortId bl_addr_port = module_manager.find_module_port(top_module, std::string(DECODER_BL_ADDRESS_PORT_NAME));
BasicPort bl_addr_port_info = module_manager.module_port(top_module, bl_addr_port);
@@ -168,9 +178,9 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma
* Otherwise, we create one and add it to the decoder library
*/
DecoderId bl_decoder_id = decoder_lib.find_decoder(bl_addr_size, num_bls,
- true, true, false);
+ true, true, false, false);
if (DecoderId::INVALID() == bl_decoder_id) {
- bl_decoder_id = decoder_lib.add_decoder(bl_addr_size, num_bls, true, true, false);
+ bl_decoder_id = decoder_lib.add_decoder(bl_addr_size, num_bls, true, true, false, false);
}
VTR_ASSERT(DecoderId::INVALID() != bl_decoder_id);
@@ -196,9 +206,9 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma
* Otherwise, we create one and add it to the decoder library
*/
DecoderId wl_decoder_id = decoder_lib.find_decoder(wl_addr_size, num_wls,
- true, false, false);
+ true, false, false, readback_port != ModulePortId::INVALID());
if (DecoderId::INVALID() == wl_decoder_id) {
- wl_decoder_id = decoder_lib.add_decoder(wl_addr_size, num_wls, true, false, false);
+ wl_decoder_id = decoder_lib.add_decoder(wl_addr_size, num_wls, true, false, false, readback_port != ModulePortId::INVALID());
}
VTR_ASSERT(DecoderId::INVALID() != wl_decoder_id);
@@ -264,7 +274,13 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma
BasicPort wl_decoder_en_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_en_port);
ModulePortId wl_decoder_addr_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_ADDRESS_PORT_NAME));
- BasicPort wl_decoder_addr_port_info = module_manager.module_port(wl_decoder_module, bl_decoder_addr_port);
+ BasicPort wl_decoder_addr_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_addr_port);
+
+ ModulePortId wl_decoder_readback_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_READBACK_PORT_NAME));
+ BasicPort wl_decoder_readback_port_info;
+ if (wl_decoder_readback_port) {
+ wl_decoder_readback_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_readback_port);
+ }
/* Top module Enable port -> WL Decoder Enable port */
add_module_bus_nets(module_manager,
@@ -278,6 +294,14 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma
top_module, 0, wl_addr_port,
wl_decoder_module, curr_wl_decoder_instance_id, wl_decoder_addr_port);
+ /* Top module readback port -> WL Decoder readback port */
+ if (wl_decoder_readback_port) {
+ add_module_bus_nets(module_manager,
+ top_module,
+ top_module, 0, readback_port,
+ wl_decoder_module, curr_wl_decoder_instance_id, wl_decoder_readback_port);
+ }
+
/**************************************************************
* Precompute the BLs and WLs distribution across the FPGA fabric
* The distribution is a matrix which contains the starting index of BL/WL for each column or row
@@ -391,6 +415,45 @@ void add_top_module_nets_cmos_ql_memory_bank_config_bus(ModuleManager& module_ma
}
}
+ /**************************************************************
+ * Optional: Add nets from WLR data out to each configurable child
+ */
+ ModulePortId wl_decoder_data_ren_port = module_manager.find_module_port(wl_decoder_module, std::string(DECODER_DATA_READ_ENABLE_PORT_NAME));
+ BasicPort wl_decoder_data_ren_port_info;
+ if (wl_decoder_data_ren_port) {
+ wl_decoder_data_ren_port_info = module_manager.module_port(wl_decoder_module, wl_decoder_data_ren_port);
+ for (size_t child_id = 0; child_id < module_manager.region_configurable_children(top_module, config_region).size(); ++child_id) {
+ ModuleId child_module = module_manager.region_configurable_children(top_module, config_region)[child_id];
+ vtr::Point coord = module_manager.region_configurable_child_coordinates(top_module, config_region)[child_id];
+
+ size_t child_instance = module_manager.region_configurable_child_instances(top_module, config_region)[child_id];
+
+ /* Find the WL port */
+ ModulePortId child_wlr_port = module_manager.find_module_port(child_module, std::string(MEMORY_WLR_PORT_NAME));
+ BasicPort child_wlr_port_info = module_manager.module_port(child_module, child_wlr_port);
+
+ size_t cur_wlr_index = 0;
+
+ for (const size_t& sink_wlr_pin : child_wlr_port_info.pins()) {
+ size_t wlr_pin_id = wl_start_index_per_tile[coord.y()] + cur_wlr_index;
+ VTR_ASSERT(wlr_pin_id < wl_decoder_data_ren_port_info.pins().size());
+
+ /* Create net */
+ ModuleNetId net = create_module_source_pin_net(module_manager, top_module,
+ wl_decoder_module, curr_wl_decoder_instance_id,
+ wl_decoder_data_ren_port,
+ wl_decoder_data_ren_port_info.pins()[wlr_pin_id]);
+ VTR_ASSERT(ModuleNetId::INVALID() != net);
+
+ /* Add net sink */
+ module_manager.add_module_net_sink(top_module, net,
+ child_module, child_instance, child_wlr_port, sink_wlr_pin);
+
+ cur_wlr_index++;
+ }
+ }
+ }
+
/**************************************************************
* Add the BL and WL decoders to the end of configurable children list
* Note: this MUST be done after adding all the module nets to other regular configurable children
diff --git a/openfpga/src/fpga_verilog/verilog_decoders.cpp b/openfpga/src/fpga_verilog/verilog_decoders.cpp
index 6960ba19e..9b6f4da45 100644
--- a/openfpga/src/fpga_verilog/verilog_decoders.cpp
+++ b/openfpga/src/fpga_verilog/verilog_decoders.cpp
@@ -289,6 +289,20 @@ void print_verilog_arch_decoder_module(std::fstream& fp,
data_inv_port = module_manager.module_port(module_id, data_inv_port_id);
}
+ /* Find readback port */
+ ModulePortId readback_port_id = module_manager.find_module_port(module_id, std::string(DECODER_READBACK_PORT_NAME));
+ BasicPort readback_port;
+ if (readback_port_id) {
+ readback_port = module_manager.module_port(module_id, readback_port_id);
+ }
+
+ /* Find data read-enable port */
+ ModulePortId data_ren_port_id = module_manager.find_module_port(module_id, std::string(DECODER_DATA_READ_ENABLE_PORT_NAME));
+ BasicPort data_ren_port;
+ if (data_ren_port_id) {
+ data_ren_port = module_manager.module_port(module_id, data_ren_port_id);
+ }
+
/* dump module definition + ports */
print_verilog_module_declaration(fp, module_manager, module_id, default_net_type);
/* Finish dumping ports */
@@ -303,10 +317,18 @@ void print_verilog_arch_decoder_module(std::fstream& fp,
* else data_out is driven by '0'
*/
if (1 == data_size) {
+ /* Output logics for data output */
fp << "always@(" << generate_verilog_port(VERILOG_PORT_CONKT, addr_port);
fp << " or " << generate_verilog_port(VERILOG_PORT_CONKT, enable_port);
+ /* If there is a readback port, the data output is only enabled when readback is disabled */
+ if (readback_port_id) {
+ fp << " or " << "~" << generate_verilog_port(VERILOG_PORT_CONKT, readback_port);
+ }
fp << ") begin" << std::endl;
fp << "\tif ((" << generate_verilog_port(VERILOG_PORT_CONKT, enable_port) << " == 1'b1) && (";
+ if (readback_port_id) {
+ fp << generate_verilog_port(VERILOG_PORT_CONKT, readback_port) << " == 1'b0) && (";
+ }
fp << generate_verilog_port(VERILOG_PORT_CONKT, addr_port) << " == 1'b0))";
fp << " begin" << std::endl;
fp << "\t\t" << generate_verilog_port_constant_values(data_port, std::vector(1, 1)) << ";" << std::endl;
@@ -315,6 +337,26 @@ void print_verilog_arch_decoder_module(std::fstream& fp,
fp << "\t" << "end" << std::endl;
fp << "end" << std::endl;
+ /* Output logics for data readback output */
+ if (data_ren_port_id) {
+ fp << "always@(" << generate_verilog_port(VERILOG_PORT_CONKT, addr_port);
+ fp << " or " << generate_verilog_port(VERILOG_PORT_CONKT, enable_port);
+ /* If there is a readback port, the data output is only enabled when readback is disabled */
+ if (readback_port_id) {
+ fp << " or " << generate_verilog_port(VERILOG_PORT_CONKT, readback_port);
+ }
+ fp << ") begin" << std::endl;
+ fp << "\tif ((" << generate_verilog_port(VERILOG_PORT_CONKT, enable_port) << " == 1'b1) && (";
+ fp << generate_verilog_port(VERILOG_PORT_CONKT, readback_port) << " == 1'b1) && (";
+ fp << generate_verilog_port(VERILOG_PORT_CONKT, addr_port) << " == 1'b0))";
+ fp << " begin" << std::endl;
+ fp << "\t\t" << generate_verilog_port_constant_values(data_ren_port, std::vector(1, 1)) << ";" << std::endl;
+ fp << "\t" << "end else begin" << std::endl;
+ fp << "\t\t" << generate_verilog_port_constant_values(data_ren_port, std::vector(1, 0)) << ";" << std::endl;
+ fp << "\t" << "end" << std::endl;
+ fp << "end" << std::endl;
+ }
+
/* Depend on if the inverted data output port is needed or not */
if (true == decoder_lib.use_data_inv_port(decoder)) {
print_verilog_wire_connection(fp, data_inv_port, addr_port, true);
@@ -344,10 +386,23 @@ void print_verilog_arch_decoder_module(std::fstream& fp,
* The rest of addr codes 3'b110, 3'b111 will be decoded to data=8'b0_0000;
*/
+ /* Output logics for data output */
fp << "always@(" << generate_verilog_port(VERILOG_PORT_CONKT, addr_port);
+ /* If there is a readback port, the data output is only enabled when readback is disabled */
+ if (readback_port_id) {
+ fp << " or " << "~" << generate_verilog_port(VERILOG_PORT_CONKT, readback_port);
+ }
fp << " or " << generate_verilog_port(VERILOG_PORT_CONKT, enable_port);
fp << ") begin" << std::endl;
- fp << "\tif (" << generate_verilog_port(VERILOG_PORT_CONKT, enable_port) << " == 1'b1) begin" << std::endl;
+ if (readback_port_id) {
+ fp << "\tif (";
+ fp << "(" << generate_verilog_port(VERILOG_PORT_CONKT, enable_port) << " == 1'b1) ";
+ fp << "&&";
+ fp << "(" << generate_verilog_port(VERILOG_PORT_CONKT, readback_port) << " == 1'b0) ";
+ fp << ") begin" << std::endl;
+ } else {
+ fp << "\tif (" << generate_verilog_port(VERILOG_PORT_CONKT, enable_port) << " == 1'b1) begin" << std::endl;
+ }
fp << "\t\t" << "case (" << generate_verilog_port(VERILOG_PORT_CONKT, addr_port) << ")" << std::endl;
/* Create a string for addr and data */
for (size_t i = 0; i < data_size; ++i) {
@@ -373,6 +428,46 @@ void print_verilog_arch_decoder_module(std::fstream& fp,
fp << "end" << std::endl;
+ /* Output logics for data readback output */
+ if (data_ren_port_id) {
+ fp << "always@(" << generate_verilog_port(VERILOG_PORT_CONKT, addr_port);
+ /* If there is a readback port, the data output is only enabled when readback is disabled */
+ if (readback_port_id) {
+ fp << " or " << generate_verilog_port(VERILOG_PORT_CONKT, readback_port);
+ }
+ fp << " or " << generate_verilog_port(VERILOG_PORT_CONKT, enable_port);
+ fp << ") begin" << std::endl;
+ fp << "\tif (";
+ fp << "(" << generate_verilog_port(VERILOG_PORT_CONKT, enable_port) << " == 1'b1) ";
+ fp << "&&";
+ fp << "(" << generate_verilog_port(VERILOG_PORT_CONKT, readback_port) << " == 1'b1) ";
+ fp << ") begin" << std::endl;
+ fp << "\t\t" << "case (" << generate_verilog_port(VERILOG_PORT_CONKT, addr_port) << ")" << std::endl;
+ /* Create a string for addr and data */
+ for (size_t i = 0; i < data_size; ++i) {
+ fp << "\t\t\t" << generate_verilog_constant_values(itobin_vec(i, addr_size));
+ fp << " : ";
+ fp << generate_verilog_port_constant_values(data_ren_port, ito1hot_vec(i, data_size));
+ fp << ";" << std::endl;
+ }
+ /* Different from MUX decoder, we assign default values which is all zero */
+ fp << "\t\t\t" << "default";
+ fp << " : ";
+ fp << generate_verilog_port_constant_values(data_ren_port, ito1hot_vec(data_size, data_size));
+ fp << ";" << std::endl;
+
+ fp << "\t\t" << "endcase" << std::endl;
+ fp << "\t" << "end" << std::endl;
+
+ /* If enable is not active, we should give all zero */
+ fp << "\t" << "else begin" << std::endl;
+ fp << "\t\t" << generate_verilog_port_constant_values(data_ren_port, ito1hot_vec(data_size, data_size));
+ fp << ";" << std::endl;
+ fp << "\t" << "end" << std::endl;
+
+ fp << "end" << std::endl;
+ }
+
if (true == decoder_lib.use_data_inv_port(decoder)) {
print_verilog_wire_connection(fp, data_inv_port, data_port, true);
}
diff --git a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp
index 289e4d667..eb070690d 100644
--- a/openfpga/src/fpga_verilog/verilog_top_testbench.cpp
+++ b/openfpga/src/fpga_verilog/verilog_top_testbench.cpp
@@ -128,6 +128,17 @@ void print_verilog_top_testbench_memory_bank_port(std::fstream& fp,
BasicPort din_port = module_manager.module_port(top_module, din_port_id);
fp << generate_verilog_port(VERILOG_PORT_REG, din_port) << ";" << std::endl;
+ /* Print the optional readback port for the decoder here */
+ print_verilog_comment(fp, std::string("---- Readback port for memory decoders -----"));
+ ModulePortId readback_port_id = module_manager.find_module_port(top_module,
+ std::string(DECODER_READBACK_PORT_NAME));
+ if (readback_port_id) {
+ BasicPort readback_port = module_manager.module_port(top_module, readback_port_id);
+ fp << generate_verilog_port(VERILOG_PORT_WIRE, readback_port) << ";" << std::endl;
+ /* Disable readback in full testbenches */
+ print_verilog_wire_constant_values(fp, readback_port, std::vector(readback_port.get_width(), 0));
+ }
+
/* Generate enable signal waveform here:
* which is a 90 degree phase shift than the programming clock
*/
diff --git a/openfpga/src/mux_lib/decoder_library.cpp b/openfpga/src/mux_lib/decoder_library.cpp
index a7c4a8840..8d6017f40 100644
--- a/openfpga/src/mux_lib/decoder_library.cpp
+++ b/openfpga/src/mux_lib/decoder_library.cpp
@@ -47,6 +47,11 @@ bool DecoderLibrary::use_data_inv_port(const DecoderId& decoder) const {
return use_data_inv_port_[decoder];
}
+bool DecoderLibrary::use_readback(const DecoderId& decoder) const {
+ VTR_ASSERT_SAFE(valid_decoder_id(decoder));
+ return use_readback_[decoder];
+}
+
/* Find a decoder to the library, with the specification.
* If found, return the id of decoder.
* If not found, return an invalid id of decoder
@@ -61,13 +66,15 @@ DecoderId DecoderLibrary::find_decoder(const size_t& addr_size,
const size_t& data_size,
const bool& use_enable,
const bool& use_data_in,
- const bool& use_data_inv_port) const {
+ const bool& use_data_inv_port,
+ const bool& use_readback) const {
for (auto decoder : decoders()) {
if ( (addr_size == addr_sizes_[decoder])
&& (data_size == data_sizes_[decoder])
&& (use_enable == use_enable_[decoder])
&& (use_data_in == use_data_in_[decoder])
- && (use_data_inv_port == use_data_inv_port_[decoder]) ) {
+ && (use_data_inv_port == use_data_inv_port_[decoder])
+ && (use_readback == use_readback_[decoder]) ) {
return decoder;
}
}
@@ -92,7 +99,8 @@ DecoderId DecoderLibrary::add_decoder(const size_t& addr_size,
const size_t& data_size,
const bool& use_enable,
const bool& use_data_in,
- const bool& use_data_inv_port) {
+ const bool& use_data_inv_port,
+ const bool& use_readback) {
DecoderId decoder = DecoderId(decoder_ids_.size());
/* Push to the decoder list */
decoder_ids_.push_back(decoder);
@@ -102,6 +110,7 @@ DecoderId DecoderLibrary::add_decoder(const size_t& addr_size,
use_enable_.push_back(use_enable);
use_data_in_.push_back(use_data_in);
use_data_inv_port_.push_back(use_data_inv_port);
+ use_readback_.push_back(use_readback);
return decoder;
}
diff --git a/openfpga/src/mux_lib/decoder_library.h b/openfpga/src/mux_lib/decoder_library.h
index 397308db5..7340f4375 100644
--- a/openfpga/src/mux_lib/decoder_library.h
+++ b/openfpga/src/mux_lib/decoder_library.h
@@ -50,6 +50,8 @@ class DecoderLibrary {
bool use_data_in(const DecoderId& decoder) const;
/* Get the flag if a decoder includes a data_inv port which is an inversion of the regular data output port */
bool use_data_inv_port(const DecoderId& decoder) const;
+ /* Get the flag if a decoder includes a readback port which enables readback from configurable memories */
+ bool use_readback(const DecoderId& decoder) const;
/* Find a decoder to the library, with the specification.
* If found, return the id of decoder.
* If not found, return an invalid id of decoder
@@ -64,7 +66,8 @@ class DecoderLibrary {
const size_t& data_size,
const bool& use_enable,
const bool& use_data_in,
- const bool& use_data_inv_port) const;
+ const bool& use_data_inv_port,
+ const bool& use_readback) const;
public: /* Public validators */
/* valid ids */
@@ -76,7 +79,8 @@ class DecoderLibrary {
const size_t& data_size,
const bool& use_enable,
const bool& use_data_in,
- const bool& use_data_inv_port);
+ const bool& use_data_inv_port,
+ const bool& use_readback);
private: /* Internal Data */
vtr::vector decoder_ids_;
@@ -85,6 +89,7 @@ class DecoderLibrary {
vtr::vector use_enable_;
vtr::vector use_data_in_;
vtr::vector use_data_inv_port_;
+ vtr::vector use_readback_;
};
} /* End namespace openfpga*/
diff --git a/openfpga/src/utils/decoder_library_utils.cpp b/openfpga/src/utils/decoder_library_utils.cpp
index 502620661..b44bb106c 100644
--- a/openfpga/src/utils/decoder_library_utils.cpp
+++ b/openfpga/src/utils/decoder_library_utils.cpp
@@ -112,11 +112,11 @@ DecoderId add_mux_local_decoder_to_library(DecoderLibrary& decoder_lib,
const size_t data_size) {
size_t addr_size = find_mux_local_decoder_addr_size(data_size);
- DecoderId decoder_id = decoder_lib.find_decoder(addr_size, data_size, false, false, true);
+ DecoderId decoder_id = decoder_lib.find_decoder(addr_size, data_size, false, false, true, false);
if (DecoderId::INVALID() == decoder_id) {
/* Add the decoder */
- return decoder_lib.add_decoder(addr_size, data_size, false, false, true);
+ return decoder_lib.add_decoder(addr_size, data_size, false, false, true, false);
}
/* There is already a decoder in the library, return the decoder id */
diff --git a/openfpga/src/utils/memory_utils.cpp b/openfpga/src/utils/memory_utils.cpp
index bcca022ab..8e2038b06 100644
--- a/openfpga/src/utils/memory_utils.cpp
+++ b/openfpga/src/utils/memory_utils.cpp
@@ -330,7 +330,8 @@ std::vector generate_sram_port_names(const CircuitLibrary& circuit_
std::vector ports_to_search;
ports_to_search.push_back(CIRCUIT_MODEL_PORT_BL);
ports_to_search.push_back(CIRCUIT_MODEL_PORT_WL);
- /* Try to find a BL/WL/BLB/WLB port and update the port types/module port types to be added */
+ ports_to_search.push_back(CIRCUIT_MODEL_PORT_WLR);
+ /* Try to find a BL/WL/WLR port and update the port types/module port types to be added */
for (const auto& port_to_search : ports_to_search) {
std::vector found_port = circuit_lib.model_ports_by_type(sram_model, port_to_search);
if (0 == found_port.size()) {
diff --git a/openfpga/src/utils/module_manager_utils.cpp b/openfpga/src/utils/module_manager_utils.cpp
index 421e7b95f..4c25c3a4a 100644
--- a/openfpga/src/utils/module_manager_utils.cpp
+++ b/openfpga/src/utils/module_manager_utils.cpp
@@ -195,6 +195,7 @@ ModuleId add_circuit_model_to_module_manager(ModuleManager& module_manager,
port_type2type_map[CIRCUIT_MODEL_PORT_BLB] = ModuleManager::MODULE_INPUT_PORT;
port_type2type_map[CIRCUIT_MODEL_PORT_WL] = ModuleManager::MODULE_INPUT_PORT;
port_type2type_map[CIRCUIT_MODEL_PORT_WLB] = ModuleManager::MODULE_INPUT_PORT;
+ port_type2type_map[CIRCUIT_MODEL_PORT_WLR] = ModuleManager::MODULE_INPUT_PORT;
port_type2type_map[CIRCUIT_MODEL_PORT_OUTPUT] = ModuleManager::MODULE_OUTPUT_PORT;
/* Input ports (ignore all the global ports when searching the circuit_lib */
@@ -390,8 +391,9 @@ void add_pb_sram_ports_to_module_manager(ModuleManager& module_manager,
for (const std::string& sram_port_name : sram_port_names) {
/* Add generated ports to the ModuleManager */
BasicPort sram_port(sram_port_name, sram_port_size);
- /* For WL ports, we need to fine-tune it */
- if (CIRCUIT_MODEL_PORT_WL == circuit_lib.port_type(circuit_lib.model_port(sram_model, sram_port_name))) {
+ /* For WL and WLR ports, we need to fine-tune it */
+ if ( (CIRCUIT_MODEL_PORT_WL == circuit_lib.port_type(circuit_lib.model_port(sram_model, sram_port_name)))
+ || (CIRCUIT_MODEL_PORT_WLR == circuit_lib.port_type(circuit_lib.model_port(sram_model, sram_port_name))) ) {
sram_port.set_width(find_memory_wl_decoder_data_size(num_config_bits, sram_port_size));
}
module_manager.add_port(module_id, sram_port, ModuleManager::MODULE_INPUT_PORT);
@@ -885,7 +887,7 @@ void add_module_nets_between_logic_and_memory_sram_bus(ModuleManager& module_man
* | | |
* +------------+----------------------+
* |
- * WL
+ * WL/WLR
*
* Note:
* - This function will do the connection for only one type of the port,
@@ -900,15 +902,16 @@ void add_module_nets_cmos_flatten_memory_config_bus(ModuleManager& module_manage
/* A counter for the current pin id for the source port of parent module */
size_t cur_src_pin_id = 0;
- ModuleId net_src_module_id;
- size_t net_src_instance_id;
- ModulePortId net_src_port_id;
-
/* Find the port name of parent module */
std::string src_port_name = generate_sram_port_name(sram_orgz_type, config_port_type);
- net_src_module_id = parent_module;
- net_src_instance_id = 0;
- net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name);
+ ModuleId net_src_module_id = parent_module;
+ size_t net_src_instance_id = 0;
+ ModulePortId net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name);
+
+ /* We may not be able to find WLR port, return now */
+ if (!net_src_port_id) {
+ return;
+ }
/* Get the pin id for source port */
BasicPort net_src_port = module_manager.module_port(net_src_module_id, net_src_port_id);
@@ -1025,7 +1028,7 @@ void add_module_nets_cmos_memory_bank_bl_config_bus(ModuleManager& module_manage
* | | |
* +------------+----------------------+
* |
- * WL<0>
+ * WL<0>/WLR<0>
*
* +--------+ +--------+ +--------+
* | Memory | | Memory | ... | Memory |
@@ -1036,7 +1039,7 @@ void add_module_nets_cmos_memory_bank_bl_config_bus(ModuleManager& module_manage
* | | |
* +------------+----------------------+
* |
- * WL<1>
+ * WL<1>/WLR<1>
*
*********************************************************************/
void add_module_nets_cmos_memory_bank_wl_config_bus(ModuleManager& module_manager,
@@ -1055,6 +1058,11 @@ void add_module_nets_cmos_memory_bank_wl_config_bus(ModuleManager& module_manage
ModulePortId net_src_port_id = module_manager.find_module_port(net_src_module_id, src_port_name);
ModulePortId net_bl_port_id = module_manager.find_module_port(net_src_module_id, bl_port_name);
+ /* We may not be able to find WLR port, return now */
+ if (!net_src_port_id) {
+ return;
+ }
+
/* Get the pin id for source port */
BasicPort net_src_port = module_manager.module_port(net_src_module_id, net_src_port_id);
BasicPort net_bl_port = module_manager.module_port(net_src_module_id, net_bl_port_id);
@@ -1300,9 +1308,9 @@ void add_module_nets_cmos_memory_frame_decoder_config_bus(ModuleManager& module_
/* Search the decoder library and try to find one
* If not found, create a new module and add it to the module manager
*/
- DecoderId decoder_id = decoder_lib.find_decoder(addr_size, data_size, true, false, false);
+ DecoderId decoder_id = decoder_lib.find_decoder(addr_size, data_size, true, false, false, false);
if (DecoderId::INVALID() == decoder_id) {
- decoder_id = decoder_lib.add_decoder(addr_size, data_size, true, false, false);
+ decoder_id = decoder_lib.add_decoder(addr_size, data_size, true, false, false, false);
}
VTR_ASSERT(DecoderId::INVALID() != decoder_id);
@@ -1519,6 +1527,8 @@ void add_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
sram_orgz_type, CIRCUIT_MODEL_PORT_BL);
add_module_nets_cmos_flatten_memory_config_bus(module_manager, parent_module,
sram_orgz_type, CIRCUIT_MODEL_PORT_WL);
+ add_module_nets_cmos_flatten_memory_config_bus(module_manager, parent_module,
+ sram_orgz_type, CIRCUIT_MODEL_PORT_WLR);
break;
case CONFIG_MEM_FRAME_BASED:
add_module_nets_cmos_memory_frame_config_bus(module_manager, decoder_lib, parent_module);
@@ -1580,6 +1590,8 @@ void add_pb_module_nets_cmos_memory_config_bus(ModuleManager& module_manager,
sram_orgz_type, CIRCUIT_MODEL_PORT_BL);
add_module_nets_cmos_memory_bank_wl_config_bus(module_manager, parent_module,
sram_orgz_type, CIRCUIT_MODEL_PORT_WL);
+ add_module_nets_cmos_memory_bank_wl_config_bus(module_manager, parent_module,
+ sram_orgz_type, CIRCUIT_MODEL_PORT_WLR);
break;
case CONFIG_MEM_MEMORY_BANK:
add_module_nets_cmos_flatten_memory_config_bus(module_manager, parent_module,
diff --git a/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbank_wlr_openfpga.xml b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbank_wlr_openfpga.xml
new file mode 100644
index 000000000..62f449b25
--- /dev/null
+++ b/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbank_wlr_openfpga.xml
@@ -0,0 +1,199 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 10e-12
+
+
+ 10e-12
+
+
+
+
+
+
+
+
+ 10e-12
+
+
+ 10e-12
+
+
+
+
+
+
+
+
+ 10e-12
+
+
+ 10e-12
+
+
+
+
+
+
+
+
+
+
+
+
+ 10e-12 5e-12 5e-12
+
+
+ 10e-12 5e-12 5e-12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/openfpga_flow/openfpga_cell_library/verilog/sram.v b/openfpga_flow/openfpga_cell_library/verilog/sram.v
index 86f3ddf99..5f3c62852 100644
--- a/openfpga_flow/openfpga_cell_library/verilog/sram.v
+++ b/openfpga_flow/openfpga_cell_library/verilog/sram.v
@@ -256,6 +256,41 @@ module SRAMSR(
endmodule
+//-----------------------------------------------------
+// Function : A SRAM cell with WL read signal
+//-----------------------------------------------------
+module SRAM_RE(
+ input WE, // Word line control signal as write enable
+ input RE, // Word line read signal as read enable
+ inout D, // Bit line control signal
+ output Q, // Data output
+ output QN // Data output
+);
+
+ //----- local variable need to be registered
+ reg data;
+ reg data_readback;
+
+ //----- when wl is enabled, we can read in data from bl
+ always @(WE or RE or D)
+ begin
+ if ((1'b1 == D)&&(1'b1 == WE)) begin
+ //----- Cases to program internal memory bit
+ //----- case 1: bl = 1, wl = 1, a -> 0
+ data <= 1'b1;
+ end else if ((1'b0 == D)&&(1'b1 == WE)) begin
+ //----- case 2: bl = 0, wl = 1, a -> 0
+ data <= 1'b0;
+ end
+ end
+
+ // Wire q_reg to Q
+ assign Q = data;
+ assign QN = ~data;
+
+endmodule
+
+
//-----------------------------------------------------
// Function : A SRAM cell with
// - an active-low reset
diff --git a/openfpga_flow/regression_test_scripts/basic_reg_test.sh b/openfpga_flow/regression_test_scripts/basic_reg_test.sh
index 5bef6a05f..531ba5f42 100755
--- a/openfpga_flow/regression_test_scripts/basic_reg_test.sh
+++ b/openfpga_flow/regression_test_scripts/basic_reg_test.sh
@@ -55,6 +55,7 @@ run-task basic_tests/preconfig_testbench/memory_bank --debug --show_thread_logs
echo -e "Testing physical design friendly memory bank configuration protocol of a K4N4 FPGA";
run-task basic_tests/full_testbench/ql_memory_bank --debug --show_thread_logs
+run-task basic_tests/full_testbench/ql_memory_bank_use_wlr --debug --show_thread_logs
echo -e "Testing testbenches without self checking features";
run-task basic_tests/full_testbench/full_testbench_without_self_checking --debug --show_thread_logs
diff --git a/openfpga_flow/tasks/basic_tests/full_testbench/ql_memory_bank_use_wlr/config/task.conf b/openfpga_flow/tasks/basic_tests/full_testbench/ql_memory_bank_use_wlr/config/task.conf
new file mode 100644
index 000000000..9ed4b8323
--- /dev/null
+++ b/openfpga_flow/tasks/basic_tests/full_testbench/ql_memory_bank_use_wlr/config/task.conf
@@ -0,0 +1,44 @@
+# = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
+# 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/write_full_testbench_example_script.openfpga
+openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k4_N4_40nm_qlbank_wlr_openfpga.xml
+openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
+openfpga_vpr_device_layout=
+openfpga_fast_configuration=
+
+[ARCHITECTURES]
+arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k4_N4_tileable_40nm.xml
+
+[BENCHMARKS]
+bench0=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2/and2.v
+bench1=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/or2/or2.v
+bench2=${PATH:OPENFPGA_PATH}/openfpga_flow/benchmarks/micro_benchmark/and2_latch/and2_latch.v
+
+[SYNTHESIS_PARAM]
+bench0_top = and2
+bench0_chan_width = 300
+
+bench1_top = or2
+bench1_chan_width = 300
+
+bench2_top = and2_latch
+bench2_chan_width = 300
+
+[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
+end_flow_with_test=