diff --git a/docs/source/manual/arch_lang/circuit_library.rst b/docs/source/manual/arch_lang/circuit_library.rst
index 4ec803f99..0e515b84b 100644
--- a/docs/source/manual/arch_lang/circuit_library.rst
+++ b/docs/source/manual/arch_lang/circuit_library.rst
@@ -53,6 +53,7 @@ Here, we focus these common syntax and we will detail special syntax in :ref:`ci
+
@@ -129,12 +130,16 @@ Input and Output Buffers
Pass Gate Logic
^^^^^^^^^^^^^^^
+.. note:: pass-gate logic are used in building multiplexers and LUTs.
+
.. option::
- ``circuit_model_name=""`` Specify the name of the circuit model which is used to implement pass-gate logic, the type of specified circuit model should be ``pass_gate``.
-.. note:: pass-gate logic are used in building multiplexers and LUTs.
+.. option::
+
+ - ``circuit_model_name=""`` Specify the name of the circuit model which is used to implement the pass-gate logic at last stage of multiplexer, the type of specified circuit model should be ``pass_gate``. The type of the pass-gate logic circuit model must be a standard cell MUX2!
.. _circuit_library_circuit_port:
diff --git a/docs/source/manual/arch_lang/circuit_model_examples.rst b/docs/source/manual/arch_lang/circuit_model_examples.rst
index 94f1d5e02..5bc928c6c 100644
--- a/docs/source/manual/arch_lang/circuit_model_examples.rst
+++ b/docs/source/manual/arch_lang/circuit_model_examples.rst
@@ -619,6 +619,14 @@ This example shows:
Standard Cell Multiplexer
`````````````````````````
+.. _fig_stdcellmux:
+
+.. figure:: ./figures/stdcellmux.png
+ :width: 100%
+ :alt: Examples of MUX built with standard cells
+
+ An example of a multiplexer built with standard cells: (a) all the MUX2 are the same; (b) the MUX2 at the last stage is a different one
+
.. code-block:: xml
@@ -631,12 +639,34 @@ Standard Cell Multiplexer
-This example shows:
+This example shows (see an illustative example in :numref:`fig_stdcellmux` (a)):
- A tree-like 4-input CMOS multiplexer built by the standard cell ``MUX2``
- All the inputs will be buffered using the circuit model ``inv1x``
- All the outputs will be buffered using the circuit model ``tapbuf4``
- The multiplexer will have 4 inputs and 3 SRAMs to control which datapath to propagate
+Alternatively, user can specify a different standard cell MUX2 at the last stage.
+
+.. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+
+
+This example shows (see an illustative example in :numref:`fig_stdcellmux` (b)):
+ - A tree-like 4-input CMOS multiplexer built by the standard cell ``MUX2``
+ - The last stage A tree-like 4-input CMOS multiplexer built by the standard cell ``MUX2``
+ - All the inputs will be buffered using the circuit model ``inv1x``
+ - All the outputs will be buffered using the circuit model ``tapbuf4``
+ - The multiplexer will have 4 inputs and 3 SRAMs to control which datapath to propagate
+
.. _circuit_model_mux_multilevel_example:
Multi-level Multiplexer
diff --git a/docs/source/manual/arch_lang/figures/stdcellmux.png b/docs/source/manual/arch_lang/figures/stdcellmux.png
new file mode 100644
index 000000000..d2d08c7b1
Binary files /dev/null and b/docs/source/manual/arch_lang/figures/stdcellmux.png differ
diff --git a/libs/libarchopenfpga/src/check_circuit_library.cpp b/libs/libarchopenfpga/src/check_circuit_library.cpp
index 62a71a3a1..a9852a7e5 100644
--- a/libs/libarchopenfpga/src/check_circuit_library.cpp
+++ b/libs/libarchopenfpga/src/check_circuit_library.cpp
@@ -800,6 +800,60 @@ static size_t check_io_circuit_model(const CircuitLibrary& circuit_lib) {
return num_err;
}
+/************************************************************************
+ * Check the last stage pass gate logic model is the same type as default
+ ***********************************************************************/
+static size_t check_pass_gate_circuit_model_consistency(
+ const CircuitLibrary& circuit_lib) {
+ size_t num_err = 0;
+
+ for (const CircuitModelId& mux_model :
+ circuit_lib.models_by_type(CIRCUIT_MODEL_MUX)) {
+ CircuitModelId pgl_model = circuit_lib.pass_gate_logic_model(mux_model);
+ CircuitModelId last_stage_pgl_model =
+ circuit_lib.last_stage_pass_gate_logic_model(mux_model);
+ if (!circuit_lib.valid_model_id(pgl_model)) {
+ VTR_LOGF_ERROR(
+ __FILE__, __LINE__,
+ "The pass-gate logic circuit model '%s' of '%s' is not valid!\n",
+ circuit_lib.pass_gate_logic_model_name(mux_model).c_str(),
+ circuit_lib.model_name(mux_model).c_str());
+ num_err++;
+ }
+ if (!circuit_lib.valid_model_id(last_stage_pgl_model)) {
+ VTR_LOGF_ERROR(
+ __FILE__, __LINE__,
+ "The last stage pass-gate logic circuit model '%s' of '%s' is not "
+ "valid!\n",
+ circuit_lib.last_stage_pass_gate_logic_model_name(mux_model).c_str(),
+ circuit_lib.model_name(mux_model).c_str());
+ num_err++;
+ }
+ if (circuit_lib.model_type(pgl_model) !=
+ circuit_lib.model_type(last_stage_pgl_model)) {
+ VTR_LOGF_ERROR(
+ __FILE__, __LINE__,
+ "The last stage pass-gate logic circuit model '%s' of '%s' should be "
+ "the same type as its regular pass-gate logic model '%s'!\n",
+ circuit_lib.model_name(last_stage_pgl_model).c_str(),
+ circuit_lib.model_name(mux_model).c_str(),
+ circuit_lib.model_name(pgl_model).c_str());
+ num_err++;
+ }
+ if (pgl_model != last_stage_pgl_model &&
+ circuit_lib.gate_type(pgl_model) != CIRCUIT_MODEL_GATE_MUX2) {
+ VTR_LOGF_ERROR(__FILE__, __LINE__,
+ "The last stage pass-gate logic circuit model '%s' of "
+ "'%s' should be a MUX2 gate!\n",
+ circuit_lib.model_name(last_stage_pgl_model).c_str(),
+ circuit_lib.model_name(mux_model).c_str());
+ num_err++;
+ }
+ }
+
+ return num_err;
+}
+
/************************************************************************
* Check points to make sure we have a valid circuit library
* Detailed checkpoints:
@@ -920,6 +974,9 @@ bool check_circuit_library(const CircuitLibrary& circuit_lib) {
/* 11. Check power-gated inverter/buffer models */
num_err += check_power_gated_circuit_models(circuit_lib);
+ /* 12. Check pass-gate logic model consistency */
+ num_err += check_pass_gate_circuit_model_consistency(circuit_lib);
+
/* If we have any errors, exit */
if (0 < num_err) {
diff --git a/libs/libarchopenfpga/src/circuit_library.cpp b/libs/libarchopenfpga/src/circuit_library.cpp
index 241f63c7a..28c00aa7b 100644
--- a/libs/libarchopenfpga/src/circuit_library.cpp
+++ b/libs/libarchopenfpga/src/circuit_library.cpp
@@ -259,6 +259,28 @@ CircuitModelId CircuitLibrary::pass_gate_logic_model(
return pgl_model_id;
}
+/* Find the id of pass-gate circuit model
+ * Two cases to be considered:
+ * 1. this is a pass-gate circuit model, just find the data and return
+ * 2. this circuit model includes a pass-gate, find the link to pass-gate
+ * circuit model and go recursively
+ */
+CircuitModelId CircuitLibrary::last_stage_pass_gate_logic_model(
+ const CircuitModelId& model_id) const {
+ /* validate the model_id */
+ VTR_ASSERT(valid_model_id(model_id));
+
+ /* Return the data if this is a pass-gate circuit model */
+ if (CIRCUIT_MODEL_PASSGATE == model_type(model_id)) {
+ return model_ids_[model_id];
+ }
+
+ /* Otherwise, we need to make sure this circuit model contains a pass-gate */
+ CircuitModelId pgl_model_id = last_stage_pass_gate_logic_model_ids_[model_id];
+ VTR_ASSERT(CircuitModelId::INVALID() != pgl_model_id);
+ return pgl_model_id;
+}
+
/* Find the name of pass-gate circuit model
* Two cases to be considered:
* 1. this is a pass-gate circuit model, just find the data and return
@@ -279,6 +301,26 @@ std::string CircuitLibrary::pass_gate_logic_model_name(
return pass_gate_logic_model_names_[model_id];
}
+/* Find the name of pass-gate circuit model
+ * Two cases to be considered:
+ * 1. this is a pass-gate circuit model, just find the data and return
+ * 2. this circuit model includes a pass-gate, find the link to pass-gate
+ * circuit model and go recursively
+ */
+std::string CircuitLibrary::last_stage_pass_gate_logic_model_name(
+ const CircuitModelId& model_id) const {
+ /* validate the model_id */
+ VTR_ASSERT(valid_model_id(model_id));
+
+ /* Return the data if this is a pass-gate circuit model */
+ if (CIRCUIT_MODEL_PASSGATE == model_type(model_id)) {
+ return model_names_[model_id];
+ }
+
+ /* Otherwise, we need to make sure this circuit model contains a pass-gate */
+ return last_stage_pass_gate_logic_model_names_[model_id];
+}
+
/* Return the type of pass gate logic module, only applicable to circuit model
* whose type is pass-gate logic */
enum e_circuit_model_pass_gate_logic_type CircuitLibrary::pass_gate_logic_type(
@@ -1262,6 +1304,8 @@ CircuitModelId CircuitLibrary::add_model(
/* Pass-gate-related parameters */
pass_gate_logic_model_names_.emplace_back();
pass_gate_logic_model_ids_.emplace_back(CircuitModelId::INVALID());
+ last_stage_pass_gate_logic_model_names_.emplace_back();
+ last_stage_pass_gate_logic_model_ids_.emplace_back(CircuitModelId::INVALID());
/* Delay information */
delay_types_.emplace_back();
@@ -1485,6 +1529,15 @@ void CircuitLibrary::set_model_pass_gate_logic(const CircuitModelId& model_id,
return;
}
+/* Set pass-gate logic information of a circuit model */
+void CircuitLibrary::set_model_last_stage_pass_gate_logic(
+ const CircuitModelId& model_id, const std::string& model_name) {
+ /* validate the model_id */
+ VTR_ASSERT(valid_model_id(model_id));
+ last_stage_pass_gate_logic_model_names_[model_id] = model_name;
+ return;
+}
+
/* Add a port to a circuit model */
CircuitPortId CircuitLibrary::add_model_port(
const CircuitModelId& model_id,
@@ -2174,6 +2227,12 @@ void CircuitLibrary::link_pass_gate_logic_model(
}
pass_gate_logic_model_ids_[model_id] =
model(pass_gate_logic_model_names_[model_id]);
+ /* Get the circuit model id by name, skip those with empty names*/
+ if (true == last_stage_pass_gate_logic_model_names_[model_id].empty()) {
+ return;
+ }
+ last_stage_pass_gate_logic_model_ids_[model_id] =
+ model(last_stage_pass_gate_logic_model_names_[model_id]);
return;
}
diff --git a/libs/libarchopenfpga/src/circuit_library.h b/libs/libarchopenfpga/src/circuit_library.h
index 30caef09c..2c511d59c 100644
--- a/libs/libarchopenfpga/src/circuit_library.h
+++ b/libs/libarchopenfpga/src/circuit_library.h
@@ -272,7 +272,11 @@ class CircuitLibrary {
const CircuitModelId& model_id) const;
/* Pass-gate-logic information */
CircuitModelId pass_gate_logic_model(const CircuitModelId& model_id) const;
+ CircuitModelId last_stage_pass_gate_logic_model(
+ const CircuitModelId& model_id) const;
std::string pass_gate_logic_model_name(const CircuitModelId& model_id) const;
+ std::string last_stage_pass_gate_logic_model_name(
+ const CircuitModelId& model_id) const;
enum e_circuit_model_pass_gate_logic_type pass_gate_logic_type(
const CircuitModelId& model_id) const;
float pass_gate_logic_pmos_size(const CircuitModelId& model_id) const;
@@ -448,6 +452,8 @@ class CircuitLibrary {
/* Pass-gate-related parameters */
void set_model_pass_gate_logic(const CircuitModelId& model_id,
const std::string& model_name);
+ void set_model_last_stage_pass_gate_logic(const CircuitModelId& model_id,
+ const std::string& model_name);
/* Port information */
CircuitPortId add_model_port(const CircuitModelId& model_id,
const enum e_circuit_model_port_type& port_type);
@@ -664,6 +670,10 @@ class CircuitLibrary {
/* Pass-gate-related parameters */
vtr::vector pass_gate_logic_model_names_;
vtr::vector pass_gate_logic_model_ids_;
+ vtr::vector
+ last_stage_pass_gate_logic_model_names_;
+ vtr::vector
+ last_stage_pass_gate_logic_model_ids_;
/* Port information */
vtr::vector port_ids_;
diff --git a/libs/libarchopenfpga/src/read_xml_circuit_library.cpp b/libs/libarchopenfpga/src/read_xml_circuit_library.cpp
index 13ff84800..9fdc05265 100644
--- a/libs/libarchopenfpga/src/read_xml_circuit_library.cpp
+++ b/libs/libarchopenfpga/src/read_xml_circuit_library.cpp
@@ -832,6 +832,25 @@ static void read_xml_circuit_model(pugi::xml_node& xml_model,
circuit_lib.set_model_pass_gate_logic(
model, get_attribute(xml_pass_gate_logic, "circuit_model_name", loc_data)
.as_string());
+ /* Last stage pass gate is optional */
+ size_t num_last_stage_pgl =
+ count_children(xml_model, "last_stage_pass_gate_logic", loc_data,
+ pugiutil::ReqOpt::OPTIONAL);
+ if (0 < num_last_stage_pgl) {
+ auto xml_last_stage_pass_gate_logic =
+ get_single_child(xml_model, "last_stage_pass_gate_logic", loc_data);
+ circuit_lib.set_model_last_stage_pass_gate_logic(
+ model, get_attribute(xml_last_stage_pass_gate_logic,
+ "circuit_model_name", loc_data)
+ .as_string());
+ } else {
+ /* By default, assume the last stage circuit model is the same as others
+ */
+ circuit_lib.set_model_last_stage_pass_gate_logic(
+ model,
+ get_attribute(xml_pass_gate_logic, "circuit_model_name", loc_data)
+ .as_string());
+ }
}
/* Parse all the ports belonging to this circuit model
diff --git a/libs/libarchopenfpga/src/write_xml_circuit_library.cpp b/libs/libarchopenfpga/src/write_xml_circuit_library.cpp
index ac6867cea..42e392685 100644
--- a/libs/libarchopenfpga/src/write_xml_circuit_library.cpp
+++ b/libs/libarchopenfpga/src/write_xml_circuit_library.cpp
@@ -593,6 +593,15 @@ static void write_xml_circuit_model(std::fstream& fp, const char* fname,
circuit_lib.model_name(circuit_lib.pass_gate_logic_model(model)).c_str());
fp << "/>"
<< "\n";
+ fp << "\t\t\t"
+ << ""
+ << "\n";
}
/* Write the ports of circuit model */
diff --git a/openfpga/src/fabric/build_mux_modules.cpp b/openfpga/src/fabric/build_mux_modules.cpp
index 3233db768..5d9fb93d7 100644
--- a/openfpga/src/fabric/build_mux_modules.cpp
+++ b/openfpga/src/fabric/build_mux_modules.cpp
@@ -496,6 +496,71 @@ static void build_cmos_mux_module_mux2_multiplexing_structure(
module_manager.module_port(std_cell_module_id, std_cell_module_output);
VTR_ASSERT(1 == std_cell_module_output_port.get_width());
+ /* Find module information of the standard cell MUX2 */
+ CircuitModelId last_stage_std_cell_model =
+ circuit_lib.last_stage_pass_gate_logic_model(mux_model);
+ std::string last_stage_std_cell_module_name =
+ circuit_lib.model_name(last_stage_std_cell_model);
+ /* Get the moduleId for the submodule */
+ ModuleId last_stage_std_cell_module_id =
+ module_manager.find_module(last_stage_std_cell_module_name);
+ /* We must have one */
+ VTR_ASSERT(ModuleId::INVALID() != last_stage_std_cell_module_id);
+
+ /* Find the input ports and output ports of the standard cell */
+ std::vector last_stage_std_cell_input_ports =
+ circuit_lib.model_ports_by_type(last_stage_std_cell_model,
+ CIRCUIT_MODEL_PORT_INPUT, true);
+ std::vector last_stage_std_cell_output_ports =
+ circuit_lib.model_ports_by_type(last_stage_std_cell_model,
+ CIRCUIT_MODEL_PORT_OUTPUT, true);
+ /* Quick check the requirements on port map */
+ VTR_ASSERT(3 == last_stage_std_cell_input_ports.size());
+ VTR_ASSERT(1 == last_stage_std_cell_output_ports.size());
+
+ /* Find the module ports of the standard cell MUX2 module */
+ std::vector last_stage_std_cell_module_inputs;
+ std::vector last_stage_std_cell_module_input_ports;
+ /* Input 0 port is the first data path input of the tgate, whose size must be
+ * 1 ! */
+ for (size_t port_id = 0; port_id < 2; ++port_id) {
+ last_stage_std_cell_module_inputs.push_back(module_manager.find_module_port(
+ last_stage_std_cell_module_id,
+ circuit_lib.port_prefix(last_stage_std_cell_input_ports[port_id])));
+ VTR_ASSERT(true == module_manager.valid_module_port_id(
+ last_stage_std_cell_module_id,
+ last_stage_std_cell_module_inputs[port_id]));
+ last_stage_std_cell_module_input_ports.push_back(
+ module_manager.module_port(last_stage_std_cell_module_id,
+ last_stage_std_cell_module_inputs[port_id]));
+ VTR_ASSERT(1 ==
+ last_stage_std_cell_module_input_ports[port_id].get_width());
+ }
+
+ /* Mem port is the memory of the standard cell MUX2, whose size must be 1 ! */
+ ModulePortId last_stage_std_cell_module_mem = module_manager.find_module_port(
+ last_stage_std_cell_module_id,
+ circuit_lib.port_prefix(last_stage_std_cell_input_ports[2]));
+ VTR_ASSERT(true ==
+ module_manager.valid_module_port_id(
+ last_stage_std_cell_module_id, last_stage_std_cell_module_mem));
+ BasicPort last_stage_std_cell_module_mem_port = module_manager.module_port(
+ last_stage_std_cell_module_id, last_stage_std_cell_module_mem);
+ VTR_ASSERT(1 == last_stage_std_cell_module_mem_port.get_width());
+
+ /* Output port is the data path output of the standard cell MUX2, whose size
+ * must be 1 ! */
+ ModulePortId last_stage_std_cell_module_output =
+ module_manager.find_module_port(
+ last_stage_std_cell_module_id,
+ circuit_lib.port_prefix(last_stage_std_cell_output_ports[0]));
+ VTR_ASSERT(true == module_manager.valid_module_port_id(
+ last_stage_std_cell_module_id,
+ last_stage_std_cell_module_output));
+ BasicPort last_stage_std_cell_module_output_port = module_manager.module_port(
+ last_stage_std_cell_module_id, last_stage_std_cell_module_output);
+ VTR_ASSERT(1 == last_stage_std_cell_module_output_port.get_width());
+
/* Cache Net ids for each level of the multiplexer */
std::vector> module_nets_by_level;
module_nets_by_level.resize(mux_graph.num_node_levels());
@@ -518,11 +583,16 @@ static void build_cmos_mux_module_mux2_multiplexing_structure(
/* To match the standard cell MUX2: We should have only 2 input_nodes */
VTR_ASSERT(2 == branch_size);
+ /* Last stage MUX model may have a different name */
+ ModuleId curr_stage_std_cell_module_id = std_cell_module_id;
+ if (true == mux_graph.is_node_output(node)) {
+ curr_stage_std_cell_module_id = last_stage_std_cell_module_id;
+ }
/* Find the instance id */
size_t std_cell_instance_id =
- module_manager.num_instance(mux_module, std_cell_module_id);
+ module_manager.num_instance(mux_module, curr_stage_std_cell_module_id);
/* Add the module to mux_module */
- module_manager.add_child_module(mux_module, std_cell_module_id);
+ module_manager.add_child_module(mux_module, curr_stage_std_cell_module_id);
/* Get the node level and index in the current level */
size_t output_node_level = mux_graph.node_level(node);
@@ -530,9 +600,9 @@ static void build_cmos_mux_module_mux2_multiplexing_structure(
/* Set a name for the instance */
std::string std_cell_instance_name = generate_mux_branch_instance_name(
output_node_level, output_node_index_at_level, false);
- module_manager.set_child_instance_name(mux_module, std_cell_module_id,
- std_cell_instance_id,
- std_cell_instance_name);
+ module_manager.set_child_instance_name(
+ mux_module, curr_stage_std_cell_module_id, std_cell_instance_id,
+ std_cell_instance_name);
/* Add module nets to wire to next stage modules */
ModuleNetId branch_net;
@@ -540,13 +610,18 @@ static void build_cmos_mux_module_mux2_multiplexing_structure(
/* This is an output node, we should use existing output nets */
MuxOutputId output_id = mux_graph.output_id(node);
branch_net = mux_module_output_nets[output_id];
+ module_manager.add_module_net_source(
+ mux_module, branch_net, curr_stage_std_cell_module_id,
+ std_cell_instance_id, last_stage_std_cell_module_output,
+ last_stage_std_cell_module_output_port.get_lsb());
} else {
VTR_ASSERT(false == mux_graph.is_node_output(node));
branch_net = module_manager.create_module_net(mux_module);
+ module_manager.add_module_net_source(
+ mux_module, branch_net, curr_stage_std_cell_module_id,
+ std_cell_instance_id, std_cell_module_output,
+ std_cell_module_output_port.get_lsb());
}
- module_manager.add_module_net_source(
- mux_module, branch_net, std_cell_module_id, std_cell_instance_id,
- std_cell_module_output, std_cell_module_output_port.get_lsb());
/* Record the module net id in the cache */
module_nets_by_level[output_node_level][output_node_index_at_level] =
@@ -567,10 +642,17 @@ static void build_cmos_mux_module_mux2_multiplexing_structure(
* Note that standard cell MUX2 only needs mem but NOT mem_inv
*/
for (const MuxMemId& mem : mems) {
- module_manager.add_module_net_sink(
- mux_module, mux_module_mem_nets[mem], std_cell_module_id,
- std_cell_instance_id, std_cell_module_mem,
- std_cell_module_mem_port.get_lsb());
+ if (true == mux_graph.is_node_output(node)) {
+ module_manager.add_module_net_sink(
+ mux_module, mux_module_mem_nets[mem], last_stage_std_cell_module_id,
+ std_cell_instance_id, last_stage_std_cell_module_mem,
+ last_stage_std_cell_module_mem_port.get_lsb());
+ } else {
+ module_manager.add_module_net_sink(
+ mux_module, mux_module_mem_nets[mem], std_cell_module_id,
+ std_cell_instance_id, std_cell_module_mem,
+ std_cell_module_mem_port.get_lsb());
+ }
}
/* Wire the branch module inputs to the nets in previous stage */
@@ -602,8 +684,15 @@ static void build_cmos_mux_module_mux2_multiplexing_structure(
mux_module, mux_module_input_nets[input_id], std_cell_module_id,
std_cell_instance_id, std_cell_module_inputs[node_id],
std_cell_module_input_ports[node_id].get_lsb());
+ } else if (true == mux_graph.is_node_output(node)) {
+ /* Find the input port of standard cell */
+ module_manager.add_module_net_sink(
+ mux_module,
+ module_nets_by_level[input_node_level][input_node_index_at_level],
+ last_stage_std_cell_module_id, std_cell_instance_id,
+ last_stage_std_cell_module_inputs[node_id],
+ last_stage_std_cell_module_input_ports[node_id].get_lsb());
} else {
- VTR_ASSERT(false == mux_graph.is_node_input(input_nodes[node_id]));
/* Find the input port of standard cell */
module_manager.add_module_net_sink(
mux_module,
diff --git a/openfpga_flow/openfpga_arch/README.md b/openfpga_flow/openfpga_arch/README.md
index a2cc2f6ee..6bd3535ed 100644
--- a/openfpga_flow/openfpga_arch/README.md
+++ b/openfpga_flow/openfpga_arch/README.md
@@ -29,6 +29,7 @@ Note that an OpenFPGA architecture can be applied to multiple VPR architecture f
- registerable\_io: If I/Os are registerable (can be either combinational or sequential)
- IoSubtile: If I/O block contains sub tiles (more compact with a higher density of I/Os)
- stdcell: If circuit designs are built with standard cells only
+- stdcell_laststage: If circuit designs are built with standard cells only. And the last stage uses a different standard cell
- tree\_mux: If routing multiplexers are built with a tree-like structure
- localClkGen: The clock signal of CLB can be generated by internal programmable resources
- : The technology node which the delay numbers are extracted from.
diff --git a/openfpga_flow/openfpga_arch/k6_frac_N8_stdcell_laststage_mux_40nm_openfpga.xml b/openfpga_flow/openfpga_arch/k6_frac_N8_stdcell_laststage_mux_40nm_openfpga.xml
new file mode 100644
index 000000000..024b4fc13
--- /dev/null
+++ b/openfpga_flow/openfpga_arch/k6_frac_N8_stdcell_laststage_mux_40nm_openfpga.xml
@@ -0,0 +1,236 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 10e-12
+
+
+ 10e-12
+
+
+
+
+
+
+
+
+ 10e-12
+
+
+ 10e-12
+
+
+
+
+
+
+
+
+ 10e-12
+
+
+ 10e-12
+
+
+
+
+
+
+
+
+
+
+
+ 10e-12 5e-12
+
+
+ 10e-12 5e-12
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/openfpga_flow/openfpga_cell_library/verilog/mux2.v b/openfpga_flow/openfpga_cell_library/verilog/mux2.v
index fed7858ba..4326a0017 100644
--- a/openfpga_flow/openfpga_cell_library/verilog/mux2.v
+++ b/openfpga_flow/openfpga_cell_library/verilog/mux2.v
@@ -54,6 +54,55 @@ module MUX2(
endmodule
+module MUX2D2(
+ // iVerilog is buggy on the 'input A' declaration when deposit initial
+ // values
+ input [0:0] AA, // Data input 0
+ input [0:0] BB, // Data input 1
+ input [0:0] SS0, // Select port
+ output [0:0] YY // Data output
+ );
+
+ assign YY = SS0 ? BB : AA;
+
+// Note:
+// MUX2 appears will appear in LUTs, routing multiplexers,
+// being a component in combinational loops
+// To help convergence in simulation
+// i.e., to avoid the X (undetermined) signals,
+// the following timing constraints and signal initialization
+// has to be added!
+
+`ifdef ENABLE_TIMING
+// ------ BEGIN Pin-to-pin Timing constraints -----
+ specify
+ (AA => YY) = (0.001, 0.001);
+ (BB => YY) = (0.001, 0.001);
+ (SS0 => YY) = (0.001, 0.001);
+ endspecify
+// ------ END Pin-to-pin Timing constraints -----
+`endif
+
+`ifdef ENABLE_SIGNAL_INITIALIZATION
+// ------ BEGIN driver initialization -----
+ initial begin
+ `ifdef ENABLE_FORMAL_VERIFICATION
+ $deposit(AA, 1'b0);
+ $deposit(BB, 1'b0);
+ $deposit(SS0, 1'b0);
+ `else
+ $deposit(AA, $random);
+ $deposit(BB, $random);
+ $deposit(SS0, $random);
+ `endif
+
+ end
+// ------ END driver initialization -----
+`endif
+
+endmodule
+
+
//-----------------------------------------------------
// Design Name : CARRY_MUX2
// File Name : mux2.v
diff --git a/openfpga_flow/regression_test_scripts/fpga_verilog_reg_test.sh b/openfpga_flow/regression_test_scripts/fpga_verilog_reg_test.sh
index 7f418b15d..6d6cb4829 100755
--- a/openfpga_flow/regression_test_scripts/fpga_verilog_reg_test.sh
+++ b/openfpga_flow/regression_test_scripts/fpga_verilog_reg_test.sh
@@ -84,6 +84,7 @@ run-task fpga_verilog/mux_design/tree_structure $@
echo -e "Testing Verilog generation with routing multiplexers implemented by standard cell MUX2";
run-task fpga_verilog/mux_design/stdcell_mux2 $@
+run-task fpga_verilog/mux_design/stdcell_mux2_last_stage $@
echo -e "Testing Verilog generation with routing multiplexers implemented by local encoders";
run-task fpga_verilog/mux_design/local_encoder $@
diff --git a/openfpga_flow/tasks/fpga_verilog/mux_design/stdcell_mux2_last_stage/config/task.conf b/openfpga_flow/tasks/fpga_verilog/mux_design/stdcell_mux2_last_stage/config/task.conf
new file mode 100644
index 000000000..a70315f2d
--- /dev/null
+++ b/openfpga_flow/tasks/fpga_verilog/mux_design/stdcell_mux2_last_stage/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=vpr_blif
+
+[OpenFPGA_SHELL]
+openfpga_shell_template=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_shell_scripts/example_script.openfpga
+openfpga_arch_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_arch/k6_frac_N8_stdcell_laststage_mux_40nm_openfpga.xml
+openfpga_sim_setting_file=${PATH:OPENFPGA_PATH}/openfpga_flow/openfpga_simulation_settings/auto_sim_openfpga.xml
+
+[ARCHITECTURES]
+arch0=${PATH:OPENFPGA_PATH}/openfpga_flow/vpr_arch/k6_frac_N8_tileable_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
+bench0_chan_width = 300
+
+[SCRIPT_PARAM_MIN_ROUTE_CHAN_WIDTH]
+end_flow_with_test=
+vpr_fpga_verilog_formal_verification_top_netlist=