diff --git a/.travis/basic_reg_test.sh b/.travis/basic_reg_test.sh
index 6c9e1c04d..b794858d9 100755
--- a/.travis/basic_reg_test.sh
+++ b/.travis/basic_reg_test.sh
@@ -36,7 +36,7 @@ echo -e "Testing Verilog testbench generation only";
python3 openfpga_flow/scripts/run_fpga_task.py generate_testbench --debug --show_thread_logs
echo -e "Testing bitstream generation only";
-python3 openfpga_flow/scripts/run_fpga_task.py generate_bitstream --debug --show_thread_logs
+python3 openfpga_flow/scripts/run_fpga_task.py fpga_bitstream/generate_bitstream --debug --show_thread_logs
echo -e "Testing user-defined simulation settings: clock frequency and number of cycles";
python3 openfpga_flow/scripts/run_fpga_task.py fixed_simulation_settings --debug --show_thread_logs
@@ -44,4 +44,7 @@ python3 openfpga_flow/scripts/run_fpga_task.py fixed_simulation_settings --debug
echo -e "Testing SDC generation with time units";
python3 openfpga_flow/scripts/run_fpga_task.py sdc_time_unit --debug --show_thread_logs
+echo -e "Testing FPGA-SPICE with netlist generation";
+python3 openfpga_flow/scripts/run_fpga_task.py fpga_spice/generate_spice --debug --show_thread_logs
+
end_section "OpenFPGA.TaskTun"
diff --git a/.travis/verilog_reg_test.sh b/.travis/verilog_reg_test.sh
index f49b6ab84..18ffe91e5 100755
--- a/.travis/verilog_reg_test.sh
+++ b/.travis/verilog_reg_test.sh
@@ -75,6 +75,12 @@ python3 openfpga_flow/scripts/run_fpga_task.py fabric_key/generate_vanilla_key -
python3 openfpga_flow/scripts/run_fpga_task.py fabric_key/generate_random_key --debug --show_thread_logs
python3 openfpga_flow/scripts/run_fpga_task.py fabric_key/load_external_key --debug --show_thread_logs
+echo -e "Testing Power-gating designs";
+python3 openfpga_flow/scripts/run_fpga_task.py power_gated_design/power_gated_inverter --show_thread_logs --debug
+
+echo -e "Testing Depopulated crossbar in local routing";
+python3 openfpga_flow/scripts/run_fpga_task.py depopulate_crossbar --debug --show_thread_logs
+
# Verify MCNC big20 benchmark suite with ModelSim
# Please make sure you have ModelSim installed in the environment
# Otherwise, it will fail
diff --git a/docs/source/manual/arch_lang/technology_library.rst b/docs/source/manual/arch_lang/technology_library.rst
index 08b6c62d9..4d1c5f2a0 100644
--- a/docs/source/manual/arch_lang/technology_library.rst
+++ b/docs/source/manual/arch_lang/technology_library.rst
@@ -13,8 +13,8 @@ General organization is as follows.
-
-
+
+
@@ -71,15 +71,19 @@ A device model represents a transistor/RRAM model available in users' technology
- ``pn_ratio=""`` specify the ratio between *p*-type and *n*-type transistors. The ratio will be used when building circuit structures such as inverters, buffers, etc.
-.. option::
+.. option::
Specify device-level parameters for transistors
- ``name=""`` specify the name of the p/n type transistor, which can be found in the manual of the technology provider.
- - ``chan_length=""`` specify the channel length of *p/n* type transistor.
+ - ``chan_length=""`` specify the channel length of a *p/n* type transistor.
- - ``min_width=""`` specify the minimum width of *p/n* type transistor. This parameter will be used in building inverter, buffer, *etc*. as a base number for transistor sizing.
+ - ``min_width=""`` specify the minimum width of a *p/n* type transistor. This parameter will be used in building inverter, buffer, *etc*. as a base number for transistor sizing.
+
+ - ``max_width=""`` specify the maximum width of a *p/n* type transistor. This parameter will be used in building inverter, buffer, *etc*. as a base number for transistor sizing. If the required transistor width exceeds the maximum width, multiple transistors will be instanciated. Note that for FinFET technology, your ``max_width`` should be the same as your ``min_width``.
+
+ .. note:: The ``max_width`` is optional. By default, it will be set to be same as the ``min_width``.
- ``variation=""`` specify the variation name defined in the ````
diff --git a/docs/source/manual/fpga_bitstream/fabric_dependent_bitstream.rst b/docs/source/manual/fpga_bitstream/fabric_dependent_bitstream.rst
index 280768c1a..131d0ce57 100644
--- a/docs/source/manual/fpga_bitstream/fabric_dependent_bitstream.rst
+++ b/docs/source/manual/fpga_bitstream/fabric_dependent_bitstream.rst
@@ -1,7 +1,133 @@
Fabric-dependent Bitstream
~~~~~~~~~~~~~~~~~~~~~~~~~~
+Usage
+`````
+
Fabric-dependent bitstream is design to be loadable to the configuration protocols of FPGAs.
The bitstream just sets an order to the configuration bits in the database, without duplicating the database.
OpenFPGA framework provides a fabric-dependent bitstream generator which is aligned to our Verilog netlists.
-The fabric-dependent bitstream can be found in autogenerated Verilog testbenches.
+The fabric-dependent bitstream can be found in the pre-configured Verilog testbenches.
+The fabric bitsteam can be outputted in different file format in terms of usage.
+
+Plain Text File Format
+```````````````````````
+
+This file format is designed to be directly loaded to an FPGA fabric.
+It does not include any comments but only bitstream.
+
+The information depends on the type of configuration procotol.
+
+.. option:: vanilla
+
+ A line consisting of ``0`` | ``1``
+
+.. option:: scan_chain
+
+ A line consisting of ``0`` | ``1``
+
+.. option:: memory_bank
+
+ Multiple lines will be included, each of which is organized as .
+ Note that due to the use of Bit-Line and Word-Line decoders, every two lines are paired.
+ The first line represents the Bit-Line address and configuration bit.
+ The second line represents the Word-Line address and configuration bit.
+ For example
+
+ .. code-block:: xml
+
+
+
+
+
+ ...
+
+
+
+.. option:: frame_based
+
+ Multiple lines will be included, each of which is organized as .
+ For example
+
+ .. code-block:: xml
+
+
+
+ ...
+
+
+XML File Format
+```````````````
+
+This file format is designed to generate testbenches using external tools, e.g., CocoTB.
+
+In principle, the file consist a number of XML node ````, each bit contains the following attributes:
+
+- ``id``: The unique id of the configuration bit in the fabric bitstream.
+
+- ``value``: The configuration bit value.
+
+ - ``hierarchy`` represents the location of this block in FPGA fabric.
+ The hierachy includes the full hierarchy of this block
+
+ - ``instance`` denotes the instance name which you can find in the fabric netlists
+
+ - ``level`` denotes the depth of the block in the hierarchy
+
+ - ``width`` denotes the number of configuration bits under the instance. Typically, only leaf instance has this attribute.
+
+A quick example:
+
+.. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+Other information may depend on the type of configuration procotol.
+
+.. option:: memory_bank
+
+ - ``bl``: Bit line address information
+
+ - ``wl``: Word line address information
+
+ A quick example:
+
+ .. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+
+
+
+.. option:: frame_based
+
+ - ``frame``: frame address information
+
+ A quick example:
+
+ .. code-block:: xml
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/source/manual/openfpga_shell/openfpga_commands/fpga_bitstream_commands.rst b/docs/source/manual/openfpga_shell/openfpga_commands/fpga_bitstream_commands.rst
index 731f99f94..5c1bf5d2b 100644
--- a/docs/source/manual/openfpga_shell/openfpga_commands/fpga_bitstream_commands.rst
+++ b/docs/source/manual/openfpga_shell/openfpga_commands/fpga_bitstream_commands.rst
@@ -7,8 +7,8 @@ repack
~~~~~~
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
+
+ .. note:: This must be done before bitstream generator and testbench generation. Strongly recommend it is done after all the fix-up have been applied
- ``--verbose`` Show verbose log
@@ -28,6 +28,15 @@ build_fabric_bitstream
Build a sequence for every configuration bits in the bitstream database for a specific FPGA fabric
+ - ``--verbose`` Show verbose log
+
+write_fabric_bitstream
+~~~~~~~~~~~~~~~~~~~~~~
+
+ Output the fabric bitstream database to a specific file format
+
- ``--file`` or ``-f`` Output the fabric bitstream to an plain text file (only 0 or 1)
+ - ``--format`` Specify the file format [``plain_text`` | ``xml``]. By default is ``plain_text``.
+
- ``--verbose`` Show verbose log
diff --git a/docs/source/manual/openfpga_shell/openfpga_commands/fpga_verilog_commands.rst b/docs/source/manual/openfpga_shell/openfpga_commands/fpga_verilog_commands.rst
index de4aecad8..c2044cf57 100644
--- a/docs/source/manual/openfpga_shell/openfpga_commands/fpga_verilog_commands.rst
+++ b/docs/source/manual/openfpga_shell/openfpga_commands/fpga_verilog_commands.rst
@@ -31,7 +31,7 @@ write_verilog_testbench
- ``--reference_benchmark_file_path`` Must specify the reference benchmark Verilog file if you want to output any testbenches
- - ``--fast_configuration`` Enable fast configuration phase for the top-level testbench in order to reduce runtime of simulations. It is applicable to memory bank and frame-based configuration protocols. When enabled, all the zero configuration bits will be skipped. So ensure that your memory cells can be correctly reset to zero with a reset signal.
+ - ``--fast_configuration`` Enable fast configuration phase for the top-level testbench in order to reduce runtime of simulations. It is applicable to configuration chain, memory bank and frame-based configuration protocols. For configuration chain, when enabled, the zeros at the head of the bitstream will be skipped. For memory bank and frame-based, when enabled, all the zero configuration bits will be skipped. So ensure that your memory cells can be correctly reset to zero with a reset signal.
- ``--print_top_testbench`` Enable top-level testbench which is a full verification including programming circuit and core logic of FPGA
diff --git a/docs/source/manual/openfpga_shell/openfpga_commands/setup_commands.rst b/docs/source/manual/openfpga_shell/openfpga_commands/setup_commands.rst
index aa0018476..2d628117a 100644
--- a/docs/source/manual/openfpga_shell/openfpga_commands/setup_commands.rst
+++ b/docs/source/manual/openfpga_shell/openfpga_commands/setup_commands.rst
@@ -109,6 +109,10 @@ build_fabric
- ``--write_fabric_key `` Output current fabric key to an XML file
+ - ``--frame_view`` Create only frame views of the module graph. When enabled, top-level module will not include any nets. This option is made for save runtime and memory.
+
+ .. warning:: Recommend to turn the option on when bitstream generation is the only purpose of the flow. Do not use it when you need generate netlists!
+
- ``--verbose`` Show verbose log
.. note:: This is a must-run command before launching FPGA-Verilog, FPGA-Bitstream, FPGA-SDC and FPGA-SPICE
diff --git a/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp b/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp
index b38fbf1b6..ea6db0678 100644
--- a/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp
+++ b/libopenfpga/libarchopenfpga/src/check_circuit_library.cpp
@@ -302,7 +302,9 @@ size_t check_sram_circuit_model_ports(const CircuitLibrary& circuit_lib,
return num_err;
}
-/* Check all the ports make sure, they satisfy the restriction */
+/************************************************************************
+ * Check all the ports make sure, they satisfy the restriction
+ ***********************************************************************/
static
size_t check_circuit_library_ports(const CircuitLibrary& circuit_lib) {
size_t num_err = 0;
@@ -435,6 +437,94 @@ size_t check_circuit_library_ports(const CircuitLibrary& circuit_lib) {
return num_err;
}
+/************************************************************************
+ * Check the port requirements for a power-gated circuit model
+ * - It must have at least 2 global ports and which are config enable signals
+ * - It must have an Enable port which control power gating
+ * - It must have an EnableB port which control power gating
+ ***********************************************************************/
+static
+int check_power_gated_circuit_model(const CircuitLibrary& circuit_lib,
+ const CircuitModelId& circuit_model) {
+ int num_err = 0;
+
+ std::vector global_ports = circuit_lib.model_global_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true, true);
+
+ /* If the circuit model is power-gated, we need to find at least one global config_enable signals */
+ VTR_ASSERT(true == circuit_lib.is_power_gated(circuit_model));
+ /* Check all the ports we have are good for a power-gated circuit model */
+ /* We need at least one global port */
+ if (2 > global_ports.size()) {
+ VTR_LOGF_ERROR(__FILE__, __LINE__,
+ "Expect at least two global ports (a pair of EN/Enb) for circuit model '%s' which is power-gated!\n",
+ circuit_lib.model_name(circuit_model).c_str());
+ num_err++;
+ }
+ /* All the global ports should be config_enable */
+ int num_config_enable_ports = 0;
+ for (const auto& port : global_ports) {
+ if (true == circuit_lib.port_is_config_enable(port)) {
+ num_config_enable_ports++;
+ }
+ }
+
+ if (2 != num_config_enable_ports) {
+ VTR_LOGF_ERROR(__FILE__, __LINE__,
+ "Circuit model '%s' is power-gated. Two config-enable global ports are required!\n",
+ circuit_lib.model_name(circuit_model).c_str());
+ num_err++;
+ }
+ /* Report errors if there are any */
+ if (0 < num_err) {
+ return num_err;
+ }
+
+ /* Try to find a pair of Enable and ENb ports from the global ports */
+ CircuitPortId en_port = CircuitPortId::INVALID();
+ CircuitPortId enb_port = CircuitPortId::INVALID();
+ for (const auto& port : global_ports) {
+ /* Focus on config_enable ports which are power-gate control signals */
+ if (false == circuit_lib.port_is_config_enable(port)) {
+ continue;
+ }
+ if (0 == circuit_lib.port_default_value(port)) {
+ en_port = port;
+ } else {
+ VTR_ASSERT(1 == circuit_lib.port_default_value(port));
+ enb_port = port;
+ }
+ }
+ /* We must have valid EN/ENb ports */
+ if (false == circuit_lib.valid_circuit_port_id(en_port)) {
+ VTR_LOGF_ERROR(__FILE__, __LINE__,
+ "Fail to find an enable port for the circuit model '%s' is power-gated!\n",
+ circuit_lib.model_name(circuit_model).c_str());
+ }
+ if (false == circuit_lib.valid_circuit_port_id(enb_port)) {
+ VTR_LOGF_ERROR(__FILE__, __LINE__,
+ "Fail to find an inverted enable port for the circuit model '%s' is power-gated!\n",
+ circuit_lib.model_name(circuit_model).c_str());
+ }
+
+ return num_err;
+}
+
+/************************************************************************
+ * Check the port requirements for each power-gated circuit model
+ ***********************************************************************/
+static
+int check_power_gated_circuit_models(const CircuitLibrary& circuit_lib) {
+ int num_err = 0;
+
+ for (const CircuitModelId& circuit_model : circuit_lib.models()) {
+ if (true == circuit_lib.is_power_gated(circuit_model)) {
+ num_err += check_power_gated_circuit_model(circuit_lib, circuit_model);
+ }
+ }
+
+ return num_err;
+}
+
/************************************************************************
* Check points to make sure we have a valid circuit library
* Detailed checkpoints:
@@ -541,6 +631,9 @@ bool check_circuit_library(const CircuitLibrary& circuit_lib) {
num_err += check_required_default_circuit_model(circuit_lib, CIRCUIT_MODEL_CHAN_WIRE);
num_err += check_required_default_circuit_model(circuit_lib, CIRCUIT_MODEL_WIRE);
+ /* 11. Check power-gated inverter/buffer models */
+ num_err += check_power_gated_circuit_models(circuit_lib);
+
/* If we have any errors, exit */
if (0 < num_err) {
diff --git a/libopenfpga/libarchopenfpga/src/read_xml_technology_library.cpp b/libopenfpga/libarchopenfpga/src/read_xml_technology_library.cpp
index f2f082116..e2871a638 100644
--- a/libopenfpga/libarchopenfpga/src/read_xml_technology_library.cpp
+++ b/libopenfpga/libarchopenfpga/src/read_xml_technology_library.cpp
@@ -122,6 +122,14 @@ void read_xml_device_transistor(pugi::xml_node& xml_device_transistor,
tech_lib.set_transistor_model_min_width(device_model, transistor_type,
get_attribute(xml_device_transistor, "min_width", loc_data).as_float(0.));
+ /* Parse the transistor maximum width, by default we consider the same as minimum width */
+ tech_lib.set_transistor_model_max_width(device_model, transistor_type,
+ get_attribute(xml_device_transistor, "max_width", loc_data, pugiutil::ReqOpt::OPTIONAL).as_float(0.));
+ /* If the max_width is default value, we set it to be the same as min_width */
+ if (0. == tech_lib.transistor_model_max_width(device_model, transistor_type)) {
+ tech_lib.set_transistor_model_max_width(device_model, transistor_type, tech_lib.transistor_model_min_width(device_model, transistor_type));
+ }
+
/* Parse the transistor variation name */
tech_lib.set_transistor_model_variation_name(device_model, transistor_type,
get_attribute(xml_device_transistor, "variation", loc_data).as_string());
diff --git a/libopenfpga/libarchopenfpga/src/technology_library.cpp b/libopenfpga/libarchopenfpga/src/technology_library.cpp
index 3f8e8e7f9..aa97abe80 100644
--- a/libopenfpga/libarchopenfpga/src/technology_library.cpp
+++ b/libopenfpga/libarchopenfpga/src/technology_library.cpp
@@ -157,6 +157,18 @@ float TechnologyLibrary::transistor_model_min_width(const TechnologyModelId& mod
return transistor_model_min_widths_[model_id][transistor_type];
}
+/* Access the maximum width of a transistor (either PMOS or NMOS) for a technology model
+ * Note: This is ONLY applicable to transistor model
+ */
+float TechnologyLibrary::transistor_model_max_width(const TechnologyModelId& model_id,
+ const e_tech_lib_transistor_type& transistor_type) const {
+ /* validate the model_id */
+ VTR_ASSERT(valid_model_id(model_id));
+ /* This is only applicable to transistor model */
+ VTR_ASSERT(TECH_LIB_MODEL_TRANSISTOR == model_type(model_id));
+ return transistor_model_max_widths_[model_id][transistor_type];
+}
+
/* Access the minimum width of a transistor (either PMOS or NMOS) for a technology model
* Note: This is ONLY applicable to transistor model
*/
@@ -270,6 +282,7 @@ TechnologyModelId TechnologyLibrary::add_model(const std::string& name) {
transistor_model_names_.emplace_back();
transistor_model_chan_lengths_.emplace_back();
transistor_model_min_widths_.emplace_back();
+ transistor_model_max_widths_.emplace_back();
transistor_model_variation_names_.emplace_back();
transistor_model_variation_ids_.push_back(std::array{TechnologyVariationId::INVALID(), TechnologyVariationId::INVALID()});
@@ -394,6 +407,19 @@ void TechnologyLibrary::set_transistor_model_min_width(const TechnologyModelId&
return;
}
+/* Set the maximum width for either PMOS or NMOS of a model in the library
+ * This is ONLY applicable to transistors
+ */
+void TechnologyLibrary::set_transistor_model_max_width(const TechnologyModelId& model_id,
+ const e_tech_lib_transistor_type& transistor_type,
+ const float& max_width) {
+ /* validate the model_id */
+ VTR_ASSERT(valid_model_id(model_id));
+ VTR_ASSERT(TECH_LIB_MODEL_TRANSISTOR == model_type(model_id));
+ transistor_model_max_widths_[model_id][transistor_type] = max_width;
+ return;
+}
+
/* Set the variation name for either PMOS or NMOS of a model in the library
* This is ONLY applicable to transistors
*/
diff --git a/libopenfpga/libarchopenfpga/src/technology_library.h b/libopenfpga/libarchopenfpga/src/technology_library.h
index a38acade3..ba90eff1d 100644
--- a/libopenfpga/libarchopenfpga/src/technology_library.h
+++ b/libopenfpga/libarchopenfpga/src/technology_library.h
@@ -101,6 +101,8 @@ class TechnologyLibrary {
const e_tech_lib_transistor_type& transistor_type) const;
float transistor_model_min_width(const TechnologyModelId& model_id,
const e_tech_lib_transistor_type& transistor_type) const;
+ float transistor_model_max_width(const TechnologyModelId& model_id,
+ const e_tech_lib_transistor_type& transistor_type) const;
TechnologyVariationId transistor_model_variation(const TechnologyModelId& model_id,
const e_tech_lib_transistor_type& transistor_type) const;
public: /* Public Accessors: Basic data query on RRAM models */
@@ -138,6 +140,9 @@ class TechnologyLibrary {
void set_transistor_model_min_width(const TechnologyModelId& model_id,
const e_tech_lib_transistor_type& transistor_type,
const float& min_width);
+ void set_transistor_model_max_width(const TechnologyModelId& model_id,
+ const e_tech_lib_transistor_type& transistor_type,
+ const float& max_width);
void set_transistor_model_variation_name(const TechnologyModelId& model_id,
const e_tech_lib_transistor_type& transistor_type,
const std::string& variation_name);
@@ -231,6 +236,15 @@ class TechnologyLibrary {
*/
vtr::vector> transistor_model_min_widths_;
+ /* The maximum width of a transistor.
+ * This should be defined by your technology vendor
+ * The maximum width of a transistor will be used to size your transistors
+ * If the required width in circuit models in larger then the max width,
+ * multiple transistor bin will be instanciated.
+ * For FinFET, the maximum width should be the same as min_width
+ */
+ vtr::vector> transistor_model_max_widths_;
+
/* The variation name and id binded to PMOS and NMOS transistor
* We expect users to provide the exact name of variation defined in this technology library
* the name and id will be automatically matched by using function link_model_to_variation()
diff --git a/libopenfpga/libarchopenfpga/src/write_xml_circuit_library.cpp b/libopenfpga/libarchopenfpga/src/write_xml_circuit_library.cpp
index 88fc0d3b2..5dd69ca8e 100644
--- a/libopenfpga/libarchopenfpga/src/write_xml_circuit_library.cpp
+++ b/libopenfpga/libarchopenfpga/src/write_xml_circuit_library.cpp
@@ -92,6 +92,25 @@ void write_xml_design_technology(std::fstream& fp,
fp << "/>" << "\n";
}
+/********************************************************************
+ * A writer to output the device technology of a circuit model to XML format
+ *******************************************************************/
+static
+void write_xml_device_technology(std::fstream& fp,
+ const char* fname,
+ const CircuitLibrary& circuit_lib,
+ const CircuitModelId& model) {
+ /* Validate the file stream */
+ openfpga::check_file_stream(fname, fp);
+
+ if (!circuit_lib.device_model_name(model).empty()) {
+ fp << "\t\t\t" << "" << "\n";
+ }
+}
+
/********************************************************************
* A writer to output a circuit port to XML format
*******************************************************************/
@@ -401,6 +420,9 @@ void write_xml_circuit_model(std::fstream& fp,
/* Write the design technology of circuit model */
write_xml_design_technology(fp, fname, circuit_lib, model);
+ /* Write the device technology of circuit model */
+ write_xml_device_technology(fp, fname, circuit_lib, model);
+
/* Write the input buffer information of circuit model,
* only applicable when this circuit model is neither inverter nor buffer
*/
diff --git a/libopenfpga/libarchopenfpga/src/write_xml_technology_library.cpp b/libopenfpga/libarchopenfpga/src/write_xml_technology_library.cpp
index 6f3f6fe0d..bf15bbe32 100644
--- a/libopenfpga/libarchopenfpga/src/write_xml_technology_library.cpp
+++ b/libopenfpga/libarchopenfpga/src/write_xml_technology_library.cpp
@@ -60,6 +60,7 @@ void write_xml_device_model(std::fstream& fp,
write_xml_attribute(fp, "name", tech_lib.transistor_model_name(device_model, TECH_LIB_TRANSISTOR_PMOS).c_str());
write_xml_attribute(fp, "chan_length", tech_lib.transistor_model_chan_length(device_model, TECH_LIB_TRANSISTOR_PMOS));
write_xml_attribute(fp, "min_width", tech_lib.transistor_model_min_width(device_model, TECH_LIB_TRANSISTOR_PMOS));
+ write_xml_attribute(fp, "max_width", tech_lib.transistor_model_max_width(device_model, TECH_LIB_TRANSISTOR_PMOS));
if (TechnologyVariationId::INVALID() != tech_lib.transistor_model_variation(device_model, TECH_LIB_TRANSISTOR_PMOS)) {
write_xml_attribute(fp, "variation", tech_lib.variation_name(tech_lib.transistor_model_variation(device_model, TECH_LIB_TRANSISTOR_PMOS)).c_str());
}
diff --git a/libopenfpga/libfpgabitstream/src/bitstream_manager.cpp b/libopenfpga/libfpgabitstream/src/bitstream_manager.cpp
index eb62222fb..3d5052989 100644
--- a/libopenfpga/libfpgabitstream/src/bitstream_manager.cpp
+++ b/libopenfpga/libfpgabitstream/src/bitstream_manager.cpp
@@ -52,6 +52,13 @@ bool BitstreamManager::bit_value(const ConfigBitId& bit_id) const {
return '1' == bit_values_[bit_id];
}
+ConfigBlockId BitstreamManager::bit_parent_block(const ConfigBitId& bit_id) const {
+ /* Ensure a valid id */
+ VTR_ASSERT(true == valid_bit_id(bit_id));
+
+ return bit_parent_blocks_[bit_id];
+}
+
std::string BitstreamManager::block_name(const ConfigBlockId& block_id) const {
/* Ensure the input ids are valid */
VTR_ASSERT(true == valid_block_id(block_id));
@@ -140,7 +147,7 @@ std::string BitstreamManager::block_output_net_ids(const ConfigBlockId& block_id
/******************************************************************************
* Public Mutators
******************************************************************************/
-ConfigBitId BitstreamManager::add_bit(const bool& bit_value) {
+ConfigBitId BitstreamManager::add_bit(const ConfigBlockId& parent_block, const bool& bit_value) {
ConfigBitId bit = ConfigBitId(num_bits_);
/* Add a new bit, and allocate associated data structures */
num_bits_++;
@@ -150,6 +157,8 @@ ConfigBitId BitstreamManager::add_bit(const bool& bit_value) {
bit_values_.push_back('0');
}
+ bit_parent_blocks_.push_back(parent_block);
+
return bit;
}
@@ -234,7 +243,7 @@ void BitstreamManager::add_block_bits(const ConfigBlockId& block,
block_bit_id_lsbs_[block] = num_bits_;
block_bit_lengths_[block] = block_bitstream.size();
for (const bool& bit : block_bitstream) {
- add_bit(bit);
+ add_bit(block, bit);
}
}
diff --git a/libopenfpga/libfpgabitstream/src/bitstream_manager.h b/libopenfpga/libfpgabitstream/src/bitstream_manager.h
index 84c3ec97c..32575c5db 100644
--- a/libopenfpga/libfpgabitstream/src/bitstream_manager.h
+++ b/libopenfpga/libfpgabitstream/src/bitstream_manager.h
@@ -119,6 +119,9 @@ class BitstreamManager {
/* Find the value of bitstream */
bool bit_value(const ConfigBitId& bit_id) const;
+ /* Find the parent block of a configuration bit */
+ ConfigBlockId bit_parent_block(const ConfigBitId& bit_id) const;
+
/* Find a name of a block */
std::string block_name(const ConfigBlockId& block_id) const;
@@ -145,7 +148,7 @@ class BitstreamManager {
public: /* Public Mutators */
/* Add a new configuration bit to the bitstream manager */
- ConfigBitId add_bit(const bool& bit_value);
+ ConfigBitId add_bit(const ConfigBlockId& parent_block, const bool& bit_value);
/* Reserve memory for a number of clocks */
void reserve_blocks(const size_t& num_blocks);
@@ -235,6 +238,7 @@ class BitstreamManager {
std::unordered_set invalid_bit_ids_;
/* value of a bit in the Bitstream */
vtr::vector bit_values_;
+ vtr::vector bit_parent_blocks_;
};
} /* end namespace openfpga */
diff --git a/openfpga/src/base/openfpga_bitstream.cpp b/openfpga/src/base/openfpga_bitstream.cpp
index 3fbffc45d..138ee2032 100644
--- a/openfpga/src/base/openfpga_bitstream.cpp
+++ b/openfpga/src/base/openfpga_bitstream.cpp
@@ -16,7 +16,8 @@
#include "write_xml_arch_bitstream.h"
#include "build_device_bitstream.h"
-#include "fabric_bitstream_writer.h"
+#include "write_text_fabric_bitstream.h"
+#include "write_xml_fabric_bitstream.h"
#include "build_fabric_bitstream.h"
#include "openfpga_bitstream.h"
@@ -65,7 +66,6 @@ int build_fabric_bitstream(OpenfpgaContext& openfpga_ctx,
const Command& cmd, const CommandContext& cmd_context) {
CommandOptionId opt_verbose = cmd.option("verbose");
- CommandOptionId opt_file = cmd.option("file");
/* Build fabric bitstream here */
openfpga_ctx.mutable_fabric_bitstream() = build_fabric_dependent_bitstream(openfpga_ctx.bitstream_manager(),
@@ -73,21 +73,51 @@ int build_fabric_bitstream(OpenfpgaContext& openfpga_ctx,
openfpga_ctx.arch().config_protocol,
cmd_context.option_enable(cmd, opt_verbose));
+ /* TODO: should identify the error code from internal function execution */
+ return CMD_EXEC_SUCCESS;
+}
+
+/********************************************************************
+ * A wrapper function to call the write_fabric_bitstream() in FPGA bitstream
+ *******************************************************************/
+int write_fabric_bitstream(const OpenfpgaContext& openfpga_ctx,
+ const Command& cmd, const CommandContext& cmd_context) {
+
+ CommandOptionId opt_verbose = cmd.option("verbose");
+ CommandOptionId opt_file = cmd.option("file");
+ CommandOptionId opt_file_format = cmd.option("format");
+
/* Write fabric bitstream if required */
int status = CMD_EXEC_SUCCESS;
- if (true == cmd_context.option_enable(cmd, opt_file)) {
- std::string src_dir_path = find_path_dir_name(cmd_context.option_value(cmd, opt_file));
+
+ VTR_ASSERT(true == cmd_context.option_enable(cmd, opt_file));
- /* Create directories */
- create_directory(src_dir_path);
+ std::string src_dir_path = find_path_dir_name(cmd_context.option_value(cmd, opt_file));
+ /* Create directories */
+ create_directory(src_dir_path);
+
+ /* Check file format requirements */
+ std::string file_format("plain_text");
+ if (true == cmd_context.option_enable(cmd, opt_file_format)) {
+ file_format = cmd_context.option_value(cmd, opt_file_format);
+ }
+
+ if (std::string("xml") == file_format) {
+ status = write_fabric_bitstream_to_xml_file(openfpga_ctx.bitstream_manager(),
+ openfpga_ctx.fabric_bitstream(),
+ openfpga_ctx.arch().config_protocol,
+ cmd_context.option_value(cmd, opt_file),
+ cmd_context.option_enable(cmd, opt_verbose));
+ } else {
+ /* By default, output in plain text format */
status = write_fabric_bitstream_to_text_file(openfpga_ctx.bitstream_manager(),
openfpga_ctx.fabric_bitstream(),
openfpga_ctx.arch().config_protocol,
- cmd_context.option_value(cmd, opt_file));
+ cmd_context.option_value(cmd, opt_file),
+ cmd_context.option_enable(cmd, opt_verbose));
}
- /* TODO: should identify the error code from internal function execution */
return status;
}
diff --git a/openfpga/src/base/openfpga_bitstream.h b/openfpga/src/base/openfpga_bitstream.h
index 58f1c7e86..c210d6bab 100644
--- a/openfpga/src/base/openfpga_bitstream.h
+++ b/openfpga/src/base/openfpga_bitstream.h
@@ -21,6 +21,9 @@ int fpga_bitstream(OpenfpgaContext& openfpga_ctx,
int build_fabric_bitstream(OpenfpgaContext& openfpga_ctx,
const Command& cmd, const CommandContext& cmd_context);
+int write_fabric_bitstream(const OpenfpgaContext& openfpga_ctx,
+ const Command& cmd, const CommandContext& cmd_context);
+
} /* end namespace openfpga */
#endif
diff --git a/openfpga/src/base/openfpga_bitstream_command.cpp b/openfpga/src/base/openfpga_bitstream_command.cpp
index 1a337e9d0..fef8dca89 100644
--- a/openfpga/src/base/openfpga_bitstream_command.cpp
+++ b/openfpga/src/base/openfpga_bitstream_command.cpp
@@ -41,9 +41,9 @@ ShellCommandId add_openfpga_repack_command(openfpga::Shell& she
* - Add command dependency
*******************************************************************/
static
-ShellCommandId add_openfpga_arch_bitstream_command(openfpga::Shell& shell,
- const ShellCommandClassId& cmd_class_id,
- const std::vector& dependent_cmds) {
+ShellCommandId add_openfpga_build_arch_bitstream_command(openfpga::Shell& shell,
+ const ShellCommandClassId& cmd_class_id,
+ const std::vector& dependent_cmds) {
Command shell_cmd("build_architecture_bitstream");
/* Add an option '--write_file' */
@@ -75,16 +75,11 @@ ShellCommandId add_openfpga_arch_bitstream_command(openfpga::Shell& shell,
- const ShellCommandClassId& cmd_class_id,
- const std::vector& dependent_cmds) {
+ShellCommandId add_openfpga_build_fabric_bitstream_command(openfpga::Shell& shell,
+ const ShellCommandClassId& cmd_class_id,
+ const std::vector& dependent_cmds) {
Command shell_cmd("build_fabric_bitstream");
- /* Add an option '--file' in short '-f'*/
- CommandOptionId opt_file = shell_cmd.add_option("file", false, "file path to output the fabric bitstream to plain text file");
- shell_cmd.set_option_short_name(opt_file, "f");
- shell_cmd.set_option_require_value(opt_file, openfpga::OPT_STRING);
-
/* Add an option '--verbose' */
shell_cmd.add_option("verbose", false, "Enable verbose output");
@@ -99,6 +94,40 @@ ShellCommandId add_openfpga_fabric_bitstream_command(openfpga::Shell& shell,
+ const ShellCommandClassId& cmd_class_id,
+ const std::vector& dependent_cmds) {
+ Command shell_cmd("write_fabric_bitstream");
+
+ /* Add an option '--file' in short '-f'*/
+ CommandOptionId opt_file = shell_cmd.add_option("file", true, "file path to output the fabric bitstream to plain text file");
+ shell_cmd.set_option_short_name(opt_file, "f");
+ shell_cmd.set_option_require_value(opt_file, openfpga::OPT_STRING);
+
+ /* Add an option '--file_format'*/
+ CommandOptionId opt_file_format = shell_cmd.add_option("format", false, "file format of fabric bitstream [plain_text|xml]. Default: plain_text");
+ shell_cmd.set_option_require_value(opt_file_format, openfpga::OPT_STRING);
+
+ /* Add an option '--verbose' */
+ shell_cmd.add_option("verbose", false, "Enable verbose output");
+
+ /* Add command 'fabric_bitstream' to the Shell */
+ ShellCommandId shell_cmd_id = shell.add_command(shell_cmd, "Write the fabric-dependent bitstream to a file");
+ shell.set_command_class(shell_cmd_id, cmd_class_id);
+ shell.set_command_execute_function(shell_cmd_id, write_fabric_bitstream);
+
+ /* Add command dependency to the Shell */
+ shell.set_command_dependency(shell_cmd_id, dependent_cmds);
+
+ return shell_cmd_id;
+}
+
/********************************************************************
* Top-level function to add all the commands related to FPGA-Bitstream
*******************************************************************/
@@ -121,17 +150,25 @@ void add_openfpga_bitstream_commands(openfpga::Shell& shell) {
* Command 'build_architecture_bitstream'
*/
/* The 'build_architecture_bitstream' command should NOT be executed before 'repack' */
- std::vector cmd_dependency_arch_bitstream;
- cmd_dependency_arch_bitstream.push_back(shell_cmd_repack_id);
- ShellCommandId shell_cmd_arch_bitstream_id = add_openfpga_arch_bitstream_command(shell, openfpga_bitstream_cmd_class, cmd_dependency_arch_bitstream);
+ std::vector cmd_dependency_build_arch_bitstream;
+ cmd_dependency_build_arch_bitstream.push_back(shell_cmd_repack_id);
+ ShellCommandId shell_cmd_build_arch_bitstream_id = add_openfpga_build_arch_bitstream_command(shell, openfpga_bitstream_cmd_class, cmd_dependency_build_arch_bitstream);
/********************************
* Command 'build_fabric_bitstream'
*/
/* The 'build_fabric_bitstream' command should NOT be executed before 'build_architecture_bitstream' */
- std::vector cmd_dependency_fabric_bitstream;
- cmd_dependency_fabric_bitstream.push_back(shell_cmd_arch_bitstream_id);
- add_openfpga_fabric_bitstream_command(shell, openfpga_bitstream_cmd_class, cmd_dependency_fabric_bitstream);
+ std::vector cmd_dependency_build_fabric_bitstream;
+ cmd_dependency_build_fabric_bitstream.push_back(shell_cmd_build_arch_bitstream_id);
+ ShellCommandId shell_cmd_build_fabric_bitstream_id = add_openfpga_build_fabric_bitstream_command(shell, openfpga_bitstream_cmd_class, cmd_dependency_build_fabric_bitstream);
+
+ /********************************
+ * Command 'write_fabric_bitstream'
+ */
+ /* The 'write_fabric_bitstream' command should NOT be executed before 'build_fabric_bitstream' */
+ std::vector cmd_dependency_write_fabric_bitstream;
+ cmd_dependency_write_fabric_bitstream.push_back(shell_cmd_build_fabric_bitstream_id);
+ add_openfpga_write_fabric_bitstream_command(shell, openfpga_bitstream_cmd_class, cmd_dependency_write_fabric_bitstream);
}
} /* end namespace openfpga */
diff --git a/openfpga/src/base/openfpga_naming.cpp b/openfpga/src/base/openfpga_naming.cpp
index f4a72ff61..f743ef3f6 100644
--- a/openfpga/src/base/openfpga_naming.cpp
+++ b/openfpga/src/base/openfpga_naming.cpp
@@ -238,7 +238,7 @@ std::string generate_routing_block_netlist_name(const std::string& prefix,
std::string generate_routing_block_netlist_name(const std::string& prefix,
const vtr::Point& coordinate,
const std::string& postfix) {
- return std::string( prefix + std::to_string(coordinate.x()) + std::string("_") + std::to_string(coordinate.y()) + postfix );
+ return std::string( prefix + std::to_string(coordinate.x()) + std::string("__") + std::to_string(coordinate.y()) + std::string("_") + postfix );
}
/*********************************************************************
@@ -968,10 +968,8 @@ std::string generate_mux_sram_port_name(const CircuitLibrary& circuit_lib,
std::string generate_logical_tile_netlist_name(const std::string& prefix,
const t_pb_graph_node* pb_graph_head,
const std::string& postfix) {
- /* This must be the root node */
- VTR_ASSERT(true == pb_graph_head->is_root());
/* Add the name of physical block */
- std::string module_name = prefix + std::string(pb_graph_head->pb_type->name);
+ std::string module_name = prefix + generate_physical_block_module_name(pb_graph_head->pb_type);
module_name += postfix;
@@ -1183,8 +1181,9 @@ std::string generate_grid_block_instance_name(const std::string& prefix,
module_name += generate_grid_block_netlist_name(block_name, is_block_io, io_side, std::string());
module_name += std::string("_");
module_name += std::to_string(grid_coord.x());
- module_name += std::string("_");
+ module_name += std::string("__");
module_name += std::to_string(grid_coord.y());
+ module_name += std::string("_");
return module_name;
}
@@ -1244,7 +1243,6 @@ std::string generate_physical_block_module_name(t_pb_type* physical_pb_type) {
return module_name;
}
-
/*********************************************************************
* Generate the instance name for physical block with a given index
**********************************************************************/
diff --git a/openfpga/src/base/openfpga_spice.cpp b/openfpga/src/base/openfpga_spice.cpp
index 2b99d33e8..4ef4058ee 100644
--- a/openfpga/src/base/openfpga_spice.cpp
+++ b/openfpga/src/base/openfpga_spice.cpp
@@ -39,7 +39,7 @@ int write_fabric_spice(OpenfpgaContext& openfpga_ctx,
int status = CMD_EXEC_SUCCESS;
status = fpga_fabric_spice(openfpga_ctx.module_graph(),
openfpga_ctx.mutable_spice_netlists(),
- openfpga_ctx.arch().tech_lib,
+ openfpga_ctx.arch(),
options);
return status;
diff --git a/openfpga/src/fpga_bitstream/fabric_bitstream_writer.cpp b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp
similarity index 93%
rename from openfpga/src/fpga_bitstream/fabric_bitstream_writer.cpp
rename to openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp
index 2991dd6a0..f96747212 100644
--- a/openfpga/src/fpga_bitstream/fabric_bitstream_writer.cpp
+++ b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.cpp
@@ -1,6 +1,6 @@
/********************************************************************
* This file includes functions that output a fabric-dependent
- * bitstream database to files in different formats
+ * bitstream database to files in plain text
*******************************************************************/
#include
#include
@@ -17,7 +17,7 @@
#include "openfpga_naming.h"
#include "bitstream_manager_utils.h"
-#include "fabric_bitstream_writer.h"
+#include "write_text_fabric_bitstream.h"
/* begin namespace openfpga */
namespace openfpga {
@@ -95,7 +95,8 @@ int write_fabric_config_bit_to_text_file(std::fstream& fp,
int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manager,
const FabricBitstream& fabric_bitstream,
const ConfigProtocol& config_protocol,
- const std::string& fname) {
+ const std::string& fname,
+ const bool& verbose) {
/* Ensure that we have a valid file name */
if (true == fname.empty()) {
VTR_LOG_ERROR("Received empty file name to output bitstream!\n\tPlease specify a valid file name.\n");
@@ -127,6 +128,11 @@ int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manage
/* Close file handler */
fp.close();
+ VTR_LOGV(verbose,
+ "Outputted %lu configuration bits to plain text file: %s\n",
+ fabric_bitstream.bits().size(),
+ fname.c_str());
+
return status;
}
diff --git a/openfpga/src/fpga_bitstream/fabric_bitstream_writer.h b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.h
similarity index 86%
rename from openfpga/src/fpga_bitstream/fabric_bitstream_writer.h
rename to openfpga/src/fpga_bitstream/write_text_fabric_bitstream.h
index bcf5466b7..9582a185c 100644
--- a/openfpga/src/fpga_bitstream/fabric_bitstream_writer.h
+++ b/openfpga/src/fpga_bitstream/write_text_fabric_bitstream.h
@@ -1,5 +1,5 @@
-#ifndef FABRIC_BITSTREAM_WRITER_H
-#define FABRIC_BITSTREAM_WRITER_H
+#ifndef WRITE_TEXT_FABRIC_BITSTREAM_H
+#define WRITE_TEXT_FABRIC_BITSTREAM_H
/********************************************************************
* Include header files that are required by function declaration
@@ -20,7 +20,8 @@ namespace openfpga {
int write_fabric_bitstream_to_text_file(const BitstreamManager& bitstream_manager,
const FabricBitstream& fabric_bitstream,
const ConfigProtocol& config_protocol,
- const std::string& fname);
+ const std::string& fname,
+ const bool& verbose);
} /* end namespace openfpga */
diff --git a/openfpga/src/fpga_bitstream/write_xml_fabric_bitstream.cpp b/openfpga/src/fpga_bitstream/write_xml_fabric_bitstream.cpp
new file mode 100644
index 000000000..b1d5aeebe
--- /dev/null
+++ b/openfpga/src/fpga_bitstream/write_xml_fabric_bitstream.cpp
@@ -0,0 +1,208 @@
+/********************************************************************
+ * This file includes functions that output a fabric-dependent
+ * bitstream database to files in XML format
+ *******************************************************************/
+#include
+#include
+#include
+
+/* Headers from vtrutil library */
+#include "vtr_assert.h"
+#include "vtr_log.h"
+#include "vtr_time.h"
+
+/* Headers from openfpgautil library */
+#include "openfpga_digest.h"
+
+/* Headers from archopenfpga library */
+
+#include "openfpga_naming.h"
+
+#include "bitstream_manager_utils.h"
+#include "write_xml_fabric_bitstream.h"
+
+/* begin namespace openfpga */
+namespace openfpga {
+
+/********************************************************************
+ * This function write header information to a bitstream file
+ *******************************************************************/
+static
+void write_fabric_bitstream_xml_file_head(std::fstream& fp) {
+ valid_file_stream(fp);
+
+ auto end = std::chrono::system_clock::now();
+ std::time_t end_time = std::chrono::system_clock::to_time_t(end);
+
+ fp << "" << std::endl;
+ fp << std::endl;
+}
+
+/********************************************************************
+ * Write a configuration bit into a plain text file
+ * General format
+ *
+ *
+ *
+ *
+ *
+ * ...
+ *
+ * The format depends on the type of configuration protocol
+ * - Vanilla (standalone): No more information to be included
+ * - Configuration chain: No more information to be included
+ * - Memory bank :
+ *
+ *
+ * - Frame-based configuration protocol :
+ *
+ *
+ * Return:
+ * - 0 if succeed
+ * - 1 if critical errors occured
+ *******************************************************************/
+static
+int write_fabric_config_bit_to_xml_file(std::fstream& fp,
+ const BitstreamManager& bitstream_manager,
+ const FabricBitstream& fabric_bitstream,
+ const FabricBitId& fabric_bit,
+ const e_config_protocol_type& config_type) {
+ if (false == valid_file_stream(fp)) {
+ return 1;
+ }
+
+ write_tab_to_file(fp, 1);
+ fp << "\n";
+
+ /* Output hierarchy of this parent*/
+ const ConfigBitId& config_bit = fabric_bitstream.config_bit(fabric_bit);
+ const ConfigBlockId& config_block = bitstream_manager.bit_parent_block(config_bit);
+ std::vector block_hierarchy = find_bitstream_manager_block_hierarchy(bitstream_manager, config_block);
+ write_tab_to_file(fp, 2);
+ fp << "\n";
+ size_t hierarchy_counter = 0;
+ for (const ConfigBlockId& temp_block : block_hierarchy) {
+ write_tab_to_file(fp, 3);
+ fp << "\n";
+ hierarchy_counter++;
+ }
+ write_tab_to_file(fp, 2);
+ fp << "\n";
+
+ switch (config_type) {
+ case CONFIG_MEM_STANDALONE:
+ case CONFIG_MEM_SCAN_CHAIN:
+ break;
+ case CONFIG_MEM_MEMORY_BANK: {
+ /* Bit line address */
+ write_tab_to_file(fp, 2);
+ fp << "\n";
+
+ write_tab_to_file(fp, 2);
+ fp << "\n";
+ break;
+ }
+ case CONFIG_MEM_FRAME_BASED: {
+ write_tab_to_file(fp, 2);
+ fp << "\n";
+ break;
+ }
+ default:
+ VTR_LOGF_ERROR(__FILE__, __LINE__,
+ "Invalid configuration protocol type!\n");
+ return 1;
+ }
+
+ write_tab_to_file(fp, 1);
+ fp << "\n";
+
+ return 0;
+}
+
+/********************************************************************
+ * Write the fabric bitstream to an XML file
+ * Notes:
+ * - This file is designed to be reused by testbench generators, e.g., CocoTB
+ * - It can NOT be directly loaded to the FPGA fabric
+ * - It include configurable memory paths in full hierarchy
+ *
+ * Return:
+ * - 0 if succeed
+ * - 1 if critical errors occured
+ *******************************************************************/
+int write_fabric_bitstream_to_xml_file(const BitstreamManager& bitstream_manager,
+ const FabricBitstream& fabric_bitstream,
+ const ConfigProtocol& config_protocol,
+ const std::string& fname,
+ const bool& verbose) {
+ /* Ensure that we have a valid file name */
+ if (true == fname.empty()) {
+ VTR_LOG_ERROR("Received empty file name to output bitstream!\n\tPlease specify a valid file name.\n");
+ }
+
+ std::string timer_message = std::string("Write ") + std::to_string(fabric_bitstream.num_bits()) + std::string(" fabric bitstream into xml file '") + fname + std::string("'");
+ vtr::ScopedStartFinishTimer timer(timer_message);
+
+ /* Create the file stream */
+ std::fstream fp;
+ fp.open(fname, std::fstream::out | std::fstream::trunc);
+
+ check_file_stream(fname.c_str(), fp);
+
+ /* Write XML head */
+ write_fabric_bitstream_xml_file_head(fp);
+
+ fp << "\n";
+
+ /* Output fabric bitstream to the file */
+ int status = 0;
+ for (const FabricBitId& fabric_bit : fabric_bitstream.bits()) {
+ status = write_fabric_config_bit_to_xml_file(fp, bitstream_manager,
+ fabric_bitstream,
+ fabric_bit,
+ config_protocol.type());
+ if (1 == status) {
+ break;
+ }
+ }
+
+ /* Print an end to the file here */
+ fp << "\n";
+
+ /* Close file handler */
+ fp.close();
+
+ VTR_LOGV(verbose,
+ "Outputted %lu configuration bits to XML file: %s\n",
+ fabric_bitstream.bits().size(),
+ fname.c_str());
+
+ return status;
+}
+
+} /* end namespace openfpga */
diff --git a/openfpga/src/fpga_bitstream/write_xml_fabric_bitstream.h b/openfpga/src/fpga_bitstream/write_xml_fabric_bitstream.h
new file mode 100644
index 000000000..73bf57912
--- /dev/null
+++ b/openfpga/src/fpga_bitstream/write_xml_fabric_bitstream.h
@@ -0,0 +1,28 @@
+#ifndef WRITE_XML_FABRIC_BITSTREAM_H
+#define WRITE_XML_FABRIC_BITSTREAM_H
+
+/********************************************************************
+ * Include header files that are required by function declaration
+ *******************************************************************/
+#include
+#include
+#include "bitstream_manager.h"
+#include "fabric_bitstream.h"
+#include "config_protocol.h"
+
+/********************************************************************
+ * Function declaration
+ *******************************************************************/
+
+/* begin namespace openfpga */
+namespace openfpga {
+
+int write_fabric_bitstream_to_xml_file(const BitstreamManager& bitstream_manager,
+ const FabricBitstream& fabric_bitstream,
+ const ConfigProtocol& config_protocol,
+ const std::string& fname,
+ const bool& verbose);
+
+} /* end namespace openfpga */
+
+#endif
diff --git a/openfpga/src/fpga_spice/spice_api.cpp b/openfpga/src/fpga_spice/spice_api.cpp
index ab65794ac..658d43851 100644
--- a/openfpga/src/fpga_spice/spice_api.cpp
+++ b/openfpga/src/fpga_spice/spice_api.cpp
@@ -39,7 +39,7 @@ namespace openfpga {
********************************************************************/
int fpga_fabric_spice(const ModuleManager& module_manager,
NetlistManager& netlist_manager,
- const TechnologyLibrary& tech_lib,
+ const Arch& openfpga_arch,
const FabricSpiceOption& options) {
vtr::ScopedStartFinishTimer timer("Write SPICE netlists for FPGA fabric\n");
@@ -71,7 +71,8 @@ int fpga_fabric_spice(const ModuleManager& module_manager,
int status = CMD_EXEC_SUCCESS;
status = print_spice_submodule(netlist_manager,
- tech_lib,
+ module_manager,
+ openfpga_arch,
submodule_dir_path);
if (CMD_EXEC_SUCCESS != status) {
diff --git a/openfpga/src/fpga_spice/spice_api.h b/openfpga/src/fpga_spice/spice_api.h
index a214ac652..cf1ce5a0a 100644
--- a/openfpga/src/fpga_spice/spice_api.h
+++ b/openfpga/src/fpga_spice/spice_api.h
@@ -9,7 +9,7 @@
#include
#include "netlist_manager.h"
#include "module_manager.h"
-#include "technology_library.h"
+#include "openfpga_arch.h"
#include "fabric_spice_options.h"
/********************************************************************
@@ -21,7 +21,7 @@ namespace openfpga {
int fpga_fabric_spice(const ModuleManager& module_manager,
NetlistManager& netlist_manager,
- const TechnologyLibrary& tech_lib,
+ const Arch& openfpga_arch,
const FabricSpiceOption& options);
} /* end namespace openfpga */
diff --git a/openfpga/src/fpga_spice/spice_essential_gates.cpp b/openfpga/src/fpga_spice/spice_essential_gates.cpp
index b21b98b59..7fd144f33 100644
--- a/openfpga/src/fpga_spice/spice_essential_gates.cpp
+++ b/openfpga/src/fpga_spice/spice_essential_gates.cpp
@@ -5,6 +5,7 @@
* logic gates etc.
***********************************************/
#include
+#include
#include
/* Headers from vtrutil library */
@@ -17,15 +18,18 @@
/* Headers from openfpgautil library */
#include "openfpga_digest.h"
+#include "circuit_library_utils.h"
+
#include "spice_constants.h"
+#include "spice_writer_utils.h"
#include "spice_essential_gates.h"
/* begin namespace openfpga */
namespace openfpga {
-/************************************************
+/********************************************************************
* Print a SPICE model wrapper for a transistor model
- ***********************************************/
+ *******************************************************************/
static
int print_spice_transistor_model_wrapper(std::fstream& fp,
const TechnologyLibrary& tech_lib,
@@ -66,9 +70,9 @@ int print_spice_transistor_model_wrapper(std::fstream& fp,
return CMD_EXEC_SUCCESS;
}
-/************************************************
+/********************************************************************
* Generate the SPICE netlist for transistors
- ***********************************************/
+ *******************************************************************/
int print_spice_transistor_wrapper(NetlistManager& netlist_manager,
const TechnologyLibrary& tech_lib,
const std::string& submodule_dir) {
@@ -82,9 +86,11 @@ int print_spice_transistor_wrapper(NetlistManager& netlist_manager,
check_file_stream(spice_fname.c_str(), fp);
/* Create file */
- VTR_LOG("Generating SPICE netlist '%s' for transistor wrappers...",
+ VTR_LOG("Generating SPICE netlist '%s' for transistors...",
spice_fname.c_str());
+ print_spice_file_header(fp, std::string("Transistor wrappers"));
+
/* Iterate over the transistor models */
for (const TechnologyModelId& model : tech_lib.models()) {
/* Focus on transistor model */
@@ -110,4 +116,972 @@ int print_spice_transistor_wrapper(NetlistManager& netlist_manager,
return CMD_EXEC_SUCCESS;
}
+/********************************************************************
+ * Generate the SPICE modeling for a power-gated inverter
+ *
+ * This function is created to be shared by inverter and buffer SPICE netlist writer
+ *
+ * Note:
+ * - This function does NOT create a file
+ * but requires a file stream created
+ * - This function only output SPICE modeling for
+ * an inverter. Any preprocessing or subckt definition should not be included!
+ *******************************************************************/
+static
+int print_spice_powergated_inverter_pmos_modeling(std::fstream& fp,
+ const std::string& trans_name_postfix,
+ const std::string& input_port_name,
+ const std::string& output_port_name,
+ const CircuitLibrary& circuit_lib,
+ const CircuitPortId& enb_port,
+ const TechnologyLibrary& tech_lib,
+ const TechnologyModelId& tech_model,
+ const float& trans_width) {
+
+ if (false == valid_file_stream(fp)) {
+ return CMD_EXEC_FATAL_ERROR;
+ }
+
+ /* Write power-gating transistor pairs using the technology model
+ * Note that for a mulit-bit power gating port, we should cascade the transistors
+ */
+ bool first_enb_pin = true;
+ size_t last_enb_pin;
+ for (const auto& power_gate_pin : circuit_lib.pins(enb_port)) {
+ BasicPort enb_pin(circuit_lib.port_prefix(enb_port), power_gate_pin, power_gate_pin);
+ fp << "Xpmos_powergate_" << trans_name_postfix << "_pin_" << power_gate_pin << " ";
+ /* For the first pin, we should connect it to local VDD*/
+ if (true == first_enb_pin) {
+ fp << output_port_name << "_pmos_pg_" << power_gate_pin << " ";
+ fp << generate_spice_port(enb_pin) << " ";
+ fp << "LVDD ";
+ fp << "LVDD ";
+ first_enb_pin = false;
+ } else {
+ VTR_ASSERT_SAFE(false == first_enb_pin);
+ fp << output_port_name << "_pmos_pg_" << last_enb_pin << " ";
+ fp << generate_spice_port(enb_pin) << " ";
+ fp << output_port_name << "_pmos_pg_" << power_gate_pin << " ";
+ fp << "LVDD ";
+ }
+ fp << tech_lib.transistor_model_name(tech_model, TECH_LIB_TRANSISTOR_PMOS) << TRANSISTOR_WRAPPER_POSTFIX;
+ fp << " W=" << std::setprecision(10) << trans_width;
+ fp << "\n";
+
+ /* Cache the last pin*/
+ last_enb_pin = power_gate_pin;
+ }
+
+ /* Write transistor pairs using the technology model */
+ fp << "Xpmos_" << trans_name_postfix << " ";
+ fp << output_port_name << " ";
+ fp << input_port_name << " ";
+ fp << output_port_name << "_pmos_pg_" << circuit_lib.pins(enb_port).back() << " ";
+ fp << "LVDD ";
+ fp << tech_lib.transistor_model_name(tech_model, TECH_LIB_TRANSISTOR_PMOS) << TRANSISTOR_WRAPPER_POSTFIX;
+ fp << " W=" << std::setprecision(10) << trans_width;
+ fp << "\n";
+
+ return CMD_EXEC_SUCCESS;
+}
+
+/********************************************************************
+ * Generate the SPICE modeling for the NMOS part of a power-gated inverter
+ *
+ * This function is created to be shared by inverter and buffer SPICE netlist writer
+ *
+ * Note:
+ * - This function does NOT create a file
+ * but requires a file stream created
+ * - This function only output SPICE modeling for
+ * an inverter. Any preprocessing or subckt definition should not be included!
+ *******************************************************************/
+static
+int print_spice_powergated_inverter_nmos_modeling(std::fstream& fp,
+ const std::string& trans_name_postfix,
+ const std::string& input_port_name,
+ const std::string& output_port_name,
+ const CircuitLibrary& circuit_lib,
+ const CircuitPortId& en_port,
+ const TechnologyLibrary& tech_lib,
+ const TechnologyModelId& tech_model,
+ const float& trans_width) {
+
+ if (false == valid_file_stream(fp)) {
+ return CMD_EXEC_FATAL_ERROR;
+ }
+
+ bool first_en_pin = true;
+ size_t last_en_pin;
+ for (const auto& power_gate_pin : circuit_lib.pins(en_port)) {
+ BasicPort en_pin(circuit_lib.port_prefix(en_port), power_gate_pin, power_gate_pin);
+ fp << "Xnmos_powergate_" << trans_name_postfix << "_pin_" << power_gate_pin << " ";
+ /* For the first pin, we should connect it to local VDD*/
+ if (true == first_en_pin) {
+ fp << output_port_name << "_nmos_pg_" << power_gate_pin << " ";
+ fp << generate_spice_port(en_pin) << " ";
+ fp << "LGND ";
+ fp << "LGND ";
+ first_en_pin = false;
+ } else {
+ VTR_ASSERT_SAFE(false == first_en_pin);
+ fp << output_port_name << "_nmos_pg_" << last_en_pin << " ";
+ fp << circuit_lib.port_prefix(en_port) << " ";
+ fp << output_port_name << "_nmos_pg_" << power_gate_pin << " ";
+ fp << "LGND ";
+ }
+ fp << tech_lib.transistor_model_name(tech_model, TECH_LIB_TRANSISTOR_NMOS) << TRANSISTOR_WRAPPER_POSTFIX;
+ fp << " W=" << std::setprecision(10) << trans_width;
+ fp << "\n";
+
+ /* Cache the last pin*/
+ last_en_pin = power_gate_pin;
+ }
+
+ fp << "Xnmos_" << trans_name_postfix << " ";
+ fp << output_port_name << " ";
+ fp << input_port_name << " ";
+ fp << output_port_name << " _nmos_pg_" << circuit_lib.pins(en_port).back() << " ";
+ fp << "LGND ";
+ fp << tech_lib.transistor_model_name(tech_model, TECH_LIB_TRANSISTOR_NMOS) << TRANSISTOR_WRAPPER_POSTFIX;
+ fp << " W=" << std::setprecision(10) << trans_width;
+ fp << "\n";
+
+ return CMD_EXEC_SUCCESS;
+}
+
+/********************************************************************
+ * Generate the SPICE subckt for a power gated inverter
+ * The Enable signal controlled the power gating
+ *
+ * Note:
+ * - This function supports multi-bit power gating
+ *
+ * Schematic
+ * LVDD
+ * |
+ * -
+ * ENb[0] -o||
+ * -
+ * |
+ * -
+ * ENb[1] -o||
+ * -
+ * |
+ *
+ * ...
+ *
+ * |
+ * -
+ * +-o||
+ * | -
+ * | |
+ * in-->+ +--> OUT
+ * | |
+ * | -
+ * +--||
+ * -
+ *
+ * ...
+ *
+ * |
+ * -
+ * EN[1] -||
+ * -
+ * |
+ * -
+ * EN[0] -||
+ * -
+ * |
+ * LGND
+ *
+ *******************************************************************/
+static
+int print_spice_powergated_inverter_subckt(std::fstream& fp,
+ const ModuleManager& module_manager,
+ const ModuleId& module_id,
+ const CircuitLibrary& circuit_lib,
+ const CircuitModelId& circuit_model,
+ const TechnologyLibrary& tech_lib,
+ const TechnologyModelId& tech_model) {
+ if (false == valid_file_stream(fp)) {
+ return CMD_EXEC_FATAL_ERROR;
+ }
+
+ /* Print the inverter subckt definition */
+ print_spice_subckt_definition(fp, module_manager, module_id);
+
+ /* Find the input and output ports:
+ * we do NOT support global ports here,
+ * it should be handled in another type of inverter subckt (power-gated)
+ */
+ std::vector input_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true);
+ std::vector output_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, true);
+
+ /* Make sure:
+ * There is only 1 input port and 1 output port,
+ * each size of which is 1
+ */
+ VTR_ASSERT( (1 == input_ports.size()) && (1 == circuit_lib.port_size(input_ports[0])) );
+ VTR_ASSERT( (1 == output_ports.size()) && (1 == circuit_lib.port_size(output_ports[0])) );
+
+ /* If the circuit model is power-gated, we need to find at least one global config_enable signals */
+ VTR_ASSERT(true == circuit_lib.is_power_gated(circuit_model));
+ CircuitPortId en_port = find_circuit_model_power_gate_en_port(circuit_lib, circuit_model);
+ CircuitPortId enb_port = find_circuit_model_power_gate_enb_port(circuit_lib, circuit_model);
+ VTR_ASSERT(true == circuit_lib.valid_circuit_port_id(en_port));
+ VTR_ASSERT(true == circuit_lib.valid_circuit_port_id(enb_port));
+
+ int status = CMD_EXEC_SUCCESS;
+
+ /* Consider use size/bin to compact layout:
+ * Try to size transistors to the max width for each bin
+ * The last bin may not reach the max width
+ */
+ float regular_pmos_bin_width = tech_lib.transistor_model_max_width(tech_model, TECH_LIB_TRANSISTOR_PMOS);
+ float total_pmos_width = circuit_lib.buffer_size(circuit_model)
+ * tech_lib.model_pn_ratio(tech_model)
+ * tech_lib.transistor_model_min_width(tech_model, TECH_LIB_TRANSISTOR_PMOS);
+ int num_pmos_bins = std::ceil(total_pmos_width / regular_pmos_bin_width);
+ float last_pmos_bin_width = std::fmod(total_pmos_width, regular_pmos_bin_width);
+ for (int ibin = 0; ibin < num_pmos_bins; ++ibin) {
+ float curr_bin_width = regular_pmos_bin_width;
+ /* For last bin, we need an irregular width */
+ if ((ibin == num_pmos_bins - 1)
+ && (0. != last_pmos_bin_width)) {
+ curr_bin_width = last_pmos_bin_width;
+ }
+ status = print_spice_powergated_inverter_pmos_modeling(fp,
+ std::to_string(ibin),
+ circuit_lib.port_prefix(input_ports[0]),
+ circuit_lib.port_prefix(output_ports[0]),
+ circuit_lib,
+ enb_port,
+ tech_lib,
+ tech_model,
+ curr_bin_width);
+ if (CMD_EXEC_FATAL_ERROR == status) {
+ return status;
+ }
+ }
+
+ /* Consider use size/bin to compact layout:
+ * Try to size transistors to the max width for each bin
+ * The last bin may not reach the max width
+ */
+ float regular_nmos_bin_width = tech_lib.transistor_model_max_width(tech_model, TECH_LIB_TRANSISTOR_NMOS);
+ float total_nmos_width = circuit_lib.buffer_size(circuit_model)
+ * tech_lib.transistor_model_min_width(tech_model, TECH_LIB_TRANSISTOR_NMOS);
+ int num_nmos_bins = std::ceil(total_nmos_width / regular_nmos_bin_width);
+ float last_nmos_bin_width = std::fmod(total_nmos_width, regular_nmos_bin_width);
+ for (int ibin = 0; ibin < num_nmos_bins; ++ibin) {
+ float curr_bin_width = regular_nmos_bin_width;
+ /* For last bin, we need an irregular width */
+ if ((ibin == num_nmos_bins - 1)
+ && (0. != last_nmos_bin_width)) {
+ curr_bin_width = last_nmos_bin_width;
+ }
+
+ status = print_spice_powergated_inverter_nmos_modeling(fp,
+ std::to_string(ibin),
+ circuit_lib.port_prefix(input_ports[0]),
+ circuit_lib.port_prefix(output_ports[0]),
+ circuit_lib,
+ en_port,
+ tech_lib,
+ tech_model,
+ curr_bin_width);
+ if (CMD_EXEC_FATAL_ERROR == status) {
+ return status;
+ }
+ }
+
+ print_spice_subckt_end(fp, module_manager.module_name(module_id));
+
+ return CMD_EXEC_SUCCESS;
+}
+
+/********************************************************************
+ * Generate the SPICE modeling for the PMOS part of a regular inverter
+ *
+ * This function is created to be shared by inverter and buffer SPICE netlist writer
+ *
+ * Note:
+ * - This function does NOT create a file
+ * but requires a file stream created
+ * - This function only output SPICE modeling for
+ * an inverter. Any preprocessing or subckt definition should not be included!
+ *******************************************************************/
+static
+int print_spice_regular_inverter_pmos_modeling(std::fstream& fp,
+ const std::string& trans_name_postfix,
+ const std::string& input_port_name,
+ const std::string& output_port_name,
+ const TechnologyLibrary& tech_lib,
+ const TechnologyModelId& tech_model,
+ const float& trans_width) {
+
+ if (false == valid_file_stream(fp)) {
+ return CMD_EXEC_FATAL_ERROR;
+ }
+
+ /* Write transistor pairs using the technology model */
+ fp << "Xpmos_" << trans_name_postfix << " ";
+ fp << output_port_name << " ";
+ fp << input_port_name << " ";
+ fp << "LVDD ";
+ fp << "LVDD ";
+ fp << tech_lib.transistor_model_name(tech_model, TECH_LIB_TRANSISTOR_PMOS) << TRANSISTOR_WRAPPER_POSTFIX;
+ fp << " W=" << std::setprecision(10) << trans_width;
+ fp << "\n";
+
+ return CMD_EXEC_SUCCESS;
+}
+
+/********************************************************************
+ * Generate the SPICE modeling for the NMOS part of a regular inverter
+ *
+ * This function is created to be shared by inverter and buffer SPICE netlist writer
+ *
+ * Note:
+ * - This function does NOT create a file
+ * but requires a file stream created
+ * - This function only output SPICE modeling for
+ * an inverter. Any preprocessing or subckt definition should not be included!
+ *******************************************************************/
+static
+int print_spice_regular_inverter_nmos_modeling(std::fstream& fp,
+ const std::string& trans_name_postfix,
+ const std::string& input_port_name,
+ const std::string& output_port_name,
+ const TechnologyLibrary& tech_lib,
+ const TechnologyModelId& tech_model,
+ const float& trans_width) {
+
+ if (false == valid_file_stream(fp)) {
+ return CMD_EXEC_FATAL_ERROR;
+ }
+
+ fp << "Xnmos_" << trans_name_postfix << " ";
+ fp << output_port_name << " ";
+ fp << input_port_name << " ";
+ fp << "LGND ";
+ fp << "LGND ";
+ fp << tech_lib.transistor_model_name(tech_model, TECH_LIB_TRANSISTOR_NMOS) << TRANSISTOR_WRAPPER_POSTFIX;
+ fp << " W=" << std::setprecision(10) << trans_width;
+ fp << "\n";
+
+ return CMD_EXEC_SUCCESS;
+}
+
+/********************************************************************
+ * Generate the SPICE subckt for a regular inverter
+ *
+ * Note:
+ * - This function does NOT support power-gating
+ * It should be managed in a separated function
+ *
+ * Schematic
+ * LVDD
+ * |
+ * -
+ * +-o||
+ * | -
+ * | |
+ * in-->+ +--> OUT
+ * | |
+ * | -
+ * +--||
+ * -
+ * |
+ * LGND
+ *
+ *******************************************************************/
+static
+int print_spice_regular_inverter_subckt(std::fstream& fp,
+ const ModuleManager& module_manager,
+ const ModuleId& module_id,
+ const CircuitLibrary& circuit_lib,
+ const CircuitModelId& circuit_model,
+ const TechnologyLibrary& tech_lib,
+ const TechnologyModelId& tech_model) {
+ if (false == valid_file_stream(fp)) {
+ return CMD_EXEC_FATAL_ERROR;
+ }
+
+ /* Print the inverter subckt definition */
+ print_spice_subckt_definition(fp, module_manager, module_id);
+
+ /* Find the input and output ports:
+ * we do NOT support global ports here,
+ * it should be handled in another type of inverter subckt (power-gated)
+ */
+ std::vector input_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true);
+ std::vector output_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, true);
+
+ /* Make sure:
+ * There is only 1 input port and 1 output port,
+ * each size of which is 1
+ */
+ VTR_ASSERT( (1 == input_ports.size()) && (1 == circuit_lib.port_size(input_ports[0])) );
+ VTR_ASSERT( (1 == output_ports.size()) && (1 == circuit_lib.port_size(output_ports[0])) );
+
+ int status = CMD_EXEC_SUCCESS;
+
+ /* Consider use size/bin to compact layout:
+ * Try to size transistors to the max width for each bin
+ * The last bin may not reach the max width
+ */
+ float regular_pmos_bin_width = tech_lib.transistor_model_max_width(tech_model, TECH_LIB_TRANSISTOR_PMOS);
+ float total_pmos_width = circuit_lib.buffer_size(circuit_model)
+ * tech_lib.model_pn_ratio(tech_model)
+ * tech_lib.transistor_model_min_width(tech_model, TECH_LIB_TRANSISTOR_PMOS);
+ int num_pmos_bins = std::ceil(total_pmos_width / regular_pmos_bin_width);
+ float last_pmos_bin_width = std::fmod(total_pmos_width, regular_pmos_bin_width);
+ for (int ibin = 0; ibin < num_pmos_bins; ++ibin) {
+ float curr_bin_width = regular_pmos_bin_width;
+ /* For last bin, we need an irregular width */
+ if ((ibin == num_pmos_bins - 1)
+ && (0. != last_pmos_bin_width)) {
+ curr_bin_width = last_pmos_bin_width;
+ }
+
+ status = print_spice_regular_inverter_pmos_modeling(fp,
+ std::to_string(ibin),
+ circuit_lib.port_prefix(input_ports[0]),
+ circuit_lib.port_prefix(output_ports[0]),
+ tech_lib,
+ tech_model,
+ curr_bin_width);
+ if (CMD_EXEC_FATAL_ERROR == status) {
+ return status;
+ }
+ }
+
+ /* Consider use size/bin to compact layout:
+ * Try to size transistors to the max width for each bin
+ * The last bin may not reach the max width
+ */
+ float regular_nmos_bin_width = tech_lib.transistor_model_max_width(tech_model, TECH_LIB_TRANSISTOR_NMOS);
+ float total_nmos_width = circuit_lib.buffer_size(circuit_model)
+ * tech_lib.transistor_model_min_width(tech_model, TECH_LIB_TRANSISTOR_NMOS);
+ int num_nmos_bins = std::ceil(total_nmos_width / regular_nmos_bin_width);
+ float last_nmos_bin_width = std::fmod(total_nmos_width, regular_nmos_bin_width);
+
+ for (int ibin = 0; ibin < num_nmos_bins; ++ibin) {
+ float curr_bin_width = regular_nmos_bin_width;
+ /* For last bin, we need an irregular width */
+ if ((ibin == num_nmos_bins - 1)
+ && (0. != last_nmos_bin_width)) {
+ curr_bin_width = last_nmos_bin_width;
+ }
+
+ status = print_spice_regular_inverter_nmos_modeling(fp,
+ std::to_string(ibin),
+ circuit_lib.port_prefix(input_ports[0]),
+ circuit_lib.port_prefix(output_ports[0]),
+ tech_lib,
+ tech_model,
+ curr_bin_width);
+ if (CMD_EXEC_FATAL_ERROR == status) {
+ return status;
+ }
+ }
+
+ print_spice_subckt_end(fp, module_manager.module_name(module_id));
+
+ return status;
+}
+
+/********************************************************************
+ * Generate the SPICE subckt for an inverter
+ * Branch on the different circuit topologies
+ *******************************************************************/
+static
+int print_spice_inverter_subckt(std::fstream& fp,
+ const ModuleManager& module_manager,
+ const ModuleId& module_id,
+ const CircuitLibrary& circuit_lib,
+ const CircuitModelId& circuit_model,
+ const TechnologyLibrary& tech_lib,
+ const TechnologyModelId& tech_model) {
+ int status = CMD_EXEC_SUCCESS;
+ if (true == circuit_lib.is_power_gated(circuit_model)) {
+ status = print_spice_powergated_inverter_subckt(fp,
+ module_manager, module_id,
+ circuit_lib, circuit_model,
+ tech_lib, tech_model);
+ } else {
+ VTR_ASSERT_SAFE(false == circuit_lib.is_power_gated(circuit_model));
+ status = print_spice_regular_inverter_subckt(fp,
+ module_manager, module_id,
+ circuit_lib, circuit_model,
+ tech_lib, tech_model);
+ }
+
+ return status;
+}
+
+/********************************************************************
+ * Generate the SPICE subckt for a power-gated buffer
+ * which contains at least 2 stages
+ *
+ * Schematic of a multi-stage buffer
+ *
+ * LVDD LVDD
+ * | |
+ * - -
+ * ENb[0] -o|| ENb[0] -o||
+ * - -
+ * | |
+ * - -
+ * ENb[1] -o|| ENb[1] -o||
+ * - -
+ * | |
+ *
+ * ...
+ *
+ * | |
+ * - -
+ * +-o|| +-o||
+ * | - | -
+ * | | | |
+ * in-->+ +-- ... ---+---->+---> out
+ * | | | |
+ * | - | -
+ * +--|| +--||
+ * - -
+ * | |
+ *
+ * ...
+ *
+ * | |
+ * - -
+ * EN[0] -|| EN[0] -||
+ * - -
+ * | |
+ * - -
+ * EN[1] -|| EN[1] -||
+ * - -
+ * | |
+
+ * | |
+ * LGND LGND
+ *
+ *******************************************************************/
+static
+int print_spice_powergated_buffer_subckt(std::fstream& fp,
+ const ModuleManager& module_manager,
+ const ModuleId& module_id,
+ const CircuitLibrary& circuit_lib,
+ const CircuitModelId& circuit_model,
+ const TechnologyLibrary& tech_lib,
+ const TechnologyModelId& tech_model) {
+ if (false == valid_file_stream(fp)) {
+ return CMD_EXEC_FATAL_ERROR;
+ }
+
+ /* Print the inverter subckt definition */
+ print_spice_subckt_definition(fp, module_manager, module_id);
+
+ /* Find the input and output ports:
+ * we do NOT support global ports here,
+ * it should be handled in another type of inverter subckt (power-gated)
+ */
+ std::vector input_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true);
+ std::vector output_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, true);
+
+ /* Make sure:
+ * There is only 1 input port and 1 output port,
+ * each size of which is 1
+ */
+ VTR_ASSERT( (1 == input_ports.size()) && (1 == circuit_lib.port_size(input_ports[0])) );
+ VTR_ASSERT( (1 == output_ports.size()) && (1 == circuit_lib.port_size(output_ports[0])) );
+
+ /* If the circuit model is power-gated, we need to find at least one global config_enable signals */
+ VTR_ASSERT(true == circuit_lib.is_power_gated(circuit_model));
+ CircuitPortId en_port = find_circuit_model_power_gate_en_port(circuit_lib, circuit_model);
+ CircuitPortId enb_port = find_circuit_model_power_gate_enb_port(circuit_lib, circuit_model);
+ VTR_ASSERT(true == circuit_lib.valid_circuit_port_id(en_port));
+ VTR_ASSERT(true == circuit_lib.valid_circuit_port_id(enb_port));
+
+ int status = CMD_EXEC_SUCCESS;
+
+ /* Buffers must have >= 2 stages */
+ VTR_ASSERT(2 <= circuit_lib.buffer_num_levels(circuit_model));
+
+ /* Build the array denoting width of inverters per stage */
+ std::vector buffer_widths(circuit_lib.buffer_num_levels(circuit_model), 1);
+ for (size_t level = 0; level < circuit_lib.buffer_num_levels(circuit_model); ++level) {
+ buffer_widths[level] = circuit_lib.buffer_size(circuit_model)
+ * std::pow(circuit_lib.buffer_f_per_stage(circuit_model), level);
+ }
+
+ for (size_t level = 0; level < circuit_lib.buffer_num_levels(circuit_model); ++level) {
+ std::string input_port_name = circuit_lib.port_prefix(input_ports[0]);
+ std::string output_port_name = circuit_lib.port_prefix(output_ports[0]);
+
+ /* Special for first stage: output port should be an intermediate node
+ * Special for rest of stages: input port should be the output of previous stage
+ */
+ if (0 == level) {
+ output_port_name += std::string("_level") + std::to_string(level);
+ } else {
+ VTR_ASSERT(0 < level);
+ input_port_name += std::string("_level") + std::to_string(level - 1);
+ }
+
+ /* Consider use size/bin to compact layout:
+ * Try to size transistors to the max width for each bin
+ * The last bin may not reach the max width
+ */
+ float regular_pmos_bin_width = tech_lib.transistor_model_max_width(tech_model, TECH_LIB_TRANSISTOR_PMOS);
+ float total_pmos_width = buffer_widths[level]
+ * tech_lib.model_pn_ratio(tech_model)
+ * tech_lib.transistor_model_min_width(tech_model, TECH_LIB_TRANSISTOR_PMOS);
+ int num_pmos_bins = std::ceil(total_pmos_width / regular_pmos_bin_width);
+ float last_pmos_bin_width = std::fmod(total_pmos_width, regular_pmos_bin_width);
+
+ for (int ibin = 0; ibin < num_pmos_bins; ++ibin) {
+ float curr_bin_width = regular_pmos_bin_width;
+ /* For last bin, we need an irregular width */
+ if ((ibin == num_pmos_bins - 1)
+ && (0. != last_pmos_bin_width)) {
+ curr_bin_width = last_pmos_bin_width;
+ }
+
+ std::string name_postfix = std::string("level") + std::to_string(level) + std::string("_bin") + std::to_string(ibin);
+
+ status = print_spice_powergated_inverter_pmos_modeling(fp,
+ name_postfix,
+ circuit_lib.port_prefix(input_ports[0]),
+ circuit_lib.port_prefix(output_ports[0]),
+ circuit_lib,
+ enb_port,
+ tech_lib,
+ tech_model,
+ curr_bin_width);
+ if (CMD_EXEC_FATAL_ERROR == status) {
+ return status;
+ }
+ }
+
+ /* Consider use size/bin to compact layout:
+ * Try to size transistors to the max width for each bin
+ * The last bin may not reach the max width
+ */
+ float regular_nmos_bin_width = tech_lib.transistor_model_max_width(tech_model, TECH_LIB_TRANSISTOR_NMOS);
+ float total_nmos_width = buffer_widths[level]
+ * tech_lib.transistor_model_min_width(tech_model, TECH_LIB_TRANSISTOR_NMOS);
+ int num_nmos_bins = std::ceil(total_nmos_width / regular_nmos_bin_width);
+ float last_nmos_bin_width = std::fmod(total_nmos_width, regular_nmos_bin_width);
+
+ for (int ibin = 0; ibin < num_nmos_bins; ++ibin) {
+ float curr_bin_width = regular_nmos_bin_width;
+ /* For last bin, we need an irregular width */
+ if ((ibin == num_nmos_bins - 1)
+ && (0. != last_nmos_bin_width)) {
+ curr_bin_width = last_nmos_bin_width;
+ }
+
+ std::string name_postfix = std::string("level") + std::to_string(level) + std::string("_bin") + std::to_string(ibin);
+
+ status = print_spice_powergated_inverter_nmos_modeling(fp,
+ name_postfix,
+ circuit_lib.port_prefix(input_ports[0]),
+ circuit_lib.port_prefix(output_ports[0]),
+ circuit_lib,
+ en_port,
+ tech_lib,
+ tech_model,
+ curr_bin_width);
+ if (CMD_EXEC_FATAL_ERROR == status) {
+ return status;
+ }
+ }
+ }
+
+ print_spice_subckt_end(fp, module_manager.module_name(module_id));
+
+ return CMD_EXEC_SUCCESS;
+}
+
+
+/********************************************************************
+ * Generate the SPICE subckt for a regular buffer
+ * which contains at least 2 stages
+ *
+ * Note:
+ * - This function does NOT support power-gating
+ * It should be managed in a separated function
+ *
+ * Schematic of a multi-stage buffer
+ *
+ * LVDD LVDD
+ * | |
+ * - -
+ * +-o|| +-o||
+ * | - | -
+ * | | | |
+ * in-->+ +-- ... ---+---->+---> out
+ * | | | |
+ * | - | -
+ * +--|| +--||
+ * - -
+ * | |
+ * LGND LGND
+ *
+ *******************************************************************/
+static
+int print_spice_regular_buffer_subckt(std::fstream& fp,
+ const ModuleManager& module_manager,
+ const ModuleId& module_id,
+ const CircuitLibrary& circuit_lib,
+ const CircuitModelId& circuit_model,
+ const TechnologyLibrary& tech_lib,
+ const TechnologyModelId& tech_model) {
+ if (false == valid_file_stream(fp)) {
+ return CMD_EXEC_FATAL_ERROR;
+ }
+
+ /* Print the inverter subckt definition */
+ print_spice_subckt_definition(fp, module_manager, module_id);
+
+ /* Find the input and output ports:
+ * we do NOT support global ports here,
+ * it should be handled in another type of inverter subckt (power-gated)
+ */
+ std::vector input_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true);
+ std::vector output_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, true);
+
+ /* Make sure:
+ * There is only 1 input port and 1 output port,
+ * each size of which is 1
+ */
+ VTR_ASSERT( (1 == input_ports.size()) && (1 == circuit_lib.port_size(input_ports[0])) );
+ VTR_ASSERT( (1 == output_ports.size()) && (1 == circuit_lib.port_size(output_ports[0])) );
+
+ int status = CMD_EXEC_SUCCESS;
+
+ /* Buffers must have >= 2 stages */
+ VTR_ASSERT(2 <= circuit_lib.buffer_num_levels(circuit_model));
+
+ /* Build the array denoting width of inverters per stage */
+ std::vector buffer_widths(circuit_lib.buffer_num_levels(circuit_model), 1);
+ for (size_t level = 0; level < circuit_lib.buffer_num_levels(circuit_model); ++level) {
+ buffer_widths[level] = circuit_lib.buffer_size(circuit_model)
+ * std::pow(circuit_lib.buffer_f_per_stage(circuit_model), level);
+ }
+
+ for (size_t level = 0; level < circuit_lib.buffer_num_levels(circuit_model); ++level) {
+ std::string input_port_name = circuit_lib.port_prefix(input_ports[0]);
+ std::string output_port_name = circuit_lib.port_prefix(output_ports[0]);
+
+ /* Special for first stage: output port should be an intermediate node
+ * Special for rest of stages: input port should be the output of previous stage
+ */
+ if (0 == level) {
+ output_port_name += std::string("_level") + std::to_string(level);
+ } else {
+ VTR_ASSERT(0 < level);
+ input_port_name += std::string("_level") + std::to_string(level - 1);
+ }
+
+ /* Consider use size/bin to compact layout:
+ * Try to size transistors to the max width for each bin
+ * The last bin may not reach the max width
+ */
+ float regular_pmos_bin_width = tech_lib.transistor_model_max_width(tech_model, TECH_LIB_TRANSISTOR_PMOS);
+ float total_pmos_width = buffer_widths[level]
+ * tech_lib.model_pn_ratio(tech_model)
+ * tech_lib.transistor_model_min_width(tech_model, TECH_LIB_TRANSISTOR_PMOS);
+ int num_pmos_bins = std::ceil(total_pmos_width / regular_pmos_bin_width);
+ float last_pmos_bin_width = std::fmod(total_pmos_width, regular_pmos_bin_width);
+
+ for (int ibin = 0; ibin < num_pmos_bins; ++ibin) {
+ float curr_bin_width = regular_pmos_bin_width;
+ /* For last bin, we need an irregular width */
+ if ((ibin == num_pmos_bins - 1)
+ && (0. != last_pmos_bin_width)) {
+ curr_bin_width = last_pmos_bin_width;
+ }
+
+ std::string name_postfix = std::string("level") + std::to_string(level) + std::string("_bin") + std::to_string(ibin);
+
+ status = print_spice_regular_inverter_pmos_modeling(fp,
+ name_postfix,
+ circuit_lib.port_prefix(input_ports[0]),
+ circuit_lib.port_prefix(output_ports[0]),
+ tech_lib,
+ tech_model,
+ curr_bin_width);
+ if (CMD_EXEC_FATAL_ERROR == status) {
+ return status;
+ }
+ }
+
+ /* Consider use size/bin to compact layout:
+ * Try to size transistors to the max width for each bin
+ * The last bin may not reach the max width
+ */
+ float regular_nmos_bin_width = tech_lib.transistor_model_max_width(tech_model, TECH_LIB_TRANSISTOR_NMOS);
+ float total_nmos_width = buffer_widths[level]
+ * tech_lib.transistor_model_min_width(tech_model, TECH_LIB_TRANSISTOR_NMOS);
+ int num_nmos_bins = std::ceil(total_nmos_width / regular_nmos_bin_width);
+ float last_nmos_bin_width = std::fmod(total_nmos_width, regular_nmos_bin_width);
+
+ for (int ibin = 0; ibin < num_nmos_bins; ++ibin) {
+ float curr_bin_width = regular_nmos_bin_width;
+ /* For last bin, we need an irregular width */
+ if ((ibin == num_nmos_bins - 1)
+ && (0. != last_nmos_bin_width)) {
+ curr_bin_width = last_nmos_bin_width;
+ }
+
+ std::string name_postfix = std::string("level") + std::to_string(level) + std::string("_bin") + std::to_string(ibin);
+
+ status = print_spice_regular_inverter_nmos_modeling(fp,
+ name_postfix,
+ circuit_lib.port_prefix(input_ports[0]),
+ circuit_lib.port_prefix(output_ports[0]),
+ tech_lib,
+ tech_model,
+ curr_bin_width);
+ if (CMD_EXEC_FATAL_ERROR == status) {
+ return status;
+ }
+ }
+ }
+
+ print_spice_subckt_end(fp, module_manager.module_name(module_id));
+
+ return status;
+}
+
+/********************************************************************
+ * Generate the SPICE subckt for an buffer
+ * which consists of multiple stage of inverters
+ *******************************************************************/
+static
+int print_spice_buffer_subckt(std::fstream& fp,
+ const ModuleManager& module_manager,
+ const ModuleId& module_id,
+ const CircuitLibrary& circuit_lib,
+ const CircuitModelId& circuit_model,
+ const TechnologyLibrary& tech_lib,
+ const TechnologyModelId& tech_model) {
+ int status = CMD_EXEC_SUCCESS;
+ if (true == circuit_lib.is_power_gated(circuit_model)) {
+ status = print_spice_powergated_buffer_subckt(fp,
+ module_manager, module_id,
+ circuit_lib, circuit_model,
+ tech_lib, tech_model);
+ } else {
+ VTR_ASSERT_SAFE(false == circuit_lib.is_power_gated(circuit_model));
+ status = print_spice_regular_buffer_subckt(fp,
+ module_manager, module_id,
+ circuit_lib, circuit_model,
+ tech_lib, tech_model);
+ }
+
+ return status;
+}
+
+/********************************************************************
+ * Generate the SPICE netlist for essential gates:
+ * - inverters and their templates
+ * - buffers and their templates
+ * - pass-transistor or transmission gates
+ * - logic gates
+ *******************************************************************/
+int print_spice_essential_gates(NetlistManager& netlist_manager,
+ const ModuleManager& module_manager,
+ const CircuitLibrary& circuit_lib,
+ const TechnologyLibrary& tech_lib,
+ const std::map& circuit_tech_binding,
+ const std::string& submodule_dir) {
+ std::string spice_fname = submodule_dir + std::string(ESSENTIALS_SPICE_FILE_NAME);
+
+ std::fstream fp;
+
+ /* Create the file stream */
+ fp.open(spice_fname, std::fstream::out | std::fstream::trunc);
+ /* Check if the file stream if valid or not */
+ check_file_stream(spice_fname.c_str(), fp);
+
+ /* Create file */
+ VTR_LOG("Generating SPICE netlist '%s' for essential gates...",
+ spice_fname.c_str());
+
+ print_spice_file_header(fp, std::string("Essential gates"));
+
+ int status = CMD_EXEC_SUCCESS;
+
+ /* Iterate over the circuit models */
+ for (const CircuitModelId& circuit_model : circuit_lib.models()) {
+ /* Bypass models require extern netlists */
+ if (!circuit_lib.model_circuit_netlist(circuit_model).empty()) {
+ continue;
+ }
+
+ /* Spot module id */
+ const ModuleId& module_id = module_manager.find_module(circuit_lib.model_name(circuit_model));
+
+ TechnologyModelId tech_model;
+ /* Focus on inverter/buffer/pass-gate/logic gates only */
+ if ( (CIRCUIT_MODEL_INVBUF == circuit_lib.model_type(circuit_model))
+ || (CIRCUIT_MODEL_PASSGATE == circuit_lib.model_type(circuit_model))
+ || (CIRCUIT_MODEL_GATE == circuit_lib.model_type(circuit_model))) {
+ auto result = circuit_tech_binding.find(circuit_model);
+ if (result == circuit_tech_binding.end()) {
+ VTR_LOGF_ERROR(__FILE__, __LINE__,
+ "Unable to find technology binding for circuit model '%s'!\n",
+ circuit_lib.model_name(circuit_model).c_str());
+ return CMD_EXEC_FATAL_ERROR;
+ }
+ /* Valid technology binding. Assign techology model */
+ tech_model = result->second;
+ /* Ensure we have a valid technology model */
+ VTR_ASSERT(true == tech_lib.valid_model_id(tech_model));
+ VTR_ASSERT(TECH_LIB_MODEL_TRANSISTOR == tech_lib.model_type(tech_model));
+ }
+
+ /* Now branch on netlist writing */
+ if (CIRCUIT_MODEL_INVBUF == circuit_lib.model_type(circuit_model)) {
+ if (CIRCUIT_MODEL_BUF_INV == circuit_lib.buffer_type(circuit_model)) {
+ VTR_ASSERT(true == module_manager.valid_module_id(module_id));
+ status = print_spice_inverter_subckt(fp,
+ module_manager, module_id,
+ circuit_lib, circuit_model,
+ tech_lib, tech_model);
+ } else {
+ VTR_ASSERT(CIRCUIT_MODEL_BUF_BUF == circuit_lib.buffer_type(circuit_model));
+ status = print_spice_buffer_subckt(fp,
+ module_manager, module_id,
+ circuit_lib, circuit_model,
+ tech_lib, tech_model);
+ }
+
+ if (CMD_EXEC_FATAL_ERROR == status) {
+ break;
+ }
+
+ /* Finish, go to the next */
+ continue;
+ }
+ }
+
+ /* Close file handler*/
+ fp.close();
+
+ /* Add fname to the netlist name list */
+ NetlistId nlist_id = netlist_manager.add_netlist(spice_fname);
+ VTR_ASSERT(NetlistId::INVALID() != nlist_id);
+ netlist_manager.set_netlist_type(nlist_id, NetlistManager::SUBMODULE_NETLIST);
+
+ VTR_LOG("Done\n");
+
+ return status;
+}
+
} /* end namespace openfpga */
diff --git a/openfpga/src/fpga_spice/spice_essential_gates.h b/openfpga/src/fpga_spice/spice_essential_gates.h
index 055a8a55f..de9ab3cdb 100644
--- a/openfpga/src/fpga_spice/spice_essential_gates.h
+++ b/openfpga/src/fpga_spice/spice_essential_gates.h
@@ -5,7 +5,10 @@
* Include header files that are required by function declaration
*******************************************************************/
#include
+#include