[FPGA-SPICE] Add wire module SPICE writer
This commit is contained in:
parent
1b2762386c
commit
82e137cbe4
|
@ -25,6 +25,7 @@
|
|||
#include "spice_buffer.h"
|
||||
#include "spice_passgate.h"
|
||||
#include "spice_logic_gate.h"
|
||||
#include "spice_wire.h"
|
||||
#include "spice_essential_gates.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
|
@ -55,7 +56,6 @@ int print_spice_essential_gates(NetlistManager& netlist_manager,
|
|||
/* Output only the model type is supported in auto-generation */
|
||||
if ( (CIRCUIT_MODEL_INVBUF != circuit_lib.model_type(circuit_model))
|
||||
&& (CIRCUIT_MODEL_PASSGATE != circuit_lib.model_type(circuit_model))
|
||||
&& (CIRCUIT_MODEL_CHAN_WIRE != circuit_lib.model_type(circuit_model))
|
||||
&& (CIRCUIT_MODEL_WIRE != circuit_lib.model_type(circuit_model))
|
||||
&& (CIRCUIT_MODEL_GATE != circuit_lib.model_type(circuit_model))) {
|
||||
continue;
|
||||
|
@ -160,15 +160,11 @@ int print_spice_essential_gates(NetlistManager& netlist_manager,
|
|||
}
|
||||
}
|
||||
|
||||
/* Now branch on netlist writing: for routing channel wires */
|
||||
if (CIRCUIT_MODEL_CHAN_WIRE == circuit_lib.model_type(circuit_model)) {
|
||||
netlist_filled = true;
|
||||
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Now branch on netlist writing: for regular wires */
|
||||
/* Now branch on netlist writing: for wires */
|
||||
if (CIRCUIT_MODEL_WIRE == circuit_lib.model_type(circuit_model)) {
|
||||
status = print_spice_wire_subckt(fp,
|
||||
module_manager, module_id,
|
||||
circuit_lib, circuit_model);
|
||||
netlist_filled = true;
|
||||
if (CMD_EXEC_FATAL_ERROR == status) {
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,408 @@
|
|||
/************************************************
|
||||
* This file includes functions on
|
||||
* outputting SPICE netlists for routing wires:
|
||||
* - regular wires (1 input and 1 output)
|
||||
* - routing track wires (1 input and 2 outputs)
|
||||
***********************************************/
|
||||
#include <fstream>
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
|
||||
/* 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 "build_module_graph_utils.h"
|
||||
|
||||
#include "spice_constants.h"
|
||||
#include "spice_writer_utils.h"
|
||||
#include "spice_wire.h"
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
/********************************************************************
|
||||
* Print SPICE modeling for pie-type RC network
|
||||
*
|
||||
* Schematic
|
||||
* middle out
|
||||
* |
|
||||
* in ---wwww----wwww--- ... --wwww---out
|
||||
* | | | |
|
||||
* = = = =
|
||||
* | | | |
|
||||
* GND GND GND GND
|
||||
*******************************************************************/
|
||||
static
|
||||
int print_spice_wire_pi_type_rc_modeling(std::fstream& fp,
|
||||
const std::string& input_port_name,
|
||||
const std::string& output_port_name,
|
||||
const std::string& middle_output_port_name,
|
||||
const float& res_total,
|
||||
const float& cap_total,
|
||||
const size_t& num_levels) {
|
||||
|
||||
/* Determine the resistance and capacitance of each level*/
|
||||
float res_per_level = res_total / ((float)(2 * num_levels));
|
||||
float cap_per_level = cap_total / ((float)(2 * num_levels));
|
||||
|
||||
/* All the resistance and capacitance value should be larger than or equal to zero*/
|
||||
VTR_ASSERT(0. <= res_per_level);
|
||||
VTR_ASSERT(0. <= cap_per_level);
|
||||
|
||||
for (size_t ilvl = 0; ilvl < num_levels; ++ilvl) {
|
||||
/* Print the first capacitor if this is the first level */
|
||||
if ((0 == ilvl) && (0. < cap_per_level)) {
|
||||
print_spice_capacitor(fp, input_port_name, std::string(SPICE_SUBCKT_GND_PORT_NAME), cap_per_level);
|
||||
}
|
||||
/* Output a regular RC pair
|
||||
*
|
||||
* midnode
|
||||
* ^
|
||||
* |
|
||||
* ------+-ww-+-ww-+------
|
||||
* | |
|
||||
* = =
|
||||
* | |
|
||||
* GND GND
|
||||
*/
|
||||
|
||||
std::string lvl_input_port_name = std::string("rc_network_node") + std::to_string(ilvl);
|
||||
if (0 == ilvl) {
|
||||
lvl_input_port_name = input_port_name;
|
||||
}
|
||||
|
||||
std::string lvl_middle_port_name = std::string("rc_network_midnode") + std::to_string(ilvl);
|
||||
|
||||
std::string lvl_output_port_name = std::string("rc_network_node") + std::to_string(ilvl + 1);
|
||||
if (ilvl == num_levels - 1) {
|
||||
lvl_output_port_name = output_port_name;
|
||||
}
|
||||
|
||||
print_spice_resistor(fp, lvl_input_port_name, lvl_middle_port_name, res_per_level);
|
||||
print_spice_resistor(fp, lvl_middle_port_name, lvl_output_port_name, res_per_level);
|
||||
|
||||
/* Last level only require 1 unit of cap_per_level */
|
||||
float cap_curr_level = 2. * cap_per_level;
|
||||
if (ilvl == num_levels - 1) {
|
||||
cap_curr_level = cap_per_level;
|
||||
}
|
||||
|
||||
if (0. < cap_curr_level) {
|
||||
print_spice_capacitor(fp, lvl_output_port_name, std::string(SPICE_SUBCKT_GND_PORT_NAME), cap_curr_level);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the middle output is required, create a short connection to
|
||||
* - when the number of levels is odd
|
||||
*
|
||||
* middle_output
|
||||
* ^
|
||||
* |
|
||||
* ---ww-+-ww-+-ww-+-ww---
|
||||
* | |
|
||||
* = =
|
||||
* | |
|
||||
* GND GND
|
||||
*
|
||||
* - when the number of levels is even:
|
||||
*
|
||||
* middle_output
|
||||
* ^
|
||||
* |
|
||||
* -+-ww--ww-+-ww--ww-+-
|
||||
* | | |
|
||||
* = = =
|
||||
* | | |
|
||||
* GND GND GND
|
||||
*
|
||||
*/
|
||||
if (!middle_output_port_name.empty()) {
|
||||
print_spice_comment(fp, std::string("Connect to the middle output"));
|
||||
std::string rc_midnode_name = std::string("rc_network_node") + std::to_string(num_levels / 2 + 1);
|
||||
if (1 == num_levels % 2) {
|
||||
rc_midnode_name = std::string("rc_network_midnode") + std::to_string(num_levels / 2);
|
||||
}
|
||||
print_spice_short_connection(fp, rc_midnode_name, middle_output_port_name);
|
||||
}
|
||||
|
||||
return CMD_EXEC_SUCCESS;
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Print SPICE modeling for T-type RC network
|
||||
*
|
||||
* Schematic
|
||||
* middle out
|
||||
* |
|
||||
* in ---ww-+--ww--+--ww--+--ww--- ... --ww--+--ww--- out
|
||||
* | | | |
|
||||
* = = = =
|
||||
* | | | |
|
||||
* GND GND GND GND
|
||||
*******************************************************************/
|
||||
static
|
||||
int print_spice_wire_t_type_rc_modeling(std::fstream& fp,
|
||||
const std::string& input_port_name,
|
||||
const std::string& output_port_name,
|
||||
const std::string& middle_output_port_name,
|
||||
const float& res_total,
|
||||
const float& cap_total,
|
||||
const size_t& num_levels) {
|
||||
|
||||
/* Determine the resistance and capacitance of each level*/
|
||||
float res_per_level = res_total / ((float)(2 * num_levels));
|
||||
float cap_per_level = cap_total / ((float)(num_levels));
|
||||
|
||||
/* All the resistance and capacitance value should be larger than or equal to zero*/
|
||||
VTR_ASSERT(0. <= res_per_level);
|
||||
VTR_ASSERT(0. <= cap_per_level);
|
||||
|
||||
for (size_t ilvl = 0; ilvl < num_levels; ++ilvl) {
|
||||
/* Output a regular RC pair
|
||||
*
|
||||
* midnode
|
||||
* ^
|
||||
* |
|
||||
* --------ww-+-ww--------
|
||||
* |
|
||||
* =
|
||||
* |
|
||||
* GND
|
||||
*/
|
||||
|
||||
std::string lvl_input_port_name = std::string("rc_network_node") + std::to_string(ilvl);
|
||||
if (0 == ilvl) {
|
||||
lvl_input_port_name = input_port_name;
|
||||
}
|
||||
|
||||
std::string lvl_middle_port_name = std::string("rc_network_midnode") + std::to_string(ilvl);
|
||||
|
||||
std::string lvl_output_port_name = std::string("rc_network_node") + std::to_string(ilvl + 1);
|
||||
if (ilvl == num_levels - 1) {
|
||||
lvl_output_port_name = output_port_name;
|
||||
}
|
||||
|
||||
print_spice_resistor(fp, lvl_input_port_name, lvl_middle_port_name, res_per_level);
|
||||
print_spice_resistor(fp, lvl_middle_port_name, lvl_output_port_name, res_per_level);
|
||||
|
||||
if (0. < cap_per_level) {
|
||||
print_spice_capacitor(fp, lvl_middle_port_name, std::string(SPICE_SUBCKT_GND_PORT_NAME), cap_per_level);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the middle output is required, create a short connection to
|
||||
* - when the number of levels is even
|
||||
*
|
||||
* middle_output
|
||||
* ^
|
||||
* |
|
||||
* ---ww-+-ww-+-ww-+-ww---
|
||||
* | |
|
||||
* = =
|
||||
* | |
|
||||
* GND GND
|
||||
*
|
||||
* - when the number of levels is odd:
|
||||
*
|
||||
* middle_output
|
||||
* ^
|
||||
* |
|
||||
* -+-ww--ww-+-ww--ww-+-
|
||||
* | | |
|
||||
* = = =
|
||||
* | | |
|
||||
* GND GND GND
|
||||
*
|
||||
*/
|
||||
if (!middle_output_port_name.empty()) {
|
||||
print_spice_comment(fp, std::string("Connect to the middle output"));
|
||||
std::string rc_midnode_name = std::string("rc_network_midnode") + std::to_string(num_levels / 2);
|
||||
if (0 == num_levels % 2) {
|
||||
rc_midnode_name = std::string("rc_network_node") + std::to_string(num_levels / 2 + 1);
|
||||
}
|
||||
print_spice_short_connection(fp, rc_midnode_name, middle_output_port_name);
|
||||
}
|
||||
|
||||
return CMD_EXEC_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/********************************************************************
|
||||
* Generate the SPICE subckt for a regular wire
|
||||
*
|
||||
* Schematic
|
||||
*
|
||||
* Middle output (only for routing track wires)
|
||||
* ^
|
||||
* |
|
||||
* +--------------------+ +---------------+ +--------------------+
|
||||
* in ->| Inverter or buffer |--->| RC Network |---->| Inverter or buffer |---> out
|
||||
* | Optional | | | | Optional |
|
||||
* +--------------------- +---------------+ +--------------------+
|
||||
*
|
||||
*******************************************************************/
|
||||
int print_spice_wire_subckt(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& module_id,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_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<CircuitPortId> input_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_INPUT, true);
|
||||
std::vector<CircuitPortId> output_ports = circuit_lib.model_ports_by_type(circuit_model, CIRCUIT_MODEL_PORT_OUTPUT, true);
|
||||
|
||||
/* Make sure:
|
||||
* There are 1 input ports 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;
|
||||
|
||||
/* Print the inverter subckt definition */
|
||||
print_spice_subckt_definition(fp, module_manager, module_id);
|
||||
|
||||
std::string input_port_name = circuit_lib.port_prefix(input_ports[0]);
|
||||
std::string output_port_name = circuit_lib.port_prefix(output_ports[0]);
|
||||
std::string middle_output_port_name;
|
||||
if (CIRCUIT_MODEL_CHAN_WIRE == circuit_lib.model_type(circuit_model)) {
|
||||
middle_output_port_name = std::string("middle") + output_port_name;
|
||||
}
|
||||
|
||||
std::string rc_ntwk_input_port_name = std::string("rc_network_node") + std::to_string(0);
|
||||
std::string rc_ntwk_output_port_name = std::string("rc_network_node") + std::to_string(circuit_lib.wire_num_level(circuit_model) - 1);
|
||||
std::string rc_ntwk_middle_output_port_name;
|
||||
if (CIRCUIT_MODEL_CHAN_WIRE == circuit_lib.model_type(circuit_model)) {
|
||||
rc_ntwk_middle_output_port_name = std::string("middle") + rc_ntwk_output_port_name;
|
||||
}
|
||||
|
||||
ModulePortId wire_module_input_port = module_manager.find_module_port(module_id, input_port_name);
|
||||
ModulePortId wire_module_output_port = module_manager.find_module_port(module_id, output_port_name);
|
||||
ModulePortId wire_module_middle_output_port = ModulePortId::INVALID();
|
||||
if (CIRCUIT_MODEL_CHAN_WIRE == circuit_lib.model_type(circuit_model)) {
|
||||
wire_module_middle_output_port = module_manager.find_module_port(module_id, output_port_name);
|
||||
}
|
||||
|
||||
/* Add input buffer:
|
||||
* - There is a valid buffer model, instanciate it
|
||||
* - There is no buffer, set a short connection
|
||||
*/
|
||||
if (circuit_lib.input_buffer_model(circuit_model)) {
|
||||
std::string instance_name = std::string("input_buffer");
|
||||
std::map<std::string, BasicPort> port2port_name_map;
|
||||
|
||||
ModuleId buffer_module = module_manager.find_module(circuit_lib.model_name(circuit_lib.input_buffer_model(circuit_model)));
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(buffer_module));
|
||||
|
||||
ModulePortId module_input_port_id = find_inverter_buffer_module_port(module_manager, buffer_module, circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_INPUT);
|
||||
ModulePortId module_output_port_id = find_inverter_buffer_module_port(module_manager, buffer_module, circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_OUTPUT);
|
||||
|
||||
/* Port size should be 1 ! */
|
||||
VTR_ASSERT(1 == module_manager.module_port(buffer_module, module_input_port_id).get_width());
|
||||
VTR_ASSERT(1 == module_manager.module_port(buffer_module, module_output_port_id).get_width());
|
||||
|
||||
port2port_name_map[module_manager.module_port(buffer_module, module_input_port_id).get_name()] = module_manager.module_port(module_id, wire_module_input_port);
|
||||
port2port_name_map[module_manager.module_port(buffer_module, module_output_port_id).get_name()] = BasicPort(rc_ntwk_input_port_name, 1);
|
||||
|
||||
print_spice_subckt_instance(fp,
|
||||
module_manager,
|
||||
buffer_module,
|
||||
instance_name,
|
||||
port2port_name_map);
|
||||
} else {
|
||||
print_spice_short_connection(fp, circuit_lib.port_prefix(input_ports[0]), rc_ntwk_input_port_name);
|
||||
}
|
||||
|
||||
/* Determine which type of model to print*/
|
||||
switch (circuit_lib.wire_type(circuit_model)) {
|
||||
case WIRE_MODEL_PI:
|
||||
status = print_spice_wire_pi_type_rc_modeling(fp,
|
||||
rc_ntwk_input_port_name,
|
||||
rc_ntwk_output_port_name,
|
||||
rc_ntwk_middle_output_port_name,
|
||||
circuit_lib.wire_r(circuit_model),
|
||||
circuit_lib.wire_c(circuit_model),
|
||||
circuit_lib.wire_num_level(circuit_model));
|
||||
break;
|
||||
case WIRE_MODEL_T:
|
||||
status = print_spice_wire_t_type_rc_modeling(fp,
|
||||
rc_ntwk_input_port_name,
|
||||
rc_ntwk_output_port_name,
|
||||
rc_ntwk_middle_output_port_name,
|
||||
circuit_lib.wire_r(circuit_model),
|
||||
circuit_lib.wire_c(circuit_model),
|
||||
circuit_lib.wire_num_level(circuit_model));
|
||||
break;
|
||||
default:
|
||||
VTR_LOGF_ERROR(__FILE__, __LINE__,
|
||||
"Unsupport wire model type for circuit model '%s.\n",
|
||||
circuit_lib.model_name(circuit_model).c_str());
|
||||
return CMD_EXEC_FATAL_ERROR;
|
||||
}
|
||||
|
||||
/* Add output buffer:
|
||||
* - There is a valid buffer model, instanciate it
|
||||
* - There is no buffer, set a short connection
|
||||
*/
|
||||
if (circuit_lib.output_buffer_model(circuit_model)) {
|
||||
std::string instance_name = std::string("output_buffer");
|
||||
std::map<std::string, BasicPort> port2port_name_map;
|
||||
|
||||
ModuleId buffer_module = module_manager.find_module(circuit_lib.model_name(circuit_lib.output_buffer_model(circuit_model)));
|
||||
VTR_ASSERT(true == module_manager.valid_module_id(buffer_module));
|
||||
|
||||
ModulePortId module_input_port_id = find_inverter_buffer_module_port(module_manager, buffer_module, circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_INPUT);
|
||||
ModulePortId module_output_port_id = find_inverter_buffer_module_port(module_manager, buffer_module, circuit_lib, circuit_model, CIRCUIT_MODEL_PORT_OUTPUT);
|
||||
|
||||
/* Port size should be 1 ! */
|
||||
VTR_ASSERT(1 == module_manager.module_port(buffer_module, module_input_port_id).get_width());
|
||||
VTR_ASSERT(1 == module_manager.module_port(buffer_module, module_output_port_id).get_width());
|
||||
|
||||
port2port_name_map[module_manager.module_port(buffer_module, module_input_port_id).get_name()] = BasicPort(rc_ntwk_output_port_name, 1);
|
||||
port2port_name_map[module_manager.module_port(buffer_module, module_output_port_id).get_name()] = module_manager.module_port(module_id, wire_module_output_port);
|
||||
|
||||
print_spice_subckt_instance(fp,
|
||||
module_manager,
|
||||
buffer_module,
|
||||
instance_name,
|
||||
port2port_name_map);
|
||||
|
||||
if (!rc_ntwk_middle_output_port_name.empty()) {
|
||||
instance_name = std::string("middle_output_buffer");
|
||||
port2port_name_map[module_manager.module_port(buffer_module, module_output_port_id).get_name()] = module_manager.module_port(module_id, wire_module_middle_output_port);
|
||||
|
||||
print_spice_subckt_instance(fp,
|
||||
module_manager,
|
||||
buffer_module,
|
||||
instance_name,
|
||||
port2port_name_map);
|
||||
}
|
||||
} else {
|
||||
print_spice_short_connection(fp, rc_ntwk_output_port_name, circuit_lib.port_prefix(output_ports[0]));
|
||||
if (!rc_ntwk_middle_output_port_name.empty()) {
|
||||
print_spice_short_connection(fp, rc_ntwk_middle_output_port_name, circuit_lib.port_prefix(output_ports[0]));
|
||||
}
|
||||
}
|
||||
|
||||
print_spice_subckt_end(fp, module_manager.module_name(module_id));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
|
@ -0,0 +1,27 @@
|
|||
#ifndef SPICE_WIRE_H
|
||||
#define SPICE_WIRE_H
|
||||
|
||||
/********************************************************************
|
||||
* Include header files that are required by function declaration
|
||||
*******************************************************************/
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "module_manager.h"
|
||||
#include "circuit_library.h"
|
||||
|
||||
/********************************************************************
|
||||
* Function declaration
|
||||
*******************************************************************/
|
||||
|
||||
/* begin namespace openfpga */
|
||||
namespace openfpga {
|
||||
|
||||
int print_spice_wire_subckt(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& module_id,
|
||||
const CircuitLibrary& circuit_lib,
|
||||
const CircuitModelId& circuit_model);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
|
@ -168,4 +168,159 @@ void print_spice_subckt_end(std::fstream& fp,
|
|||
fp << std::endl;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Print a resistor in SPICE syntax
|
||||
***********************************************/
|
||||
void print_spice_resistor(std::fstream& fp,
|
||||
const std::string& input_port,
|
||||
const std::string& output_port,
|
||||
const float& resistance) {
|
||||
VTR_ASSERT(true == valid_file_stream(fp));
|
||||
|
||||
/* Set an unique name to the resistor */
|
||||
fp << "R" << input_port << "_to_" << output_port;
|
||||
fp << " " << input_port;
|
||||
fp << " " << output_port;
|
||||
fp << " " << std::setprecision(10) << resistance;
|
||||
fp << std::endl;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Print a capacitor in SPICE syntax
|
||||
***********************************************/
|
||||
void print_spice_capacitor(std::fstream& fp,
|
||||
const std::string& input_port,
|
||||
const std::string& output_port,
|
||||
const float& capacitance) {
|
||||
VTR_ASSERT(true == valid_file_stream(fp));
|
||||
|
||||
/* Set an unique name to the capacitor */
|
||||
fp << "C" << input_port << "_to_" << output_port;
|
||||
fp << " " << input_port;
|
||||
fp << " " << output_port;
|
||||
fp << " " << std::setprecision(10) << capacitance;
|
||||
fp << std::endl;
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* Print a short-connected wire using zero resistance in SPICE syntax
|
||||
***********************************************/
|
||||
void print_spice_short_connection(std::fstream& fp,
|
||||
const std::string& input_port,
|
||||
const std::string& output_port) {
|
||||
print_spice_resistor(fp, input_port, output_port, 0.);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
* Print an instance in SPICE format (a generic version)
|
||||
* This function will require user to provide an instance name
|
||||
*
|
||||
* This function will output the port map by referring to a port-to-port
|
||||
* mapping:
|
||||
* <module_port_name> -> <instance_port_name>
|
||||
* The key of the port-to-port mapping is the port name of the module:
|
||||
* The value of the port-to-port mapping is the port information of the instance
|
||||
* With link between module and instance, the function can output a SPICE
|
||||
* instance easily, by following the define port sequence of the module
|
||||
*
|
||||
* Note that, it is not necessary that the port-to-port mapping
|
||||
* covers all the module ports.
|
||||
* Any instance/module port which are not specified in the port-to-port
|
||||
* mapping will be output by the module port name.
|
||||
*******************************************************************/
|
||||
void print_spice_subckt_instance(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& module_id,
|
||||
const std::string& instance_name,
|
||||
const std::map<std::string, BasicPort>& port2port_name_map) {
|
||||
|
||||
VTR_ASSERT(true == valid_file_stream(fp));
|
||||
|
||||
/* Check: all the key ports in the port2port_name_map does exist in the child module */
|
||||
for (const auto& kv : port2port_name_map) {
|
||||
ModulePortId module_port_id = module_manager.find_module_port(module_id, kv.first);
|
||||
VTR_ASSERT(ModulePortId::INVALID() != module_port_id);
|
||||
}
|
||||
|
||||
/* Print instance name */
|
||||
std::string instance_head_line = "X " + instance_name + " ";
|
||||
fp << instance_head_line;
|
||||
|
||||
/* Port sequence: global, inout, input, output and clock ports, */
|
||||
bool fit_one_line = true;
|
||||
bool new_line = false;
|
||||
size_t pin_cnt = 0;
|
||||
for (int port_type = ModuleManager::MODULE_GLOBAL_PORT;
|
||||
port_type < ModuleManager::NUM_MODULE_PORT_TYPES;
|
||||
++port_type) {
|
||||
for (const auto& port : module_manager.module_ports_by_type(module_id, static_cast<ModuleManager::e_module_port_type>(port_type))) {
|
||||
/* Deposit a default port name */
|
||||
BasicPort port_to_print = port;
|
||||
/* Try to find the instanced port name in the name map */
|
||||
auto port_search_result = port2port_name_map.find(port.get_name());
|
||||
if (port_search_result != port2port_name_map.end()) {
|
||||
/* Found it, we assign the port name */
|
||||
/* TODO: make sure the port width matches! */
|
||||
ModulePortId module_port_id = module_manager.find_module_port(module_id, port.get_name());
|
||||
/* Get the port from module */
|
||||
BasicPort module_port = module_manager.module_port(module_id, module_port_id);
|
||||
VTR_ASSERT(module_port.get_width() == port_search_result->second.get_width());
|
||||
|
||||
port_to_print = port_search_result->second;
|
||||
}
|
||||
|
||||
/* Print port: only the port name is enough */
|
||||
for (const auto& pin : port_to_print.pins()) {
|
||||
|
||||
if (true == new_line) {
|
||||
std::string port_whitespace(instance_head_line.length() - 2, ' ');
|
||||
fp << "+ " << port_whitespace;
|
||||
}
|
||||
|
||||
if (0 != pin_cnt) {
|
||||
write_space_to_file(fp, 1);
|
||||
}
|
||||
|
||||
BasicPort port_pin(port.get_name(), pin, pin);
|
||||
|
||||
/* For single-bit port,
|
||||
* we can print the port name directly
|
||||
*/
|
||||
bool omit_pin_zero = false;
|
||||
if ((1 == port.pins().size())
|
||||
&& (0 == pin)) {
|
||||
omit_pin_zero = true;
|
||||
}
|
||||
|
||||
fp << generate_spice_port(port_pin, omit_pin_zero);
|
||||
|
||||
/* Increase the counter */
|
||||
pin_cnt++;
|
||||
|
||||
/* Currently we limit 10 ports per line to keep a clean netlist */
|
||||
new_line = false;
|
||||
if (10 == pin_cnt) {
|
||||
pin_cnt = 0;
|
||||
fp << std::endl;
|
||||
new_line = true;
|
||||
fit_one_line = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Print module name:
|
||||
* if port print cannot fit one line, we create a new line for the module for a clean format
|
||||
*/
|
||||
if (false == fit_one_line) {
|
||||
fp << std::endl;
|
||||
fp << "+";
|
||||
}
|
||||
write_space_to_file(fp, 1);
|
||||
fp << module_manager.module_name(module_id);
|
||||
|
||||
/* Print an end to the instance */
|
||||
fp << std::endl;
|
||||
}
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
|
|
@ -48,6 +48,26 @@ void print_spice_subckt_definition(std::fstream& fp,
|
|||
void print_spice_subckt_end(std::fstream& fp,
|
||||
const std::string& module_name);
|
||||
|
||||
void print_spice_resistor(std::fstream& fp,
|
||||
const std::string& input_port,
|
||||
const std::string& output_port,
|
||||
const float& resistance);
|
||||
|
||||
void print_spice_capacitor(std::fstream& fp,
|
||||
const std::string& input_port,
|
||||
const std::string& output_port,
|
||||
const float& capacitance);
|
||||
|
||||
void print_spice_short_connection(std::fstream& fp,
|
||||
const std::string& input_port,
|
||||
const std::string& output_port);
|
||||
|
||||
void print_spice_subckt_instance(std::fstream& fp,
|
||||
const ModuleManager& module_manager,
|
||||
const ModuleId& module_id,
|
||||
const std::string& instance_name,
|
||||
const std::map<std::string, BasicPort>& port2port_name_map);
|
||||
|
||||
} /* end namespace openfpga */
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue