diff --git a/search/WriteSpice.cc b/search/WriteSpice.cc deleted file mode 100644 index 65bdb990..00000000 --- a/search/WriteSpice.cc +++ /dev/null @@ -1,927 +0,0 @@ -// OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#include -#include -#include -#include -#include "Machine.hh" -#include "Debug.hh" -#include "Error.hh" -#include "Report.hh" -#include "StringUtil.hh" -#include "FuncExpr.hh" -#include "Liberty.hh" -#include "TimingArc.hh" -#include "Network.hh" -#include "Graph.hh" -#include "Sdc.hh" -#include "DcalcAnalysisPt.hh" -#include "Parasitics.hh" -#include "PathAnalysisPt.hh" -#include "Path.hh" -#include "PathRef.hh" -#include "PathExpanded.hh" -#include "StaState.hh" -#include "WriteSpice.hh" - -namespace sta { - -using std::string; -using std::ofstream; -using std::ifstream; - -typedef Vector StringVector; -typedef Map CellSpicePortNames; -typedef int Stage; -typedef Map ParasiticNodeMap; - -void -split(const string &text, - const string &delims, - // Return values. - StringVector &tokens); -void -streamPrint(ofstream &stream, - const char *fmt, - ...) __attribute__((format (printf, 2, 3))); - -//////////////////////////////////////////////////////////////// - -class WriteSpice : public StaState -{ -public: - WriteSpice(Path *path, - const char *spice_filename, - const char *subckts_filename, - const char *lib_subckts_filename, - const char *models_filename, - const StaState *sta); - ~WriteSpice(); - void writeSpice();; - -private: - void writeHeader(); - void writeStageInstances(); - void writeInputSource(); - void writeStageSubckts(); - void writeInputStage(Stage stage); - void writeMeasureStmts(); - void writeGateStage(Stage stage); - void writeStageVoltageSources(LibertyCell *cell, - StringVector *spice_port_names, - const char *inst_name, - LibertyPort *from_port, - LibertyPort *drvr_port); - void writeStageParasitics(Stage stage); - void writeSubckts(); - void findPathCellnames(// Return values. - StringSet &path_cell_names); - void recordSpicePortNames(const char *cell_name, - StringVector &tokens); - float pgPortVoltage(const char *pg_port_name, - LibertyCell *cell); - float pgPortVoltage(LibertyPgPort *pg_port); - float maxTime(); - const char *nodeName(ParasiticNode *node); - void initNodeMap(const char *net_name); - - // Stage "accessors". - // Internally a stage index from stageFirst() to stageLast() - // is turned into an index into path_expanded_. - Stage stageFirst(); - Stage stageLast(); - string stageName(Stage stage); - int stageGateInputPathIndex(Stage stage); - int stageDrvrPathIndex(Stage stage); - int stageLoadPathIndex(Stage stage); - PathRef *stageGateInputPath(Stage stage); - PathRef *stageDrvrPath(Stage stage); - PathRef *stageLoadPath(Stage stage); - TimingArc *stageGateArc(Stage stage); - TimingArc *stageWireArc(Stage stage); - Edge *stageGateEdge(Stage stage); - Edge *stageWireEdge(Stage stage); - Pin *stageInputPin(Stage stage); - Pin *stageDrvrPin(Stage stage); - Pin *stageLoadPin(Stage stage); - const char *stageInputPinName(Stage stage); - const char *stageDrvrPinName(Stage stage); - const char *stageLoadPinName(Stage stage); - - Path *path_; - const char *spice_filename_; - const char *subckts_filename_; - const char *lib_subckts_filename_; - const char *models_filename_; - - ofstream spice_stream_; - PathExpanded path_expanded_; - CellSpicePortNames cell_spice_port_names_; - ParasiticNodeMap node_map_; - int next_node_index_; - const char *net_name_; - - // Resistance to use to simulate a short circuit between spice nodes. - static const float short_ckt_resistance_; -}; - -//////////////////////////////////////////////////////////////// - -class SubcktEndsMissing : public StaException -{ -public: - SubcktEndsMissing(const char *cell_name, - const char *subckt_filename);; - const char *what() const throw(); - -protected: - string what_; -}; - -SubcktEndsMissing::SubcktEndsMissing(const char *cell_name, - const char *subckt_filename) -{ - what_ = "Error: spice subckt for cell "; - what_ += cell_name; - what_ += " missing .ends in "; - what_ += subckt_filename; -} - -const char * -SubcktEndsMissing::what() const throw() -{ - return what_.c_str(); -} - -//////////////////////////////////////////////////////////////// - -void -writeSpice (Path *path, - const char *spice_filename, - const char *subckts_filename, - const char *lib_subckts_filename, - const char *models_filename, - StaState *sta) -{ - WriteSpice writer(path, spice_filename, subckts_filename, - lib_subckts_filename, models_filename, sta); - writer.writeSpice(); -} - -const float WriteSpice::short_ckt_resistance_ = .0001; - -WriteSpice::WriteSpice(Path *path, - const char *spice_filename, - const char *subckts_filename, - const char *lib_subckts_filename, - const char *models_filename, - const StaState *sta) : - StaState(sta), - path_(path), - spice_filename_(spice_filename), - subckts_filename_(subckts_filename), - lib_subckts_filename_(lib_subckts_filename), - models_filename_(models_filename), - path_expanded_(sta), - net_name_(NULL) -{ -} - -WriteSpice::~WriteSpice() -{ - cell_spice_port_names_.deleteContents(); -} - -void -WriteSpice::writeSpice() -{ - spice_stream_.open(spice_filename_); - if (spice_stream_.is_open()) { - path_expanded_.expand(path_, true); - // Find subckt port names as a side-effect of writeSubckts. - writeSubckts(); - writeHeader(); - writeStageInstances(); - writeInputSource(); - writeStageSubckts(); - streamPrint(spice_stream_, ".end\n"); - spice_stream_.close(); - } - else - throw FileNotWritable(spice_filename_); -} - -void -WriteSpice::writeHeader() -{ - const MinMax *min_max = path_->minMax(this); - const Pvt *pvt = sdc_->operatingConditions(min_max); - if (pvt == NULL) - pvt = network_->defaultLibertyLibrary()->defaultOperatingConditions(); - float temp = pvt->temperature(); - streamPrint(spice_stream_, ".temp %.1f\n", temp); - streamPrint(spice_stream_, ".include \"%s\"\n", models_filename_); - streamPrint(spice_stream_, ".include \"%s\"\n", subckts_filename_); - - float max_time = maxTime(); - float time_step = max_time / 1e+3; - streamPrint(spice_stream_, ".tran %.3g %.3g\n\n", - time_step, max_time); -} - -float -WriteSpice::maxTime() -{ - float end_slew = path_->slew(this); - float max_time = (path_->arrival(this) + end_slew * 2) * 1.5; - return max_time; -} - -void -WriteSpice::writeStageInstances() -{ - streamPrint(spice_stream_, "*****************\n"); - streamPrint(spice_stream_, "* Stage instances\n"); - streamPrint(spice_stream_, "*****************\n\n"); - - for (Stage stage = stageFirst(); stage <= stageLast(); stage++) { - const char *stage_name = stageName(stage).c_str(); - if (stage == stageFirst()) - streamPrint(spice_stream_, "x%s %s %s %s\n", - stage_name, - stageDrvrPinName(stage), - stageLoadPinName(stage), - stage_name); - else - streamPrint(spice_stream_, "x%s %s %s %s %s\n", - stage_name, - stageInputPinName(stage), - stageDrvrPinName(stage), - stageLoadPinName(stage), - stage_name); - } - streamPrint(spice_stream_, "\n"); -} - -float -WriteSpice::pgPortVoltage(const char *pg_port_name, - LibertyCell *cell) -{ - auto pg_port = cell->findPgPort(pg_port_name); - return pgPortVoltage(pg_port); -} - -float -WriteSpice::pgPortVoltage(LibertyPgPort *pg_port) -{ - auto cell = pg_port->cell(); - auto voltage_name = pg_port->voltageName(); - auto lib = cell->libertyLibrary(); - float voltage = lib->supplyVoltage(voltage_name); - return voltage; -} - -void -WriteSpice::writeInputSource() -{ - streamPrint(spice_stream_, "**************\n"); - streamPrint(spice_stream_, "* Input source\n"); - streamPrint(spice_stream_, "**************\n\n"); - - Stage input_stage = stageFirst(); - streamPrint(spice_stream_, "v1 %s 0 pwl(\n", - stageDrvrPinName(input_stage)); - auto wire_arc = stageWireArc(input_stage); - auto load_pin = stageLoadPin(input_stage); - auto cell = network_->libertyCell(network_->instance(load_pin)); - auto load_port = network_->libertyPort(load_pin); - const char *pg_gnd_port_name = load_port->relatedGroundPin(); - const char *pg_pwr_port_name = load_port->relatedPowerPin(); - auto gnd_volt = pgPortVoltage(pg_gnd_port_name, cell); - auto pwr_volt = pgPortVoltage(pg_pwr_port_name, cell); - float volt0, volt1; - if (wire_arc->fromTrans()->asRiseFall() == TransRiseFall::rise()) { - volt0 = gnd_volt; - volt1 = pwr_volt; - } - else { - volt0 = pwr_volt; - volt1 = gnd_volt; - } - float time0 = .1e-9; - float time1 = .2e-9; - streamPrint(spice_stream_, "+%.3e %.3e\n", 0.0, volt0); - streamPrint(spice_stream_, "+%.3e %.3e\n", time0, volt0); - streamPrint(spice_stream_, "+%.3e %.3e\n", time1, volt1); - streamPrint(spice_stream_, "+%.3e %.3e\n", maxTime(), volt1); - streamPrint(spice_stream_, "+)\n\n"); -} - -void -WriteSpice::writeMeasureStmts() -{ - streamPrint(spice_stream_, "********************\n"); - streamPrint(spice_stream_, "* Measure statements\n"); - streamPrint(spice_stream_, "********************\n\n"); -} - -void -WriteSpice::writeStageSubckts() -{ - streamPrint(spice_stream_, "***************\n"); - streamPrint(spice_stream_, "* Stage subckts\n"); - streamPrint(spice_stream_, "***************\n\n"); - - for (Stage stage = stageFirst(); stage <= stageLast(); stage++) { - if (stage == stageFirst()) - writeInputStage(stage); - else - writeGateStage(stage); - } -} - -// Input port to first gate input. -void -WriteSpice::writeInputStage(Stage stage) -{ - // Input arc. - // External driver not handled. - auto drvr_pin_name = stageDrvrPinName(stage); - auto load_pin_name = stageLoadPinName(stage); - streamPrint(spice_stream_, ".subckt %s %s %s\n", - stageName(stage).c_str(), - drvr_pin_name, - load_pin_name); - writeStageParasitics(stage); - streamPrint(spice_stream_, ".ends\n\n"); -} - -// Gate and load parasitics. -void -WriteSpice::writeGateStage(Stage stage) -{ - auto input_pin = stageInputPin(stage); - auto input_pin_name = stageInputPinName(stage); - auto drvr_pin = stageDrvrPin(stage); - auto drvr_pin_name = stageDrvrPinName(stage); - auto load_pin_name = stageLoadPinName(stage); - streamPrint(spice_stream_, ".subckt stage%d %s %s %s\n", - stage, - input_pin_name, - drvr_pin_name, - load_pin_name); - Instance *inst = network_->instance(input_pin); - const char *inst_name = network_->pathName(inst); - LibertyCell *cell = network_->libertyCell(inst); - const char *cell_name = cell->name(); - auto spice_port_names = cell_spice_port_names_[cell_name]; - - // Instance subckt call. - streamPrint(spice_stream_, "x%s", inst_name); - StringVector::Iterator port_iter(spice_port_names); - while (port_iter.hasNext()) { - const char *subckt_port_name = port_iter.next().c_str(); - auto pin = network_->findPin(inst, subckt_port_name); - auto pg_port = cell->findPgPort(subckt_port_name); - const char *pin_name; - if (pin) { - pin_name = network_->pathName(pin); - streamPrint(spice_stream_, " %s", pin_name); - } - else if (pg_port) - streamPrint(spice_stream_, " %s/%s", inst_name, subckt_port_name); - } - streamPrint(spice_stream_, " %s\n", cell_name); - - writeStageVoltageSources(cell, spice_port_names, - inst_name, - network_->libertyPort(input_pin), - network_->libertyPort(drvr_pin)); - writeStageParasitics(stage); - streamPrint(spice_stream_, ".ends\n\n"); -} - -typedef Map LibertyPortLogicValues; - -// Find the logic values for expression inputs to enable paths from_port. -void -sensitizationValues(FuncExpr *expr, - LibertyPort *from_port, - // Return values. - LibertyPortLogicValues &port_values) -{ - switch (expr->op()) { - case FuncExpr::op_port: { - break; - } - case FuncExpr::op_not: { - sensitizationValues(expr->left(), from_port, port_values); - break; - } - case FuncExpr::op_or: { - FuncExpr *left = expr->left(); - FuncExpr *right = expr->right(); - if (left->port() == from_port - && right->op() == FuncExpr::op_port) - port_values[right->port()] = logic_zero; - else if (right->port() == from_port - && left->op() == FuncExpr::op_port) - port_values[left->port()] = logic_zero; - break; - } - case FuncExpr::op_and: { - FuncExpr *left = expr->left(); - FuncExpr *right = expr->right(); - if (left->port() == from_port - && right->op() == FuncExpr::op_port) - port_values[right->port()] = logic_one; - else if (right->port() == from_port - && left->op() == FuncExpr::op_port) - port_values[left->port()] = logic_one; - break; - } - case FuncExpr::op_xor: { - // Need to know timing arc sense to get this right. - FuncExpr *left = expr->left(); - FuncExpr *right = expr->right(); - if (left->port() == from_port - && right->op() == FuncExpr::op_port) - port_values[right->port()] = logic_zero; - else if (right->port() == from_port - && left->op() == FuncExpr::op_port) - port_values[left->port()] = logic_zero; - break; - } - case FuncExpr::op_one: - case FuncExpr::op_zero: - break; - } -} - -// Power/ground and input voltage sources. -void -WriteSpice::writeStageVoltageSources(LibertyCell *cell, - StringVector *spice_port_names, - const char *inst_name, - LibertyPort *from_port, - LibertyPort *drvr_port) -{ - auto from_port_name = from_port->name(); - auto drvr_port_name = drvr_port->name(); - LibertyLibrary *lib = cell->libertyLibrary(); - LibertyPortLogicValues port_values; - sensitizationValues(drvr_port->function(), from_port, port_values); - int volt_source = 1; - debugPrint1(debug_, "write_spice", 2, "subckt %s\n", cell->name()); - StringVector::Iterator port_iter(spice_port_names); - while (port_iter.hasNext()) { - auto subckt_port_name = port_iter.next().c_str(); - auto pg_port = cell->findPgPort(subckt_port_name); - debugPrint2(debug_, "write_spice", 2, " port %s%s\n", - subckt_port_name, - pg_port ? " pwr/gnd" : ""); - if (pg_port) { - auto voltage = pgPortVoltage(pg_port); - streamPrint(spice_stream_, "v%d %s/%s 0 %.3f\n", - volt_source, - inst_name, subckt_port_name, - voltage); - volt_source++; - } else if (!(stringEq(subckt_port_name, from_port_name) - || stringEq(subckt_port_name, drvr_port_name))) { - // Input voltage to sensitize path from gate input to output. - LibertyPort *port = cell->findLibertyPort(subckt_port_name); - if (port) { - const char *pg_port_name = NULL; - bool port_has_value; - LogicValue port_value; - port_values.findKey(port, port_value, port_has_value); - if (port_has_value) { - switch (port_value) { - case logic_zero: - pg_port_name = port->relatedGroundPin(); - break; - case logic_one: - pg_port_name = port->relatedPowerPin(); - break; - default: - break; - } - if (pg_port_name) { - auto pg_port = cell->findPgPort(pg_port_name); - if (pg_port) { - auto voltage_name = pg_port->voltageName(); - if (voltage_name) { - float voltage = lib->supplyVoltage(voltage_name); - streamPrint(spice_stream_, "v%d %s/%s 0 %.3f\n", - volt_source, - inst_name, subckt_port_name, - voltage); - volt_source++; - } - else - report_->error("port %s %s voltage %s not found,\n", - subckt_port_name, - pg_port_name, - voltage_name); - } - else - report_->error("port %s %s not found,\n", - subckt_port_name, - pg_port_name); - } - } - } - } - } -} - -typedef Set ParasiticDeviceSet; -typedef Set ParasiticNodeSet; - -void -findParasiticDevicesNodes(ParasiticNode *node, - Parasitics *parasitics, - // Return values. - ParasiticNodeSet &nodes, - ParasiticDeviceSet &devices) -{ - nodes.insert(node); - auto device_iter = parasitics->deviceIterator(node); - while (device_iter->hasNext()) { - auto device = device_iter->next(); - if (!devices.hasKey(device)) { - devices.insert(device); - auto other_node = parasitics->otherNode(device, node); - findParasiticDevicesNodes(other_node, parasitics, nodes, devices); - } - } - delete device_iter; -} - -void -WriteSpice::writeStageParasitics(Stage stage) -{ - auto drvr_path = stageDrvrPath(stage); - auto drvr_pin = stageDrvrPin(stage); - auto load_pin = stageLoadPin(stage); - auto dcalc_ap = drvr_path->dcalcAnalysisPt(this); - auto parasitic_ap = dcalc_ap->parasiticAnalysisPt(); - auto parasitic = parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap); - int resistor_index = 1; - int cap_index = 1; - if (parasitic) { - Net *net = network_->net(drvr_pin); - auto net_name = - net ? network_->pathName(net) : network_->pathName(drvr_pin); - initNodeMap(net_name); - streamPrint(spice_stream_, "* Net %s\n", net_name); - auto node = parasitics_->findNode(parasitic, drvr_pin); - ParasiticNodeSet nodes; - ParasiticDeviceSet devices; - findParasiticDevicesNodes(node, parasitics_, nodes, devices); - ParasiticDeviceSet::Iterator device_iter(devices); - while (device_iter.hasNext()) { - auto device = device_iter.next(); - auto resistance = parasitics_->value(device, parasitic_ap); - if (parasitics_->isResistor(device)) { - ParasiticNode *node1, *node2; - parasitics_->resistorNodes(device, node1, node2); - streamPrint(spice_stream_, "R%d %s %s %.3e\n", - resistor_index, - nodeName(node1), - nodeName(node2), - resistance); - resistor_index++; - } - else if (parasitics_->isCouplingCap(device)) { - } - } - ParasiticNodeSet::Iterator node_iter(nodes); - while (node_iter.hasNext()) { - auto node = node_iter.next(); - auto cap = parasitics_->nodeGndCap(node, parasitic_ap); - streamPrint(spice_stream_, "C%d %s 0 %.3e\n", - cap_index, - nodeName(node), - cap); - cap_index++; - } - } - else - streamPrint(spice_stream_, "R1 %s %s %.3e\n", - network_->pathName(drvr_pin), - network_->pathName(load_pin), - short_ckt_resistance_); -} - -void -WriteSpice::initNodeMap(const char *net_name) -{ - stringDelete(net_name_); - node_map_.clear(); - next_node_index_ = 1; - net_name_ = stringCopy(net_name); -} - -const char * -WriteSpice::nodeName(ParasiticNode *node) -{ - auto pin = parasitics_->connectionPin(node); - if (pin) - return parasitics_->name(node); - else { - int node_index; - bool node_index_exists; - node_map_.findKey(node, node_index, node_index_exists); - if (!node_index_exists) { - node_index = next_node_index_++; - node_map_[node] = node_index; - } - return stringPrintTmp(strlen(net_name_) + 10, "%s/%d", - net_name_, node_index); - } -} - -//////////////////////////////////////////////////////////////// - -// Copy the subckt definition from lib_subckts_filename for -// each cell in path to path_subckts_filename. -void -WriteSpice::writeSubckts() -{ - StringSet path_cell_names; - findPathCellnames(path_cell_names); - - ifstream lib_subckts_stream(lib_subckts_filename_); - if (lib_subckts_stream.is_open()) { - ofstream subckts_stream(subckts_filename_); - if (subckts_stream.is_open()) { - string line; - while (getline(lib_subckts_stream, line)) { - // .subckt [args..] - StringVector tokens; - split(line, " \t", tokens); - if (tokens.size() >= 2 - && stringEqual(tokens[0].c_str(), ".subckt")) { - const char *cell_name = tokens[1].c_str(); - if (path_cell_names.hasKey(cell_name)) { - subckts_stream << line << "\n"; - bool found_ends = false; - while (getline(lib_subckts_stream, line)) { - subckts_stream << line << "\n"; - if (stringEqual(line.c_str(), ".ends")) { - subckts_stream << "\n"; - found_ends = true; - break; - } - } - if (!found_ends) - throw SubcktEndsMissing(cell_name, lib_subckts_filename_); - path_cell_names.eraseKey(cell_name); - } - recordSpicePortNames(cell_name, tokens); - } - } - subckts_stream.close(); - lib_subckts_stream.close(); - - if (!path_cell_names.empty()) { - StringSet::Iterator cell_iter(path_cell_names); - report_->error("The following subkcts are missing from %s\n", - lib_subckts_filename_); - while (cell_iter.hasNext()) { - const char *cell_name = cell_iter.next(); - report_->printError(" %s\n", cell_name); - } - } - } - else { - lib_subckts_stream.close(); - throw FileNotWritable(subckts_filename_); - } - } - else - throw FileNotReadable(lib_subckts_filename_); -} - -void -WriteSpice::findPathCellnames(// Return values. - StringSet &path_cell_names) -{ - for (Stage stage = stageFirst(); stage <= stageLast(); stage++) { - auto arc = stageGateArc(stage); - if (arc) { - LibertyCell *cell = arc->set()->libertyCell(); - if (cell) { - debugPrint1(debug_, "write_spice", 2, "cell %s\n", cell->name()); - path_cell_names.insert(cell->name()); - } - } - } -} - -void -WriteSpice::recordSpicePortNames(const char *cell_name, - StringVector &tokens) -{ - auto cell = network_->findLibertyCell(cell_name); - auto spice_port_names = new StringVector; - for (int i = 2; i < tokens.size(); i++) { - const char *port_name = tokens[i].c_str(); - auto port = cell->findLibertyPort(port_name); - auto pg_port = cell->findPgPort(port_name); - if (port == NULL && pg_port == NULL) - report_->error("subckt %s port %s has no corresponding liberty port or pg_port.\n", - cell_name, port_name); - spice_port_names->push_back(port_name); - } - cell_spice_port_names_[cell_name] = spice_port_names; -} - -//////////////////////////////////////////////////////////////// - -Stage -WriteSpice::stageFirst() -{ - return 1; -} - -Stage -WriteSpice::stageLast() -{ - return (path_expanded_.size() + 1) / 2; -} - -string -WriteSpice::stageName(Stage stage) -{ - string name; - stringPrint(name, "stage%d", stage); - return name; -} - -int -WriteSpice::stageGateInputPathIndex(Stage stage) -{ - return stage * 2 - 3; -} - -int -WriteSpice::stageDrvrPathIndex(Stage stage) -{ - return stage * 2 - 2; -} - -int -WriteSpice::stageLoadPathIndex(Stage stage) -{ - return stage * 2 - 1; -} - -PathRef * -WriteSpice::stageGateInputPath(Stage stage) -{ - int path_index = stageGateInputPathIndex(stage); - return path_expanded_.path(path_index); -} - -PathRef * -WriteSpice::stageDrvrPath(Stage stage) -{ - int path_index = stageDrvrPathIndex(stage); - return path_expanded_.path(path_index); -} - -PathRef * -WriteSpice::stageLoadPath(Stage stage) -{ - int path_index = stageLoadPathIndex(stage); - return path_expanded_.path(path_index); -} - -TimingArc * -WriteSpice::stageGateArc(Stage stage) -{ - int path_index = stageDrvrPathIndex(stage); - if (path_index >= 0) - return path_expanded_.prevArc(path_index); - else - return NULL; -} - -TimingArc * -WriteSpice::stageWireArc(Stage stage) -{ - int path_index = stageLoadPathIndex(stage); - return path_expanded_.prevArc(path_index); -} - -Edge * -WriteSpice::stageGateEdge(Stage stage) -{ - PathRef *path = stageGateInputPath(stage); - TimingArc *arc = stageGateArc(stage); - return path->prevEdge(arc, this); -} - -Edge * -WriteSpice::stageWireEdge(Stage stage) -{ - PathRef *path = stageLoadPath(stage); - TimingArc *arc = stageWireArc(stage); - return path->prevEdge(arc, this); -} - -Pin * -WriteSpice::stageInputPin(Stage stage) -{ - PathRef *path = stageGateInputPath(stage); - return path->pin(this); -} - -Pin * -WriteSpice::stageDrvrPin(Stage stage) -{ - PathRef *path = stageDrvrPath(stage); - return path->pin(this); -} - -Pin * -WriteSpice::stageLoadPin(Stage stage) -{ - PathRef *path = stageLoadPath(stage); - return path->pin(this); -} - -const char * -WriteSpice::stageInputPinName(Stage stage) -{ - const Pin *pin = stageInputPin(stage); - return network_->pathName(pin); -} - -const char * -WriteSpice::stageDrvrPinName(Stage stage) -{ - Pin *pin = stageDrvrPin(stage); - return network_->pathName(pin); -} - -const char * -WriteSpice::stageLoadPinName(Stage stage) -{ - const Pin *pin = stageLoadPin(stage); - return network_->pathName(pin); -} - -//////////////////////////////////////////////////////////////// - -void -split(const string &text, - const string &delims, - // Return values. - StringVector &tokens) -{ - auto start = text.find_first_not_of(delims); - auto end = text.find_first_of(delims, start); - while (end != string::npos) { - tokens.push_back(text.substr(start, end - start)); - start = text.find_first_not_of(delims, end); - end = text.find_first_of(delims, start); - } - if (start != string::npos) - tokens.push_back(text.substr(start)); -} - -// fprintf for c++ streams. -// Yes, I hate formatted output to ostream THAT much. -void -streamPrint(ofstream &stream, - const char *fmt, - ...) -{ - va_list args; - va_start(args, fmt); - char *result; - vasprintf(&result, fmt, args); - stream << result; - free(result); - va_end(args); -} - -} // namespace diff --git a/search/WriteSpice.hh b/search/WriteSpice.hh deleted file mode 100644 index c6d7465c..00000000 --- a/search/WriteSpice.hh +++ /dev/null @@ -1,36 +0,0 @@ -// OpenSTA, Static Timing Analyzer -// Copyright (c) 2023, Parallax Software, Inc. -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -#pragma once - -namespace sta { - -// Write a spice deck for path. -// Throws FileNotReadable, FileNotWritable, SubcktEndsMissing -void -writeSpice(Path *path, - // Spice file written for path. - const char *spice_filename, - // Subckts used by path included in spice file. - const char *subckts_filename, - // File of all cell spice subckt definitions. - const char *lib_subckts_filename, - // Device model file included in spice file. - const char *models_filename, - StaState *sta); - -} // namespace -#endif