diff --git a/openfpga/src/fpga_spice/spice_buffer.cpp b/openfpga/src/fpga_spice/spice_buffer.cpp index 59fa06d7f..824e3debc 100644 --- a/openfpga/src/fpga_spice/spice_buffer.cpp +++ b/openfpga/src/fpga_spice/spice_buffer.cpp @@ -63,15 +63,15 @@ int print_spice_powergated_inverter_pmos_modeling(std::fstream& fp, if (true == first_enb_pin) { fp << output_port_name << "_pmos_pg_" << power_gate_pin << " "; fp << generate_spice_port(enb_pin) << " "; - fp << "LVDD "; - fp << "LVDD "; + fp << SPICE_SUBCKT_VDD_PORT_NAME << " "; + fp << SPICE_SUBCKT_VDD_PORT_NAME << " "; 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 << SPICE_SUBCKT_VDD_PORT_NAME << " "; } fp << tech_lib.transistor_model_name(tech_model, TECH_LIB_TRANSISTOR_PMOS) << TRANSISTOR_WRAPPER_POSTFIX; fp << " W=" << std::setprecision(10) << trans_width; @@ -86,7 +86,7 @@ int print_spice_powergated_inverter_pmos_modeling(std::fstream& fp, fp << output_port_name << " "; fp << input_port_name << " "; fp << output_port_name << "_pmos_pg_" << circuit_lib.pins(enb_port).back() << " "; - fp << "LVDD "; + fp << SPICE_SUBCKT_VDD_PORT_NAME << " "; fp << tech_lib.transistor_model_name(tech_model, TECH_LIB_TRANSISTOR_PMOS) << TRANSISTOR_WRAPPER_POSTFIX; fp << " W=" << std::setprecision(10) << trans_width; fp << "\n"; @@ -129,15 +129,15 @@ int print_spice_powergated_inverter_nmos_modeling(std::fstream& fp, if (true == first_en_pin) { fp << output_port_name << "_nmos_pg_" << power_gate_pin << " "; fp << generate_spice_port(en_pin) << " "; - fp << "LGND "; - fp << "LGND "; + fp << SPICE_SUBCKT_GND_PORT_NAME << " "; + fp << SPICE_SUBCKT_GND_PORT_NAME << " "; 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 << SPICE_SUBCKT_GND_PORT_NAME << " "; } fp << tech_lib.transistor_model_name(tech_model, TECH_LIB_TRANSISTOR_NMOS) << TRANSISTOR_WRAPPER_POSTFIX; fp << " W=" << std::setprecision(10) << trans_width; @@ -151,7 +151,7 @@ int print_spice_powergated_inverter_nmos_modeling(std::fstream& fp, fp << output_port_name << " "; fp << input_port_name << " "; fp << output_port_name << " _nmos_pg_" << circuit_lib.pins(en_port).back() << " "; - fp << "LGND "; + fp << SPICE_SUBCKT_GND_PORT_NAME << " "; fp << tech_lib.transistor_model_name(tech_model, TECH_LIB_TRANSISTOR_NMOS) << TRANSISTOR_WRAPPER_POSTFIX; fp << " W=" << std::setprecision(10) << trans_width; fp << "\n"; @@ -338,8 +338,8 @@ int print_spice_regular_inverter_pmos_modeling(std::fstream& fp, fp << "Xpmos_" << trans_name_postfix << " "; fp << output_port_name << " "; fp << input_port_name << " "; - fp << "LVDD "; - fp << "LVDD "; + fp << SPICE_SUBCKT_VDD_PORT_NAME << " "; + fp << SPICE_SUBCKT_VDD_PORT_NAME << " "; fp << tech_lib.transistor_model_name(tech_model, TECH_LIB_TRANSISTOR_PMOS) << TRANSISTOR_WRAPPER_POSTFIX; fp << " W=" << std::setprecision(10) << trans_width; fp << "\n"; @@ -374,8 +374,8 @@ int print_spice_regular_inverter_nmos_modeling(std::fstream& fp, fp << "Xnmos_" << trans_name_postfix << " "; fp << output_port_name << " "; fp << input_port_name << " "; - fp << "LGND "; - fp << "LGND "; + fp << SPICE_SUBCKT_GND_PORT_NAME << " "; + fp << SPICE_SUBCKT_GND_PORT_NAME << " "; fp << tech_lib.transistor_model_name(tech_model, TECH_LIB_TRANSISTOR_NMOS) << TRANSISTOR_WRAPPER_POSTFIX; fp << " W=" << std::setprecision(10) << trans_width; fp << "\n"; diff --git a/openfpga/src/fpga_spice/spice_constants.h b/openfpga/src/fpga_spice/spice_constants.h index 770e1b595..80a13af36 100644 --- a/openfpga/src/fpga_spice/spice_constants.h +++ b/openfpga/src/fpga_spice/spice_constants.h @@ -10,4 +10,7 @@ constexpr char* TRANSISTOR_WRAPPER_POSTFIX = "_wrapper"; constexpr char* TRANSISTORS_SPICE_FILE_NAME = "transistor.sp"; constexpr char* ESSENTIALS_SPICE_FILE_NAME = "inv_buf_passgate.sp"; +constexpr char* SPICE_SUBCKT_VDD_PORT_NAME = "VDD"; +constexpr char* SPICE_SUBCKT_GND_PORT_NAME = "VSS"; + #endif diff --git a/openfpga/src/fpga_spice/spice_essential_gates.cpp b/openfpga/src/fpga_spice/spice_essential_gates.cpp index fe554c328..6cad5c6f6 100644 --- a/openfpga/src/fpga_spice/spice_essential_gates.cpp +++ b/openfpga/src/fpga_spice/spice_essential_gates.cpp @@ -24,6 +24,7 @@ #include "spice_writer_utils.h" #include "spice_buffer.h" #include "spice_passgate.h" +#include "spice_logic_gate.h" #include "spice_essential_gates.h" /* begin namespace openfpga */ @@ -112,7 +113,7 @@ int print_spice_essential_gates(NetlistManager& netlist_manager, continue; } - /* Now branch on netlist writing: for inverter/buffers */ + /* Now branch on netlist writing: for pass-gate logic */ if (CIRCUIT_MODEL_PASSGATE == circuit_lib.model_type(circuit_model)) { status = print_spice_passgate_subckt(fp, module_manager, module_id, @@ -126,6 +127,29 @@ int print_spice_essential_gates(NetlistManager& netlist_manager, /* Finish, go to the next */ continue; } + + /* Now branch on netlist writing: for logic gate */ + if (CIRCUIT_MODEL_GATE == circuit_lib.model_type(circuit_model)) { + if (CIRCUIT_MODEL_GATE_AND == circuit_lib.gate_type(circuit_model)) { + status = print_spice_and_gate_subckt(fp, + module_manager, module_id, + circuit_lib, circuit_model, + tech_lib, tech_model); + } else if (CIRCUIT_MODEL_GATE_OR == circuit_lib.gate_type(circuit_model)) { + status = print_spice_or_gate_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*/ diff --git a/openfpga/src/fpga_spice/spice_logic_gate.cpp b/openfpga/src/fpga_spice/spice_logic_gate.cpp new file mode 100644 index 000000000..6eba3da7a --- /dev/null +++ b/openfpga/src/fpga_spice/spice_logic_gate.cpp @@ -0,0 +1,346 @@ +/************************************************ + * This file includes functions on + * outputting SPICE netlists for logic gates: + * - N-input AND gate + * - N-input OR gate + ***********************************************/ +#include +#include +#include + +/* Headers from vtrutil library */ +#include "vtr_assert.h" +#include "vtr_log.h" + +/* Headers from openfpgashell library */ +#include "command_exit_codes.h" + +/* Headers from openfpgautil library */ +#include "openfpga_digest.h" + +#include "circuit_library_utils.h" + +#include "spice_constants.h" +#include "spice_writer_utils.h" +#include "spice_transistor_wrapper.h" +#include "spice_logic_gate.h" + +/* begin namespace openfpga */ +namespace openfpga { + +/******************************************************************** + * Generate the SPICE subckt for a N-input AND gate + * + * Schematic + * + * VDD VDD VDD + * | | | + * - - - + * in0 -o|| in1 -o|| ... in[N-1] -o|| + * - - - + * | | | + * +----+-----+- ... -------------+ + * | + * - + * in0 -|| + * - + * | + * - + * in1 -|| + * - + * | + * ... + * | + * - + * in[N-1] -|| + * - + * | + * GND + *******************************************************************/ +int print_spice_and_gate_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; + } + + /* 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 are at least 2 input ports and 1 output port, + * each size of which is 1 + */ + VTR_ASSERT(2 <= input_ports.size()); + for (const auto& input_port : input_ports) { + VTR_ASSERT(1 == circuit_lib.port_size(input_port)); + } + + VTR_ASSERT( (1 == output_ports.size()) && (1 == circuit_lib.port_size(output_ports[0])) ); + + int status = CMD_EXEC_SUCCESS; + + /* Print the inverter subckt definition */ + print_spice_subckt_definition(fp, module_manager, module_id); + + /* 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 = 1. /* TODO: allow users to define gate strength */ + * 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); + + + /* Output the PMOS network */ + for (const auto& input_port : input_ports) { + 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_generic_pmos_modeling(fp, + std::to_string(ibin), + std::string(SPICE_SUBCKT_VDD_PORT_NAME), + circuit_lib.port_prefix(input_port), + 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 = 1. /* TODO: allow users to define gate strength */ + * 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); + + /* Output the NMOS network */ + for (size_t input_id = 0; input_id < input_ports.size(); ++input_id) { + 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; + } + + /* Depending on the input id, we assign different port names to source/drain */ + std::string source_port_name; + std::string drain_port_name; + + if (0 == input_id) { + /* First transistor should connect to the output port and an internal node */ + source_port_name = circuit_lib.port_prefix(output_ports[0]); + drain_port_name = std::string("internal_node") + std::to_string(input_id); + } else if (input_id == input_ports.size() - 1) { + /* Last transistor should connect to an internal node and GND */ + source_port_name = std::string("internal_node") + std::to_string(input_id - 1); + drain_port_name = std::string(SPICE_SUBCKT_GND_PORT_NAME); + } else { + /* Other transistors should connect to two internal nodes */ + source_port_name = std::string("internal_node") + std::to_string(input_id - 1); + drain_port_name = std::string("internal_node") + std::to_string(input_id); + } + + status = print_spice_generic_nmos_modeling(fp, + std::to_string(ibin), + source_port_name, + circuit_lib.port_prefix(input_ports[input_id]), + drain_port_name, + 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 a N-input OR gate + * + * Schematic + * + * + * VDD + * | + * - + * in0 -o|| + * - + * | + * - + * in1 -o|| + * - + * | + * ... + * | + * - + * in[N-1] -o|| + * - + * | + * +----+-----+- ... -------------+ + * | | | + * - - - + * in0 -|| in1 -|| ... in[N-1] -|| + * - - - + * | | | + * GND GND GND + *******************************************************************/ +int print_spice_or_gate_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; + } + + /* 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 are at least 2 input ports and 1 output port, + * each size of which is 1 + */ + VTR_ASSERT(2 <= input_ports.size()); + for (const auto& input_port : input_ports) { + VTR_ASSERT(1 == circuit_lib.port_size(input_port)); + } + + VTR_ASSERT( (1 == output_ports.size()) && (1 == circuit_lib.port_size(output_ports[0])) ); + + int status = CMD_EXEC_SUCCESS; + + /* Print the inverter subckt definition */ + print_spice_subckt_definition(fp, module_manager, module_id); + + /* 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 = 1. /* TODO: allow users to define gate strength */ + * 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); + + + /* Output the PMOS network */ + for (size_t input_id = 0; input_id < input_ports.size(); ++input_id) { + 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; + } + + /* Depending on the input id, we assign different port names to source/drain */ + std::string source_port_name; + std::string drain_port_name; + + if (0 == input_id) { + /* First transistor should connect to the output port and an internal node */ + source_port_name = circuit_lib.port_prefix(output_ports[0]); + drain_port_name = std::string("internal_node") + std::to_string(input_id); + } else if (input_id == input_ports.size() - 1) { + /* Last transistor should connect to an internal node and GND */ + source_port_name = std::string("internal_node") + std::to_string(input_id - 1); + drain_port_name = std::string(SPICE_SUBCKT_VDD_PORT_NAME); + } else { + /* Other transistors should connect to two internal nodes */ + source_port_name = std::string("internal_node") + std::to_string(input_id - 1); + drain_port_name = std::string("internal_node") + std::to_string(input_id); + } + + status = print_spice_generic_pmos_modeling(fp, + std::to_string(ibin), + source_port_name, + circuit_lib.port_prefix(input_ports[input_id]), + drain_port_name, + 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 = 1. /* TODO: allow users to define gate strength */ + * 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); + + /* Output the NMOS network */ + for (const auto& input_port : input_ports) { + 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_generic_nmos_modeling(fp, + std::to_string(ibin), + circuit_lib.port_prefix(output_ports[0]), + circuit_lib.port_prefix(input_port), + std::string(SPICE_SUBCKT_GND_PORT_NAME), + 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; +} + +} /* end namespace openfpga */ diff --git a/openfpga/src/fpga_spice/spice_logic_gate.h b/openfpga/src/fpga_spice/spice_logic_gate.h new file mode 100644 index 000000000..4a72c803f --- /dev/null +++ b/openfpga/src/fpga_spice/spice_logic_gate.h @@ -0,0 +1,38 @@ +#ifndef SPICE_LOGIC_GATE_H +#define SPICE_LOGIC_GATE_H + +/******************************************************************** + * Include header files that are required by function declaration + *******************************************************************/ +#include +#include +#include "module_manager.h" +#include "circuit_library.h" +#include "technology_library.h" + +/******************************************************************** + * Function declaration + *******************************************************************/ + +/* begin namespace openfpga */ +namespace openfpga { + +int print_spice_and_gate_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 print_spice_or_gate_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); + +} /* end namespace openfpga */ + +#endif diff --git a/openfpga/src/fpga_spice/spice_passgate.cpp b/openfpga/src/fpga_spice/spice_passgate.cpp index d26ac5bfb..cf3702ba7 100644 --- a/openfpga/src/fpga_spice/spice_passgate.cpp +++ b/openfpga/src/fpga_spice/spice_passgate.cpp @@ -248,7 +248,7 @@ int print_spice_passgate_subckt(std::fstream& fp, module_manager, module_id, circuit_lib, circuit_model, tech_lib, tech_model); - } else if (CIRCUIT_MODEL_PASS_GATE_TRANSMISSION == circuit_lib.is_power_gated(circuit_model)) { + } else if (CIRCUIT_MODEL_PASS_GATE_TRANSMISSION == circuit_lib.pass_gate_logic_type(circuit_model)) { status = print_spice_transmission_gate_subckt(fp, module_manager, module_id, circuit_lib, circuit_model, diff --git a/openfpga/src/fpga_spice/spice_transistor_wrapper.cpp b/openfpga/src/fpga_spice/spice_transistor_wrapper.cpp index 882d43f4d..6a90b0c96 100644 --- a/openfpga/src/fpga_spice/spice_transistor_wrapper.cpp +++ b/openfpga/src/fpga_spice/spice_transistor_wrapper.cpp @@ -96,7 +96,7 @@ int print_spice_transistor_wrapper(NetlistManager& netlist_manager, continue; } /* Write a wrapper for the transistor model */ - if (CMD_EXEC_SUCCESS == print_spice_transistor_model_wrapper(fp, tech_lib, model)) { + if (CMD_EXEC_SUCCESS != print_spice_transistor_model_wrapper(fp, tech_lib, model)) { return CMD_EXEC_FATAL_ERROR; } } @@ -144,7 +144,7 @@ int print_spice_generic_pmos_modeling(std::fstream& fp, fp << input_port_name << " "; fp << gate_port_name << " "; fp << output_port_name << " "; - fp << "LVDD "; + fp << SPICE_SUBCKT_VDD_PORT_NAME << " "; fp << tech_lib.transistor_model_name(tech_model, TECH_LIB_TRANSISTOR_PMOS) << TRANSISTOR_WRAPPER_POSTFIX; fp << " W=" << std::setprecision(10) << trans_width; fp << "\n"; @@ -178,7 +178,7 @@ int print_spice_generic_nmos_modeling(std::fstream& fp, fp << input_port_name << " "; fp << gate_port_name << " "; fp << output_port_name << " "; - fp << "LGND "; + fp << SPICE_SUBCKT_GND_PORT_NAME << " "; fp << tech_lib.transistor_model_name(tech_model, TECH_LIB_TRANSISTOR_NMOS) << TRANSISTOR_WRAPPER_POSTFIX; fp << " W=" << std::setprecision(10) << trans_width; fp << "\n";