Files
OpenSTA/spice/WritePathSpice.cc
T

758 lines
22 KiB
C++
Raw Normal View History

2019-01-03 16:14:15 -08:00
// OpenSTA, Static Timing Analyzer
2026-03-10 13:21:17 -07:00
// Copyright (c) 2026, Parallax Software, Inc.
2019-01-03 16:14:15 -08:00
//
// 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
2022-01-04 10:17:08 -07:00
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2019-01-03 16:14:15 -08:00
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
2022-01-04 10:17:08 -07:00
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2025-01-21 18:54:33 -07:00
//
// The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software.
//
// Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// This notice may not be removed or altered from any source distribution.
2019-01-03 16:14:15 -08:00
2020-04-05 14:53:44 -07:00
#include "WritePathSpice.hh"
2020-04-05 11:35:51 -07:00
2026-04-15 09:38:10 -07:00
#include <algorithm>
2019-01-03 16:14:15 -08:00
#include <fstream>
2026-03-02 12:13:13 -08:00
#include <string>
2026-03-28 19:13:35 -07:00
#include <string_view>
2020-04-05 11:35:51 -07:00
2020-04-05 14:53:44 -07:00
#include "Debug.hh"
#include "Error.hh"
2026-03-15 14:35:24 -07:00
#include "Format.hh"
2020-04-05 14:53:44 -07:00
#include "FuncExpr.hh"
2026-04-15 09:38:10 -07:00
#include "Graph.hh"
2020-04-05 14:53:44 -07:00
#include "Liberty.hh"
#include "Network.hh"
#include "Parasitics.hh"
#include "Path.hh"
#include "PathExpanded.hh"
2026-04-15 09:38:10 -07:00
#include "PortDirection.hh"
#include "Report.hh"
#include "Sdc.hh"
#include "Sequential.hh"
2020-04-05 14:53:44 -07:00
#include "StaState.hh"
2026-04-15 09:38:10 -07:00
#include "StringUtil.hh"
#include "TableModel.hh"
#include "TimingArc.hh"
#include "Units.hh"
2024-02-27 10:00:48 -07:00
#include "WriteSpice.hh"
2026-04-15 09:38:10 -07:00
#include "search/Sim.hh"
2019-01-03 16:14:15 -08:00
namespace sta {
2026-04-15 09:38:10 -07:00
using Stage = int;
2019-01-03 16:14:15 -08:00
////////////////////////////////////////////////////////////////
2024-02-27 10:00:48 -07:00
class WritePathSpice : public WriteSpice
2019-01-03 16:14:15 -08:00
{
public:
2026-03-08 13:50:22 -07:00
WritePathSpice(const Path *path,
2026-03-28 19:13:35 -07:00
std::string_view spice_filename,
std::string_view subckt_filename,
std::string_view lib_subckt_filename,
std::string_view model_filename,
std::string_view power_name,
std::string_view gnd_name,
2024-02-27 10:00:48 -07:00
CircuitSim ckt_sim,
2026-01-03 16:59:35 -08:00
const StaState *sta);
2019-08-08 14:13:02 -07:00
void writeSpice();
2019-01-03 16:14:15 -08:00
private:
void writeHeader();
2024-02-27 10:00:48 -07:00
void writePrintStmt();
2019-01-03 16:14:15 -08:00
void writeStageInstances();
void writeInputSource();
void writeStageSubckts();
void writeInputStage(Stage stage);
void writeMeasureStmts();
void writeMeasureStmt(const Pin *pin);
void writeGateStage(Stage stage);
void writeStageParasitics(Stage stage);
void writeSubckts();
2026-03-08 15:55:12 -07:00
StringSet findPathCellNames();
void findPathCellSubckts(StringSet &path_cell_names);
2019-01-03 16:14:15 -08:00
float maxTime();
2023-04-19 16:44:52 -07:00
float pathMaxTime();
2019-01-03 16:14:15 -08:00
void writeMeasureDelayStmt(Stage stage,
2026-01-03 16:59:35 -08:00
const Path *from_path,
const Path *to_path);
2019-01-03 16:14:15 -08:00
void writeMeasureSlewStmt(Stage stage,
2026-01-03 16:59:35 -08:00
const Path *path);
2019-01-22 20:41:32 -08:00
void writeInputWaveform();
void writeClkWaveform();
2019-01-03 16:14:15 -08:00
// Stage "accessors".
2019-01-20 09:44:24 -08:00
//
// stage
// |---------------|
2019-03-03 17:50:56 -08:00
// |\ |\ .
2019-01-20 09:44:24 -08:00
// -------| >---/\/\/----| >---
// gate |/ drvr load|/
// input
//
// A path from an input port has no GateInputPath (the input port is the drvr).
2019-01-03 16:14:15 -08:00
// Internally a stage index from stageFirst() to stageLast()
// is turned into an index into path_expanded_.
2019-01-20 09:44:24 -08:00
//
2019-01-03 16:14:15 -08:00
Stage stageFirst();
Stage stageLast();
2026-03-02 12:13:13 -08:00
std::string stageName(Stage stage);
2019-01-03 16:14:15 -08:00
int stageGateInputPathIndex(Stage stage);
int stageDrvrPathIndex(Stage stage);
int stageLoadPathIndex(Stage stage);
2025-03-26 18:21:03 -07:00
const Path *stageGateInputPath(Stage stage);
const Path *stageDrvrPath(Stage stage);
const Path *stageLoadPath(Stage stage);
const TimingArc *stageGateArc(Stage stage);
const TimingArc *stageWireArc(Stage stage);
2026-03-08 13:50:22 -07:00
const Edge *stageGateEdge(Stage stage);
const Edge *stageWireEdge(Stage stage);
const Pin *stageGateInputPin(Stage stage);
const Pin *stageDrvrPin(Stage stage);
const LibertyPort *stageGateInputPort(Stage stage);
const LibertyPort *stageDrvrPort(Stage stage);
const Pin *stageLoadPin(Stage stage);
2026-03-28 19:13:35 -07:00
std::string stageGateInputPinName(Stage stage);
std::string stageDrvrPinName(Stage stage);
std::string stageLoadPinName(Stage stage);
2026-03-08 13:50:22 -07:00
const LibertyCell *stageLibertyCell(Stage stage);
const Instance *stageInstance(Stage stage);
2019-01-03 16:14:15 -08:00
2024-09-16 17:04:31 -07:00
float findSlew(const Path *path);
float findSlew(const Path *path,
2026-01-03 16:59:35 -08:00
const RiseFall *rf,
const TimingArc *next_arc);
2026-03-08 13:50:22 -07:00
const Path *path_;
2019-01-03 16:14:15 -08:00
PathExpanded path_expanded_;
2019-01-22 20:41:32 -08:00
// Input clock waveform cycles.
2026-04-15 09:38:10 -07:00
int clk_cycle_count_{3};
2019-01-03 16:14:15 -08:00
2024-06-27 13:57:58 -07:00
InstanceSet written_insts_;
2024-02-27 10:00:48 -07:00
using WriteSpice::writeHeader;
using WriteSpice::writePrintStmt;
using WriteSpice::writeSubckts;
using WriteSpice::writeVoltageSource;
using WriteSpice::writeMeasureDelayStmt;
using WriteSpice::writeMeasureSlewStmt;
using WriteSpice::findSlew;
2019-01-03 16:14:15 -08:00
};
////////////////////////////////////////////////////////////////
void
2026-03-08 13:50:22 -07:00
writePathSpice(const Path *path,
2026-03-28 19:13:35 -07:00
std::string_view spice_filename,
std::string_view subckt_filename,
std::string_view lib_subckt_filename,
std::string_view model_filename,
std::string_view power_name,
std::string_view gnd_name,
2024-02-27 10:00:48 -07:00
CircuitSim ckt_sim,
2026-01-03 16:59:35 -08:00
StaState *sta)
2019-01-03 16:14:15 -08:00
{
WritePathSpice writer(path, spice_filename, subckt_filename,
2024-02-27 10:00:48 -07:00
lib_subckt_filename, model_filename,
power_name, gnd_name, ckt_sim, sta);
2019-01-03 16:14:15 -08:00
writer.writeSpice();
}
2026-03-08 13:50:22 -07:00
WritePathSpice::WritePathSpice(const Path *path,
2026-03-28 19:13:35 -07:00
std::string_view spice_filename,
std::string_view subckt_filename,
std::string_view lib_subckt_filename,
std::string_view model_filename,
std::string_view power_name,
std::string_view gnd_name,
2024-02-27 10:00:48 -07:00
CircuitSim ckt_sim,
2026-01-03 16:59:35 -08:00
const StaState *sta) :
2024-02-27 10:00:48 -07:00
WriteSpice(spice_filename, subckt_filename, lib_subckt_filename,
2024-06-27 13:57:58 -07:00
model_filename, power_name, gnd_name, ckt_sim,
2026-01-03 16:59:35 -08:00
path->scene(sta), path->minMax(sta), sta),
2019-01-03 16:14:15 -08:00
path_(path),
path_expanded_(sta),
2024-06-27 13:57:58 -07:00
written_insts_(network_)
2019-01-03 16:14:15 -08:00
{
2024-06-27 13:57:58 -07:00
initPowerGnd();
2019-01-03 16:14:15 -08:00
}
void
WritePathSpice::writeSpice()
{
2026-04-23 09:56:45 -07:00
spice_stream_.open(spice_filename_);
2019-01-03 16:14:15 -08:00
if (spice_stream_.is_open()) {
path_expanded_.expand(path_, true);
// Find subckt port names as a side-effect of writeSubckts.
writeSubckts();
writeHeader();
2023-03-22 09:57:54 -07:00
writePrintStmt();
2024-02-27 10:00:48 -07:00
if (ckt_sim_ == CircuitSim::hspice)
2024-01-12 18:50:19 -08:00
writeMeasureStmts();
2019-01-03 16:14:15 -08:00
writeInputSource();
2024-02-27 10:00:48 -07:00
writeStageInstances();
2019-01-03 16:14:15 -08:00
writeStageSubckts();
2026-03-15 14:35:24 -07:00
sta::print(spice_stream_, ".end\n");
2019-01-03 16:14:15 -08:00
spice_stream_.close();
}
else
throw FileNotWritable(spice_filename_);
}
void
WritePathSpice::writeHeader()
{
2025-02-01 14:53:28 -08:00
const Path *start_path = path_expanded_.startPath();
2026-03-15 14:35:24 -07:00
std::string title = sta::format("Path from {} {} to {} {}",
network_->pathName(start_path->pin(this)),
start_path->transition(this)->shortName(),
network_->pathName(path_->pin(this)),
path_->transition(this)->shortName());
2019-11-11 15:53:29 -07:00
float max_time = maxTime();
2023-05-05 10:21:12 -07:00
float time_step = 1e-13;
2024-02-27 10:00:48 -07:00
writeHeader(title, max_time, time_step);
2023-03-22 09:57:54 -07:00
}
void
WritePathSpice::writePrintStmt()
{
2026-03-08 15:51:50 -07:00
StringSeq node_names;
2023-03-22 09:57:54 -07:00
for (Stage stage = stageFirst(); stage <= stageLast(); stage++) {
2024-02-27 10:00:48 -07:00
node_names.push_back(stageDrvrPinName(stage));
node_names.push_back(stageLoadPinName(stage));
2023-03-22 09:57:54 -07:00
}
2024-02-27 10:00:48 -07:00
writePrintStmt(node_names);
2019-01-03 16:14:15 -08:00
}
float
WritePathSpice::maxTime()
{
2019-11-11 15:53:29 -07:00
Stage input_stage = stageFirst();
2025-03-26 18:21:03 -07:00
const Path *input_path = stageDrvrPath(input_stage);
2019-01-22 20:41:32 -08:00
if (input_path->isClock(this)) {
2023-01-19 11:23:45 -07:00
const Clock *clk = input_path->clock(this);
2019-11-11 15:53:29 -07:00
float period = clk->period();
2019-01-22 20:41:32 -08:00
float first_edge_offset = period / 10;
2019-11-11 15:53:29 -07:00
float max_time = period * clk_cycle_count_ + first_edge_offset;
2019-01-22 20:41:32 -08:00
return max_time;
}
2023-04-19 16:44:52 -07:00
else
return pathMaxTime();
}
// Make sure run time is long enough to see side load transitions along the path.
float
WritePathSpice::pathMaxTime()
{
float max_time = 0.0;
for (size_t i = 0; i < path_expanded_.size(); i++) {
2025-03-26 18:21:03 -07:00
const Path *path = path_expanded_.path(i);
2023-04-19 16:44:52 -07:00
const RiseFall *rf = path->transition(this);
Vertex *vertex = path->vertex(this);
2024-06-27 13:57:58 -07:00
float path_max_slew = railToRailSlew(findSlew(vertex,rf,nullptr), rf);
2023-04-19 16:44:52 -07:00
if (vertex->isDriver(network_)) {
VertexOutEdgeIterator edge_iter(vertex, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
Vertex *load = edge->to(graph_);
2024-06-27 13:57:58 -07:00
float load_slew = railToRailSlew(findSlew(load, rf, nullptr), rf);
2026-04-15 09:38:10 -07:00
path_max_slew = std::max(load_slew, path_max_slew);
2023-04-19 16:44:52 -07:00
}
}
2025-03-26 18:21:03 -07:00
float path_max_time = delayAsFloat(path->arrival()) + path_max_slew * 2.0;
2026-04-15 09:38:10 -07:00
max_time = std::max(path_max_time, max_time);
2019-01-22 20:41:32 -08:00
}
2023-04-19 16:44:52 -07:00
return max_time;
2019-01-03 16:14:15 -08:00
}
void
WritePathSpice::writeStageInstances()
{
2026-03-15 14:35:24 -07:00
sta::print(spice_stream_, "*****************\n");
sta::print(spice_stream_, "* Stage instances\n");
sta::print(spice_stream_, "*****************\n\n");
2019-01-03 16:14:15 -08:00
for (Stage stage = stageFirst(); stage <= stageLast(); stage++) {
2026-03-02 12:13:13 -08:00
std::string stage_name = stageName(stage);
2019-01-03 16:14:15 -08:00
if (stage == stageFirst())
2026-03-15 14:35:24 -07:00
sta::print(spice_stream_, "x{} {} {} {}\n",
2026-03-28 19:13:35 -07:00
stage_name,
2026-03-15 14:35:24 -07:00
stageDrvrPinName(stage),
stageLoadPinName(stage),
2026-03-28 19:13:35 -07:00
stage_name);
2023-04-15 14:31:47 -07:00
else {
2026-03-15 14:35:24 -07:00
sta::print(spice_stream_, "x{} {} {} {} {}\n",
2026-03-28 19:13:35 -07:00
stage_name,
2026-03-15 14:35:24 -07:00
stageGateInputPinName(stage),
stageDrvrPinName(stage),
stageLoadPinName(stage),
2026-03-28 19:13:35 -07:00
stage_name);
2023-04-15 14:31:47 -07:00
}
2019-01-03 16:14:15 -08:00
}
2026-03-15 14:35:24 -07:00
sta::print(spice_stream_, "\n");
2019-01-03 16:14:15 -08:00
}
void
WritePathSpice::writeInputSource()
{
2026-03-15 14:35:24 -07:00
sta::print(spice_stream_, "**************\n");
sta::print(spice_stream_, "* Input source\n");
sta::print(spice_stream_, "**************\n\n");
2019-01-03 16:14:15 -08:00
2019-11-11 15:53:29 -07:00
Stage input_stage = stageFirst();
2025-03-26 18:21:03 -07:00
const Path *input_path = stageDrvrPath(input_stage);
2019-01-22 20:41:32 -08:00
if (input_path->isClock(this))
writeClkWaveform();
else
writeInputWaveform();
2026-03-15 14:35:24 -07:00
sta::print(spice_stream_, "\n");
2019-01-22 20:41:32 -08:00
}
void
WritePathSpice::writeInputWaveform()
{
2019-11-11 15:53:29 -07:00
Stage input_stage = stageFirst();
2025-03-26 18:21:03 -07:00
const Path *input_path = stageDrvrPath(input_stage);
2019-11-11 15:53:29 -07:00
const RiseFall *rf = input_path->transition(this);
2025-03-26 18:21:03 -07:00
const TimingArc *next_arc = stageGateArc(input_stage + 1);
2019-12-09 12:06:49 -07:00
float slew0 = findSlew(input_path, rf, next_arc);
2023-04-04 17:41:49 -07:00
float threshold = default_library_->inputThreshold(rf);
float dt = railToRailSlew(slew0, rf);
float time0 = dt * threshold;
2019-11-11 15:53:29 -07:00
const Pin *drvr_pin = stageDrvrPin(input_stage);
2023-03-22 09:57:54 -07:00
const Pin *load_pin = stageLoadPin(input_stage);
const LibertyPort *load_port = network_->libertyPort(load_pin);
DriverWaveform *drvr_waveform = nullptr;
if (load_port)
drvr_waveform = load_port->driverWaveform(rf);
if (drvr_waveform)
2024-02-27 10:00:48 -07:00
writeWaveformVoltSource(drvr_pin, drvr_waveform, rf, 0.0, slew0);
2023-03-22 09:57:54 -07:00
else
2024-02-27 10:00:48 -07:00
writeRampVoltSource(drvr_pin, rf, time0, slew0);
2019-01-22 20:41:32 -08:00
}
void
WritePathSpice::writeClkWaveform()
{
2019-11-11 15:53:29 -07:00
Stage input_stage = stageFirst();
2025-03-26 18:21:03 -07:00
const Path *input_path = stageDrvrPath(input_stage);
const TimingArc *next_arc = stageGateArc(input_stage + 1);
2023-01-19 11:23:45 -07:00
const ClockEdge *clk_edge = input_path->clkEdge(this);
2024-02-27 10:00:48 -07:00
2023-01-19 11:23:45 -07:00
const Clock *clk = clk_edge->clock();
2019-11-11 15:53:29 -07:00
float period = clk->period();
2024-02-27 10:00:48 -07:00
float time_offset = clkWaveformTimeOffset(clk);
2025-03-30 15:27:53 -07:00
const RiseFall *rf0, *rf1;
2019-01-22 20:41:32 -08:00
float volt0;
if (clk_edge->time() < period) {
2019-11-11 15:30:19 -07:00
rf0 = RiseFall::rise();
rf1 = RiseFall::fall();
2019-01-22 20:41:32 -08:00
volt0 = gnd_voltage_;
}
else {
2019-11-11 15:30:19 -07:00
rf0 = RiseFall::fall();
rf1 = RiseFall::rise();
2019-01-22 20:41:32 -08:00
volt0 = power_voltage_;
}
2019-12-09 12:06:49 -07:00
float slew0 = findSlew(input_path, rf0, next_arc);
float slew1 = findSlew(input_path, rf1, next_arc);
2026-03-15 14:35:24 -07:00
sta::print(spice_stream_, "v1 {} 0 pwl(\n",
stageDrvrPinName(input_stage));
sta::print(spice_stream_, "+{:.3e} {:.3e}\n", 0.0, volt0);
2019-01-22 20:41:32 -08:00
for (int cycle = 0; cycle < clk_cycle_count_; cycle++) {
2019-11-11 15:53:29 -07:00
float time0 = time_offset + cycle * period;
float time1 = time0 + period / 2.0;
2019-11-11 15:30:19 -07:00
writeWaveformEdge(rf0, time0, slew0);
writeWaveformEdge(rf1, time1, slew1);
2019-01-22 20:41:32 -08:00
}
2026-03-15 14:35:24 -07:00
sta::print(spice_stream_, "+{:.3e} {:.3e}\n", max_time_, volt0);
sta::print(spice_stream_, "+)\n");
2019-01-22 20:41:32 -08:00
}
float
2024-09-16 17:04:31 -07:00
WritePathSpice::findSlew(const Path *path)
2019-01-22 20:41:32 -08:00
{
2019-11-11 15:30:19 -07:00
Vertex *vertex = path->vertex(this);
const RiseFall *rf = path->transition(this);
2024-06-27 13:57:58 -07:00
return findSlew(vertex, rf, nullptr);
2019-01-22 20:41:32 -08:00
}
float
2024-09-16 17:04:31 -07:00
WritePathSpice::findSlew(const Path *path,
const RiseFall *rf,
2025-03-26 18:21:03 -07:00
const TimingArc *next_arc)
2019-01-22 20:41:32 -08:00
{
2019-11-11 15:30:19 -07:00
Vertex *vertex = path->vertex(this);
2024-06-27 13:57:58 -07:00
return findSlew(vertex, rf, next_arc);
2019-01-22 20:41:32 -08:00
}
////////////////////////////////////////////////////////////////
2019-01-03 16:14:15 -08:00
void
WritePathSpice::writeMeasureStmts()
{
2026-03-15 14:35:24 -07:00
sta::print(spice_stream_, "********************\n");
sta::print(spice_stream_, "* Measure statements\n");
sta::print(spice_stream_, "********************\n\n");
2019-01-03 16:14:15 -08:00
2019-11-11 15:30:19 -07:00
for (Stage stage = stageFirst(); stage <= stageLast(); stage++) {
2025-03-26 18:21:03 -07:00
const Path *gate_input_path = stageGateInputPath(stage);
const Path *drvr_path = stageDrvrPath(stage);
const Path *load_path = stageLoadPath(stage);
2019-01-20 09:44:24 -08:00
if (gate_input_path) {
// gate input -> gate output
writeMeasureSlewStmt(stage, gate_input_path);
writeMeasureDelayStmt(stage, gate_input_path, drvr_path);
}
writeMeasureSlewStmt(stage, drvr_path);
// gate output | input port -> load
writeMeasureDelayStmt(stage, drvr_path, load_path);
2019-01-03 16:14:15 -08:00
if (stage == stageLast())
2019-01-20 09:44:24 -08:00
writeMeasureSlewStmt(stage, load_path);
2019-01-03 16:14:15 -08:00
}
2026-03-15 14:35:24 -07:00
sta::print(spice_stream_, "\n");
2019-01-03 16:14:15 -08:00
}
void
WritePathSpice::writeMeasureDelayStmt(Stage stage,
2026-01-03 16:59:35 -08:00
const Path *from_path,
const Path *to_path)
2019-01-03 16:14:15 -08:00
{
2024-02-27 10:00:48 -07:00
writeMeasureDelayStmt(from_path->pin(this), from_path->transition(this),
to_path->pin(this), to_path->transition(this),
stageName(stage));
2019-01-03 16:14:15 -08:00
}
void
WritePathSpice::writeMeasureSlewStmt(Stage stage,
2026-01-03 16:59:35 -08:00
const Path *path)
2019-01-03 16:14:15 -08:00
{
2024-02-27 10:00:48 -07:00
const Pin *pin = path->pin(this);
2019-11-11 15:53:29 -07:00
const RiseFall *rf = path->transition(this);
2026-03-02 12:13:13 -08:00
std::string prefix = stageName(stage);
2024-02-27 10:00:48 -07:00
writeMeasureSlewStmt(pin, rf, prefix);
2019-01-03 16:14:15 -08:00
}
void
WritePathSpice::writeStageSubckts()
{
2026-03-15 14:35:24 -07:00
sta::print(spice_stream_, "***************\n");
sta::print(spice_stream_, "* Stage subckts\n");
sta::print(spice_stream_, "***************\n\n");
2019-01-03 16:14:15 -08:00
2019-11-11 15:30:19 -07:00
for (Stage stage = stageFirst(); stage <= stageLast(); stage++) {
2024-02-27 10:00:48 -07:00
cap_index_ = 1;
res_index_ = 1;
volt_index_ = 1;
2019-01-03 16:14:15 -08:00
if (stage == stageFirst())
writeInputStage(stage);
else
writeGateStage(stage);
}
}
// Input port to first gate input.
void
WritePathSpice::writeInputStage(Stage stage)
{
// Input arc.
// External driver not handled.
2026-03-28 19:13:35 -07:00
std::string drvr_pin_name = stageDrvrPinName(stage);
std::string load_pin_name = stageLoadPinName(stage);
2026-03-02 12:13:13 -08:00
std::string prefix = stageName(stage);
2026-03-15 14:35:24 -07:00
sta::print(spice_stream_, ".subckt {} {} {}\n",
prefix,
drvr_pin_name,
load_pin_name);
2019-01-03 16:14:15 -08:00
writeStageParasitics(stage);
2026-03-15 14:35:24 -07:00
sta::print(spice_stream_, ".ends\n\n");
2019-01-03 16:14:15 -08:00
}
// Gate and load parasitics.
void
WritePathSpice::writeGateStage(Stage stage)
{
2019-11-11 15:53:29 -07:00
const Pin *input_pin = stageGateInputPin(stage);
2026-03-28 19:13:35 -07:00
std::string input_pin_name = stageGateInputPinName(stage);
2019-11-11 15:53:29 -07:00
const Pin *drvr_pin = stageDrvrPin(stage);
2026-03-28 19:13:35 -07:00
std::string drvr_pin_name = stageDrvrPinName(stage);
2019-11-11 15:53:29 -07:00
const Pin *load_pin = stageLoadPin(stage);
2026-03-28 19:13:35 -07:00
std::string load_pin_name = stageLoadPinName(stage);
2026-03-02 12:13:13 -08:00
std::string subckt_name = "stage" + std::to_string(stage);
2024-02-27 10:00:48 -07:00
2024-06-27 13:57:58 -07:00
const Instance *inst = stageInstance(stage);
2026-03-08 13:50:22 -07:00
const LibertyPort *input_port = stageGateInputPort(stage);
const LibertyPort *drvr_port = stageDrvrPort(stage);
2024-02-27 10:00:48 -07:00
2026-03-15 14:35:24 -07:00
sta::print(spice_stream_, ".subckt {} {} {} {}\n",
subckt_name,
input_pin_name,
drvr_pin_name,
load_pin_name);
2023-04-15 14:31:47 -07:00
// Driver subckt call.
2026-03-15 14:35:24 -07:00
sta::print(spice_stream_, "* Gate {} {} -> {}\n",
network_->pathName(inst),
input_port->name(),
drvr_port->name());
2024-06-27 13:57:58 -07:00
writeSubcktInst(inst);
2025-03-26 18:21:03 -07:00
const Path *drvr_path = stageDrvrPath(stage);
2024-02-27 10:00:48 -07:00
const RiseFall *drvr_rf = drvr_path->transition(this);
2026-03-08 13:50:22 -07:00
const Edge *gate_edge = stageGateEdge(stage);
2024-02-27 10:00:48 -07:00
LibertyPortLogicValues port_values;
bool is_clked;
gatePortValues(input_pin, drvr_pin, drvr_rf, gate_edge,
port_values, is_clked);
2019-01-20 09:44:24 -08:00
2024-06-27 13:57:58 -07:00
PinSet inputs(network_);
inputs.insert(input_pin);
writeSubcktInstVoltSrcs(inst, port_values, inputs);
2026-03-15 14:35:24 -07:00
sta::print(spice_stream_, "\n");
2019-01-22 20:41:32 -08:00
2024-06-27 13:57:58 -07:00
PinSet drvr_loads(network_);
PinConnectedPinIterator *pin_iter = network_->connectedPinIterator(drvr_pin);
while (pin_iter->hasNext()) {
const Pin *load_pin = pin_iter->next();
drvr_loads.insert(load_pin);
}
delete pin_iter;
writeSubcktInstLoads(drvr_pin, load_pin, drvr_loads, written_insts_);
2024-02-27 10:00:48 -07:00
writeStageParasitics(stage);
2026-03-15 14:35:24 -07:00
sta::print(spice_stream_, ".ends\n\n");
2019-01-22 20:41:32 -08:00
}
2019-01-03 16:14:15 -08:00
void
WritePathSpice::writeStageParasitics(Stage stage)
{
2025-03-26 18:21:03 -07:00
const Path *drvr_path = stageDrvrPath(stage);
2026-01-03 16:59:35 -08:00
const MinMax *min_max = drvr_path->minMax(this);
2024-06-27 13:57:58 -07:00
const Pin *drvr_pin = stageDrvrPin(stage);
2026-01-03 16:59:35 -08:00
const Parasitic *parasitic = parasitics_->findParasiticNetwork(drvr_pin);
2024-06-27 13:57:58 -07:00
if (parasitic == nullptr) {
const RiseFall *drvr_rf = drvr_path->transition(this);
2026-01-03 16:59:35 -08:00
parasitic = parasitics_->findPiElmore(drvr_pin, drvr_rf, min_max);
2024-06-27 13:57:58 -07:00
}
2024-02-27 10:00:48 -07:00
NetSet coupling_nets;
2024-06-27 13:57:58 -07:00
writeDrvrParasitics(drvr_pin, parasitic, coupling_nets);
2019-01-03 16:14:15 -08:00
}
////////////////////////////////////////////////////////////////
// Copy the subckt definition from lib_subckt_filename for
// each cell in path to path_subckt_filename.
void
WritePathSpice::writeSubckts()
{
2026-03-08 15:55:12 -07:00
StringSet cell_names = findPathCellNames();
2024-02-27 10:00:48 -07:00
writeSubckts(cell_names);
2019-01-03 16:14:15 -08:00
}
2026-03-08 15:55:12 -07:00
StringSet
2024-02-27 10:00:48 -07:00
WritePathSpice::findPathCellNames()
2019-01-03 16:14:15 -08:00
{
2026-03-08 15:55:12 -07:00
StringSet path_cell_names;
2019-11-11 15:30:19 -07:00
for (Stage stage = stageFirst(); stage <= stageLast(); stage++) {
2025-03-26 18:21:03 -07:00
const TimingArc *arc = stageGateArc(stage);
2019-01-03 16:14:15 -08:00
if (arc) {
2019-11-11 15:30:19 -07:00
LibertyCell *cell = arc->set()->libertyCell();
2019-01-03 16:14:15 -08:00
if (cell) {
2026-03-15 14:35:24 -07:00
debugPrint(debug_, "write_spice", 2, "cell {}", cell->name());
2026-01-03 16:59:35 -08:00
path_cell_names.insert(cell->name());
2019-01-03 16:14:15 -08:00
}
// Include side receivers.
2026-03-08 13:50:22 -07:00
const Pin *drvr_pin = stageDrvrPin(stage);
auto pin_iter = network_->connectedPinIterator(drvr_pin);
while (pin_iter->hasNext()) {
2026-01-03 16:59:35 -08:00
const Pin *pin = pin_iter->next();
LibertyPort *port = network_->libertyPort(pin);
if (port) {
LibertyCell *cell = port->libertyCell();
path_cell_names.insert(cell->name());
}
}
delete pin_iter;
2019-01-03 16:14:15 -08:00
}
}
return path_cell_names;
}
2019-01-03 16:14:15 -08:00
////////////////////////////////////////////////////////////////
Stage
WritePathSpice::stageFirst()
{
return 1;
}
Stage
WritePathSpice::stageLast()
{
return (path_expanded_.size() + 1) / 2;
}
2026-03-02 12:13:13 -08:00
std::string
2019-01-03 16:14:15 -08:00
WritePathSpice::stageName(Stage stage)
{
2026-03-15 14:35:24 -07:00
return sta::format("stage{}", stage);
2019-01-03 16:14:15 -08:00
}
int
WritePathSpice::stageGateInputPathIndex(Stage stage)
{
return stage * 2 - 3;
}
int
WritePathSpice::stageDrvrPathIndex(Stage stage)
{
return stage * 2 - 2;
}
int
WritePathSpice::stageLoadPathIndex(Stage stage)
{
return stage * 2 - 1;
}
2025-03-26 18:21:03 -07:00
const Path *
2019-01-03 16:14:15 -08:00
WritePathSpice::stageGateInputPath(Stage stage)
{
2019-11-11 15:30:19 -07:00
int path_index = stageGateInputPathIndex(stage);
2019-01-03 16:14:15 -08:00
return path_expanded_.path(path_index);
}
2025-03-26 18:21:03 -07:00
const Path *
2019-01-03 16:14:15 -08:00
WritePathSpice::stageDrvrPath(Stage stage)
{
2019-11-11 15:30:19 -07:00
int path_index = stageDrvrPathIndex(stage);
2019-01-03 16:14:15 -08:00
return path_expanded_.path(path_index);
}
2025-03-26 18:21:03 -07:00
const Path *
2019-01-03 16:14:15 -08:00
WritePathSpice::stageLoadPath(Stage stage)
{
2019-11-11 15:30:19 -07:00
int path_index = stageLoadPathIndex(stage);
2019-01-03 16:14:15 -08:00
return path_expanded_.path(path_index);
}
2025-03-26 18:21:03 -07:00
const TimingArc *
2019-01-03 16:14:15 -08:00
WritePathSpice::stageGateArc(Stage stage)
{
2019-11-11 15:30:19 -07:00
int path_index = stageDrvrPathIndex(stage);
2019-01-03 16:14:15 -08:00
if (path_index >= 0)
2025-03-26 18:21:03 -07:00
return path_expanded_.path(path_index)->prevArc(this);
2019-01-03 16:14:15 -08:00
else
2019-03-12 17:25:53 -07:00
return nullptr;
2019-01-03 16:14:15 -08:00
}
2025-03-26 18:21:03 -07:00
const TimingArc *
2019-01-03 16:14:15 -08:00
WritePathSpice::stageWireArc(Stage stage)
{
2019-11-11 15:30:19 -07:00
int path_index = stageLoadPathIndex(stage);
2025-03-26 18:21:03 -07:00
return path_expanded_.path(path_index)->prevArc(this);
2019-01-03 16:14:15 -08:00
}
2026-03-08 13:50:22 -07:00
const Edge *
2019-01-03 16:14:15 -08:00
WritePathSpice::stageGateEdge(Stage stage)
{
2025-03-26 18:21:03 -07:00
const Path *path = stageDrvrPath(stage);
return path->prevEdge(this);
2019-01-03 16:14:15 -08:00
}
2026-03-08 13:50:22 -07:00
const Edge *
2019-01-03 16:14:15 -08:00
WritePathSpice::stageWireEdge(Stage stage)
{
2025-03-26 18:21:03 -07:00
const Path *path = stageLoadPath(stage);
return path->prevEdge(this);
2019-01-03 16:14:15 -08:00
}
2026-03-08 13:50:22 -07:00
const Pin *
2019-01-22 20:41:32 -08:00
WritePathSpice::stageGateInputPin(Stage stage)
2019-01-03 16:14:15 -08:00
{
2025-03-26 18:21:03 -07:00
const Path *path = stageGateInputPath(stage);
2019-01-03 16:14:15 -08:00
return path->pin(this);
}
2026-03-08 13:50:22 -07:00
const LibertyPort *
WritePathSpice::stageGateInputPort(Stage stage)
{
2026-03-08 13:50:22 -07:00
const Pin *pin = stageGateInputPin(stage);
return network_->libertyPort(pin);
}
2026-03-08 13:50:22 -07:00
const Pin *
2019-01-03 16:14:15 -08:00
WritePathSpice::stageDrvrPin(Stage stage)
{
2025-03-26 18:21:03 -07:00
const Path *path = stageDrvrPath(stage);
2019-01-03 16:14:15 -08:00
return path->pin(this);
}
2026-03-08 13:50:22 -07:00
const LibertyPort *
WritePathSpice::stageDrvrPort(Stage stage)
{
2026-03-08 13:50:22 -07:00
const Pin *pin = stageDrvrPin(stage);
return network_->libertyPort(pin);
}
2026-03-08 13:50:22 -07:00
const Pin *
2019-01-03 16:14:15 -08:00
WritePathSpice::stageLoadPin(Stage stage)
{
2025-03-26 18:21:03 -07:00
const Path *path = stageLoadPath(stage);
2019-01-03 16:14:15 -08:00
return path->pin(this);
}
2026-03-28 19:13:35 -07:00
std::string
2019-01-03 16:14:15 -08:00
WritePathSpice::stageGateInputPinName(Stage stage)
{
2026-03-08 13:50:22 -07:00
const Pin *pin = stageGateInputPin(stage);
2019-01-03 16:14:15 -08:00
return network_->pathName(pin);
}
2026-03-28 19:13:35 -07:00
std::string
2019-01-03 16:14:15 -08:00
WritePathSpice::stageDrvrPinName(Stage stage)
{
2026-03-08 13:50:22 -07:00
const Pin *pin = stageDrvrPin(stage);
2019-01-03 16:14:15 -08:00
return network_->pathName(pin);
}
2026-03-28 19:13:35 -07:00
std::string
2019-01-03 16:14:15 -08:00
WritePathSpice::stageLoadPinName(Stage stage)
{
2026-03-08 13:50:22 -07:00
const Pin *pin = stageLoadPin(stage);
2019-01-03 16:14:15 -08:00
return network_->pathName(pin);
}
2026-03-08 13:50:22 -07:00
const Instance *
WritePathSpice::stageInstance(Stage stage)
{
2026-03-08 13:50:22 -07:00
const Pin *pin = stageDrvrPin(stage);
return network_->instance(pin);
}
2026-03-08 13:50:22 -07:00
const LibertyCell *
WritePathSpice::stageLibertyCell(Stage stage)
{
2026-03-08 13:50:22 -07:00
const Pin *pin = stageDrvrPin(stage);
return network_->libertyPort(pin)->libertyCell();
}
2026-04-13 14:58:16 -07:00
} // namespace sta