2019/02/21 write_path_spice include side load pins
This commit is contained in:
parent
83c8dc3358
commit
1af0963fd4
|
|
@ -68,6 +68,8 @@ Makefile
|
||||||
# /test/
|
# /test/
|
||||||
/test/gmon.out
|
/test/gmon.out
|
||||||
/test/results
|
/test/results
|
||||||
|
# ngspice turd
|
||||||
|
/test/b3v3_1check.log
|
||||||
|
|
||||||
/test_native
|
/test_native
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,3 +16,4 @@ Release 2.0 Patches
|
||||||
2019/01/31 generated clk -divide_by 16384 cycle accting fallout
|
2019/01/31 generated clk -divide_by 16384 cycle accting fallout
|
||||||
2019/02/17 report_power internal power accuracy
|
2019/02/17 report_power internal power accuracy
|
||||||
2019/02/18 write_path_spice first line is comment
|
2019/02/18 write_path_spice first line is comment
|
||||||
|
2019/02/21 write_path_spice include side load pins
|
||||||
|
|
|
||||||
BIN
doc/OpenSTA.odt
BIN
doc/OpenSTA.odt
Binary file not shown.
|
|
@ -29,6 +29,7 @@
|
||||||
#include "TableModel.hh"
|
#include "TableModel.hh"
|
||||||
#include "Liberty.hh"
|
#include "Liberty.hh"
|
||||||
#include "TimingArc.hh"
|
#include "TimingArc.hh"
|
||||||
|
#include "PortDirection.hh"
|
||||||
#include "Network.hh"
|
#include "Network.hh"
|
||||||
#include "Graph.hh"
|
#include "Graph.hh"
|
||||||
#include "Sdc.hh"
|
#include "Sdc.hh"
|
||||||
|
|
@ -95,8 +96,13 @@ private:
|
||||||
void writeMeasureStmts();
|
void writeMeasureStmts();
|
||||||
void writeMeasureStmt(const Pin *pin);
|
void writeMeasureStmt(const Pin *pin);
|
||||||
void writeGateStage(Stage stage);
|
void writeGateStage(Stage stage);
|
||||||
void writeStageVoltageSources(Stage stage,
|
void writeSubcktInst(const Pin *input_pin);
|
||||||
StringVector *spice_port_names);
|
void writeSubcktInstVoltSrcs(Stage stage,
|
||||||
|
const Pin *input_pin,
|
||||||
|
int &volt_index,
|
||||||
|
LibertyPortLogicValues &port_values,
|
||||||
|
const Clock *clk,
|
||||||
|
DcalcAPIndex dcalc_ap_index);
|
||||||
void writeStageParasitics(Stage stage);
|
void writeStageParasitics(Stage stage);
|
||||||
void writeSubckts();
|
void writeSubckts();
|
||||||
void findPathCellnames(// Return values.
|
void findPathCellnames(// Return values.
|
||||||
|
|
@ -115,12 +121,22 @@ private:
|
||||||
Path *to_path);
|
Path *to_path);
|
||||||
void writeMeasureSlewStmt(Stage stage,
|
void writeMeasureSlewStmt(Stage stage,
|
||||||
Path *path);
|
Path *path);
|
||||||
void sensitizationValues(const Instance *inst,
|
void gatePortValues(Stage stage,
|
||||||
|
// Return values.
|
||||||
|
LibertyPortLogicValues &port_values,
|
||||||
|
const Clock *&clk,
|
||||||
|
DcalcAPIndex &dcalc_ap_index);
|
||||||
|
void regPortValues(Stage stage,
|
||||||
|
// Return values.
|
||||||
|
LibertyPortLogicValues &port_values,
|
||||||
|
const Clock *&clk,
|
||||||
|
DcalcAPIndex &dcalc_ap_index);
|
||||||
|
void gatePortValues(const Instance *inst,
|
||||||
FuncExpr *expr,
|
FuncExpr *expr,
|
||||||
LibertyPort *input_port,
|
LibertyPort *input_port,
|
||||||
// Return values.
|
// Return values.
|
||||||
LibertyPortLogicValues &port_values);
|
LibertyPortLogicValues &port_values);
|
||||||
void seqSensitizationValues(Sequential *seq,
|
void seqPortValues(Sequential *seq,
|
||||||
const TransRiseFall *tr,
|
const TransRiseFall *tr,
|
||||||
// Return values.
|
// Return values.
|
||||||
LibertyPortLogicValues &port_values);
|
LibertyPortLogicValues &port_values);
|
||||||
|
|
@ -160,7 +176,7 @@ private:
|
||||||
// gate |/ drvr load|/
|
// gate |/ drvr load|/
|
||||||
// input
|
// input
|
||||||
//
|
//
|
||||||
// A path from an input port has no GateInputPath.
|
// A path from an input port has no GateInputPath (the input port is the drvr).
|
||||||
// Internally a stage index from stageFirst() to stageLast()
|
// Internally a stage index from stageFirst() to stageLast()
|
||||||
// is turned into an index into path_expanded_.
|
// is turned into an index into path_expanded_.
|
||||||
//
|
//
|
||||||
|
|
@ -179,10 +195,14 @@ private:
|
||||||
Edge *stageWireEdge(Stage stage);
|
Edge *stageWireEdge(Stage stage);
|
||||||
Pin *stageGateInputPin(Stage stage);
|
Pin *stageGateInputPin(Stage stage);
|
||||||
Pin *stageDrvrPin(Stage stage);
|
Pin *stageDrvrPin(Stage stage);
|
||||||
|
LibertyPort *stageGateInputPort(Stage stage);
|
||||||
|
LibertyPort *stageDrvrPort(Stage stage);
|
||||||
Pin *stageLoadPin(Stage stage);
|
Pin *stageLoadPin(Stage stage);
|
||||||
const char *stageGateInputPinName(Stage stage);
|
const char *stageGateInputPinName(Stage stage);
|
||||||
const char *stageDrvrPinName(Stage stage);
|
const char *stageDrvrPinName(Stage stage);
|
||||||
const char *stageLoadPinName(Stage stage);
|
const char *stageLoadPinName(Stage stage);
|
||||||
|
LibertyCell *stageLibertyCell(Stage stage);
|
||||||
|
Instance *stageInstance(Stage stage);
|
||||||
|
|
||||||
Path *path_;
|
Path *path_;
|
||||||
const char *spice_filename_;
|
const char *spice_filename_;
|
||||||
|
|
@ -721,20 +741,62 @@ WritePathSpice::writeGateStage(Stage stage)
|
||||||
{
|
{
|
||||||
auto input_pin = stageGateInputPin(stage);
|
auto input_pin = stageGateInputPin(stage);
|
||||||
auto input_pin_name = stageGateInputPinName(stage);
|
auto input_pin_name = stageGateInputPinName(stage);
|
||||||
|
auto drvr_pin = stageDrvrPin(stage);
|
||||||
auto drvr_pin_name = stageDrvrPinName(stage);
|
auto drvr_pin_name = stageDrvrPinName(stage);
|
||||||
|
auto load_pin = stageLoadPin(stage);
|
||||||
auto load_pin_name = stageLoadPinName(stage);
|
auto load_pin_name = stageLoadPinName(stage);
|
||||||
streamPrint(spice_stream_, ".subckt stage%d %s %s %s\n",
|
streamPrint(spice_stream_, ".subckt stage%d %s %s %s\n",
|
||||||
stage,
|
stage,
|
||||||
input_pin_name,
|
input_pin_name,
|
||||||
drvr_pin_name,
|
drvr_pin_name,
|
||||||
load_pin_name);
|
load_pin_name);
|
||||||
|
// Driver subckt call.
|
||||||
|
auto inst = stageInstance(stage);
|
||||||
|
auto input_port = stageGateInputPort(stage);
|
||||||
|
auto drvr_port = stageDrvrPort(stage);
|
||||||
|
streamPrint(spice_stream_, "* Gate %s %s -> %s\n",
|
||||||
|
network_->pathName(inst),
|
||||||
|
input_port->name(),
|
||||||
|
drvr_port->name());
|
||||||
|
writeSubcktInst(input_pin);
|
||||||
|
LibertyPortLogicValues port_values;
|
||||||
|
DcalcAPIndex dcalc_ap_index;
|
||||||
|
const Clock *clk;
|
||||||
|
int volt_index = 1;
|
||||||
|
gatePortValues(stage, port_values, clk, dcalc_ap_index);
|
||||||
|
writeSubcktInstVoltSrcs(stage, input_pin, volt_index,
|
||||||
|
port_values, clk, dcalc_ap_index);
|
||||||
|
streamPrint(spice_stream_, "\n");
|
||||||
|
|
||||||
|
port_values.clear();
|
||||||
|
auto pin_iter = network_->connectedPinIterator(drvr_pin);
|
||||||
|
while (pin_iter->hasNext()) {
|
||||||
|
auto pin = pin_iter->next();
|
||||||
|
if (pin != drvr_pin
|
||||||
|
&& pin != load_pin
|
||||||
|
&& network_->direction(pin)->isAnyInput()
|
||||||
|
&& !network_->isHierarchical(pin)
|
||||||
|
&& !network_->isTopLevelPort(pin)) {
|
||||||
|
streamPrint(spice_stream_, "* Side load %s\n", network_->pathName(pin));
|
||||||
|
writeSubcktInst(pin);
|
||||||
|
writeSubcktInstVoltSrcs(stage, pin, volt_index, port_values, NULL, 0);
|
||||||
|
streamPrint(spice_stream_, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete pin_iter;
|
||||||
|
|
||||||
|
writeStageParasitics(stage);
|
||||||
|
streamPrint(spice_stream_, ".ends\n\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
WritePathSpice::writeSubcktInst(const Pin *input_pin)
|
||||||
|
{
|
||||||
auto inst = network_->instance(input_pin);
|
auto inst = network_->instance(input_pin);
|
||||||
auto inst_name = network_->pathName(inst);
|
auto inst_name = network_->pathName(inst);
|
||||||
auto cell = network_->libertyCell(inst);
|
auto cell = network_->libertyCell(inst);
|
||||||
auto cell_name = cell->name();
|
auto cell_name = cell->name();
|
||||||
auto spice_port_names = cell_spice_port_names_[cell_name];
|
auto spice_port_names = cell_spice_port_names_[cell_name];
|
||||||
|
|
||||||
// Instance subckt call.
|
|
||||||
streamPrint(spice_stream_, "x%s", inst_name);
|
streamPrint(spice_stream_, "x%s", inst_name);
|
||||||
StringVector::Iterator port_iter(spice_port_names);
|
StringVector::Iterator port_iter(spice_port_names);
|
||||||
while (port_iter.hasNext()) {
|
while (port_iter.hasNext()) {
|
||||||
|
|
@ -750,55 +812,30 @@ WritePathSpice::writeGateStage(Stage stage)
|
||||||
streamPrint(spice_stream_, " %s/%s", inst_name, subckt_port_name);
|
streamPrint(spice_stream_, " %s/%s", inst_name, subckt_port_name);
|
||||||
}
|
}
|
||||||
streamPrint(spice_stream_, " %s\n", cell_name);
|
streamPrint(spice_stream_, " %s\n", cell_name);
|
||||||
|
|
||||||
writeStageVoltageSources(stage, spice_port_names);
|
|
||||||
writeStageParasitics(stage);
|
|
||||||
streamPrint(spice_stream_, ".ends\n\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Power/ground and input voltage sources.
|
// Power/ground and input voltage sources.
|
||||||
void
|
void
|
||||||
WritePathSpice::writeStageVoltageSources(Stage stage,
|
WritePathSpice::writeSubcktInstVoltSrcs(Stage stage,
|
||||||
StringVector *spice_port_names)
|
const Pin *input_pin,
|
||||||
|
int &volt_index,
|
||||||
|
LibertyPortLogicValues &port_values,
|
||||||
|
const Clock *clk,
|
||||||
|
DcalcAPIndex dcalc_ap_index)
|
||||||
|
|
||||||
{
|
{
|
||||||
auto input_pin = stageGateInputPin(stage);
|
auto inst = network_->instance(input_pin);
|
||||||
|
auto cell = network_->libertyCell(inst);
|
||||||
|
auto cell_name = cell->name();
|
||||||
|
auto spice_port_names = cell_spice_port_names_[cell_name];
|
||||||
|
|
||||||
auto drvr_pin = stageDrvrPin(stage);
|
auto drvr_pin = stageDrvrPin(stage);
|
||||||
auto input_port = network_->libertyPort(input_pin);
|
auto input_port = network_->libertyPort(input_pin);
|
||||||
auto drvr_port = network_->libertyPort(drvr_pin);
|
auto drvr_port = network_->libertyPort(drvr_pin);
|
||||||
auto input_port_name = input_port->name();
|
auto input_port_name = input_port->name();
|
||||||
auto drvr_port_name = drvr_port->name();
|
auto drvr_port_name = drvr_port->name();
|
||||||
auto inst = network_->instance(input_pin);
|
|
||||||
auto inst_name = network_->pathName(inst);
|
auto inst_name = network_->pathName(inst);
|
||||||
auto cell = network_->libertyCell(inst);
|
|
||||||
auto gate_edge = stageGateEdge(stage);
|
|
||||||
|
|
||||||
LibertyPortLogicValues port_values;
|
|
||||||
const Clock *clk = NULL;
|
|
||||||
DcalcAPIndex dcalc_ap_index = 0;
|
|
||||||
if (gate_edge->role()->genericRole() == TimingRole::regClkToQ()) {
|
|
||||||
auto drvr_expr = drvr_port->function();
|
|
||||||
if (drvr_expr) {
|
|
||||||
auto q_port = drvr_expr->port();
|
|
||||||
if (q_port) {
|
|
||||||
// Drvr (register/latch output) function should be a reference
|
|
||||||
// to an internal port like IQ or IQN.
|
|
||||||
auto seq = cell->outputPortSequential(q_port);
|
|
||||||
if (seq) {
|
|
||||||
auto drvr_path = stageDrvrPath(stage);
|
|
||||||
auto drvr_tr = drvr_path->transition(this);
|
|
||||||
seqSensitizationValues(seq, drvr_tr, port_values);
|
|
||||||
clk = drvr_path->clock(this);
|
|
||||||
dcalc_ap_index = drvr_path->dcalcAnalysisPt(this)->index();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
report_->error("no register/latch found for path from %s to %s,\n",
|
|
||||||
input_port_name, drvr_port_name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (drvr_port->function())
|
|
||||||
sensitizationValues(inst, drvr_port->function(), input_port, port_values);
|
|
||||||
int volt_index = 1;
|
|
||||||
debugPrint1(debug_, "write_spice", 2, "subckt %s\n", cell->name());
|
debugPrint1(debug_, "write_spice", 2, "subckt %s\n", cell->name());
|
||||||
StringVector::Iterator port_iter(spice_port_names);
|
StringVector::Iterator port_iter(spice_port_names);
|
||||||
while (port_iter.hasNext()) {
|
while (port_iter.hasNext()) {
|
||||||
|
|
@ -818,7 +855,8 @@ WritePathSpice::writeStageVoltageSources(Stage stage,
|
||||||
|| stringEq(subckt_port_name, drvr_port_name))) {
|
|| stringEq(subckt_port_name, drvr_port_name))) {
|
||||||
// Input voltage to sensitize path from gate input to output.
|
// Input voltage to sensitize path from gate input to output.
|
||||||
auto port = cell->findLibertyPort(subckt_port_name);
|
auto port = cell->findLibertyPort(subckt_port_name);
|
||||||
if (port) {
|
if (port
|
||||||
|
&& port->direction()->isAnyInput()) {
|
||||||
const Pin *pin = network_->findPin(inst, port);
|
const Pin *pin = network_->findPin(inst, port);
|
||||||
// Look for tie high/low or propagated constant values.
|
// Look for tie high/low or propagated constant values.
|
||||||
LogicValue port_value = sim_->logicValue(pin);
|
LogicValue port_value = sim_->logicValue(pin);
|
||||||
|
|
@ -831,6 +869,7 @@ WritePathSpice::writeStageVoltageSources(Stage stage,
|
||||||
}
|
}
|
||||||
switch (port_value) {
|
switch (port_value) {
|
||||||
case logic_zero:
|
case logic_zero:
|
||||||
|
case logic_unknown:
|
||||||
writeVoltageSource(cell, inst_name, subckt_port_name,
|
writeVoltageSource(cell, inst_name, subckt_port_name,
|
||||||
port->relatedGroundPin(),
|
port->relatedGroundPin(),
|
||||||
volt_index);
|
volt_index);
|
||||||
|
|
@ -848,8 +887,6 @@ WritePathSpice::writeStageVoltageSources(Stage stage,
|
||||||
writeClkedStepSource(pin, TransRiseFall::fall(), clk,
|
writeClkedStepSource(pin, TransRiseFall::fall(), clk,
|
||||||
dcalc_ap_index, volt_index);
|
dcalc_ap_index, volt_index);
|
||||||
break;
|
break;
|
||||||
case logic_unknown:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -900,9 +937,62 @@ WritePathSpice::writeVoltageSource(LibertyCell *cell,
|
||||||
pg_port_name);
|
pg_port_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
WritePathSpice::gatePortValues(Stage stage,
|
||||||
|
// Return values.
|
||||||
|
LibertyPortLogicValues &port_values,
|
||||||
|
const Clock *&clk,
|
||||||
|
DcalcAPIndex &dcalc_ap_index)
|
||||||
|
{
|
||||||
|
clk = NULL;
|
||||||
|
dcalc_ap_index = 0;
|
||||||
|
|
||||||
|
auto gate_edge = stageGateEdge(stage);
|
||||||
|
auto drvr_port = stageDrvrPort(stage);
|
||||||
|
if (gate_edge->role()->genericRole() == TimingRole::regClkToQ())
|
||||||
|
regPortValues(stage, port_values, clk, dcalc_ap_index);
|
||||||
|
else if (drvr_port->function()) {
|
||||||
|
auto input_pin = stageGateInputPin(stage);
|
||||||
|
auto input_port = network_->libertyPort(input_pin);
|
||||||
|
auto inst = network_->instance(input_pin);
|
||||||
|
gatePortValues(inst, drvr_port->function(), input_port, port_values);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
WritePathSpice::regPortValues(Stage stage,
|
||||||
|
// Return values.
|
||||||
|
LibertyPortLogicValues &port_values,
|
||||||
|
const Clock *&clk,
|
||||||
|
DcalcAPIndex &dcalc_ap_index)
|
||||||
|
{
|
||||||
|
auto drvr_port = stageDrvrPort(stage);
|
||||||
|
auto drvr_expr = drvr_port->function();
|
||||||
|
if (drvr_expr) {
|
||||||
|
auto q_port = drvr_expr->port();
|
||||||
|
if (q_port) {
|
||||||
|
// Drvr (register/latch output) function should be a reference
|
||||||
|
// to an internal port like IQ or IQN.
|
||||||
|
auto cell = stageLibertyCell(stage);
|
||||||
|
auto seq = cell->outputPortSequential(q_port);
|
||||||
|
if (seq) {
|
||||||
|
auto drvr_path = stageDrvrPath(stage);
|
||||||
|
auto drvr_tr = drvr_path->transition(this);
|
||||||
|
seqPortValues(seq, drvr_tr, port_values);
|
||||||
|
clk = drvr_path->clock(this);
|
||||||
|
dcalc_ap_index = drvr_path->dcalcAnalysisPt(this)->index();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
report_->error("no register/latch found for path from %s to %s,\n",
|
||||||
|
stageGateInputPort(stage)->name(),
|
||||||
|
stageDrvrPort(stage)->name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Find the logic values for expression inputs to enable paths input_port.
|
// Find the logic values for expression inputs to enable paths input_port.
|
||||||
void
|
void
|
||||||
WritePathSpice::sensitizationValues(const Instance *inst,
|
WritePathSpice::gatePortValues(const Instance *inst,
|
||||||
FuncExpr *expr,
|
FuncExpr *expr,
|
||||||
LibertyPort *input_port,
|
LibertyPort *input_port,
|
||||||
// Return values.
|
// Return values.
|
||||||
|
|
@ -914,7 +1004,7 @@ WritePathSpice::sensitizationValues(const Instance *inst,
|
||||||
case FuncExpr::op_port:
|
case FuncExpr::op_port:
|
||||||
break;
|
break;
|
||||||
case FuncExpr::op_not:
|
case FuncExpr::op_not:
|
||||||
sensitizationValues(inst, left, input_port, port_values);
|
gatePortValues(inst, left, input_port, port_values);
|
||||||
break;
|
break;
|
||||||
case FuncExpr::op_or:
|
case FuncExpr::op_or:
|
||||||
if (left->hasPort(input_port)
|
if (left->hasPort(input_port)
|
||||||
|
|
@ -934,8 +1024,8 @@ WritePathSpice::sensitizationValues(const Instance *inst,
|
||||||
// input_port + !left_port
|
// input_port + !left_port
|
||||||
port_values[left->left()->port()] = logic_one;
|
port_values[left->left()->port()] = logic_one;
|
||||||
else {
|
else {
|
||||||
sensitizationValues(inst, left, input_port, port_values);
|
gatePortValues(inst, left, input_port, port_values);
|
||||||
sensitizationValues(inst, right, input_port, port_values);
|
gatePortValues(inst, right, input_port, port_values);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FuncExpr::op_and:
|
case FuncExpr::op_and:
|
||||||
|
|
@ -956,8 +1046,8 @@ WritePathSpice::sensitizationValues(const Instance *inst,
|
||||||
// input_port * !left_port
|
// input_port * !left_port
|
||||||
port_values[left->left()->port()] = logic_zero;
|
port_values[left->left()->port()] = logic_zero;
|
||||||
else {
|
else {
|
||||||
sensitizationValues(inst, left, input_port, port_values);
|
gatePortValues(inst, left, input_port, port_values);
|
||||||
sensitizationValues(inst, right, input_port, port_values);
|
gatePortValues(inst, right, input_port, port_values);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FuncExpr::op_xor:
|
case FuncExpr::op_xor:
|
||||||
|
|
@ -969,8 +1059,8 @@ WritePathSpice::sensitizationValues(const Instance *inst,
|
||||||
&& left->op() == FuncExpr::op_port)
|
&& left->op() == FuncExpr::op_port)
|
||||||
port_values[left->port()] = logic_zero;
|
port_values[left->port()] = logic_zero;
|
||||||
else {
|
else {
|
||||||
sensitizationValues(inst, left, input_port, port_values);
|
gatePortValues(inst, left, input_port, port_values);
|
||||||
sensitizationValues(inst, right, input_port, port_values);
|
gatePortValues(inst, right, input_port, port_values);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case FuncExpr::op_one:
|
case FuncExpr::op_one:
|
||||||
|
|
@ -980,7 +1070,7 @@ WritePathSpice::sensitizationValues(const Instance *inst,
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
WritePathSpice::seqSensitizationValues(Sequential *seq,
|
WritePathSpice::seqPortValues(Sequential *seq,
|
||||||
const TransRiseFall *tr,
|
const TransRiseFall *tr,
|
||||||
// Return values.
|
// Return values.
|
||||||
LibertyPortLogicValues &port_values)
|
LibertyPortLogicValues &port_values)
|
||||||
|
|
@ -1041,16 +1131,15 @@ WritePathSpice::writeStageParasitics(Stage stage)
|
||||||
{
|
{
|
||||||
auto drvr_path = stageDrvrPath(stage);
|
auto drvr_path = stageDrvrPath(stage);
|
||||||
auto drvr_pin = stageDrvrPin(stage);
|
auto drvr_pin = stageDrvrPin(stage);
|
||||||
auto load_pin = stageLoadPin(stage);
|
|
||||||
auto dcalc_ap = drvr_path->dcalcAnalysisPt(this);
|
auto dcalc_ap = drvr_path->dcalcAnalysisPt(this);
|
||||||
auto parasitic_ap = dcalc_ap->parasiticAnalysisPt();
|
auto parasitic_ap = dcalc_ap->parasiticAnalysisPt();
|
||||||
auto parasitic = parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
|
auto parasitic = parasitics_->findParasiticNetwork(drvr_pin, parasitic_ap);
|
||||||
int resistor_index = 1;
|
Set<const Pin*> reachable_pins;
|
||||||
|
int res_index = 1;
|
||||||
int cap_index = 1;
|
int cap_index = 1;
|
||||||
if (parasitic) {
|
if (parasitic) {
|
||||||
auto net = network_->net(drvr_pin);
|
auto net = network_->net(drvr_pin);
|
||||||
auto net_name =
|
auto net_name = net ? network_->pathName(net) : network_->pathName(drvr_pin);
|
||||||
net ? network_->pathName(net) : network_->pathName(drvr_pin);
|
|
||||||
initNodeMap(net_name);
|
initNodeMap(net_name);
|
||||||
streamPrint(spice_stream_, "* Net %s\n", net_name);
|
streamPrint(spice_stream_, "* Net %s\n", net_name);
|
||||||
ParasiticDeviceIterator *device_iter = parasitics_->deviceIterator(parasitic);
|
ParasiticDeviceIterator *device_iter = parasitics_->deviceIterator(parasitic);
|
||||||
|
|
@ -1058,14 +1147,19 @@ WritePathSpice::writeStageParasitics(Stage stage)
|
||||||
auto device = device_iter->next();
|
auto device = device_iter->next();
|
||||||
auto resistance = parasitics_->value(device, parasitic_ap);
|
auto resistance = parasitics_->value(device, parasitic_ap);
|
||||||
if (parasitics_->isResistor(device)) {
|
if (parasitics_->isResistor(device)) {
|
||||||
ParasiticNode *node1 = parasitics_->node1(device);
|
auto node1 = parasitics_->node1(device);
|
||||||
ParasiticNode *node2 = parasitics_->node2(device);
|
auto node2 = parasitics_->node2(device);
|
||||||
streamPrint(spice_stream_, "R%d %s %s %.3e\n",
|
streamPrint(spice_stream_, "R%d %s %s %.3e\n",
|
||||||
resistor_index,
|
res_index,
|
||||||
nodeName(node1),
|
nodeName(node1),
|
||||||
nodeName(node2),
|
nodeName(node2),
|
||||||
resistance);
|
resistance);
|
||||||
resistor_index++;
|
res_index++;
|
||||||
|
|
||||||
|
auto pin1 = parasitics_->connectionPin(node1);
|
||||||
|
reachable_pins.insert(pin1);
|
||||||
|
auto pin2 = parasitics_->connectionPin(node2);
|
||||||
|
reachable_pins.insert(pin2);
|
||||||
}
|
}
|
||||||
else if (parasitics_->isCouplingCap(device)) {
|
else if (parasitics_->isCouplingCap(device)) {
|
||||||
// Ground coupling caps for now.
|
// Ground coupling caps for now.
|
||||||
|
|
@ -1079,6 +1173,29 @@ WritePathSpice::writeStageParasitics(Stage stage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete device_iter;
|
delete device_iter;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
streamPrint(spice_stream_, "* No parasitics found for this net.\n");
|
||||||
|
|
||||||
|
// Add resistors from drvr to load for missing parasitic connections.
|
||||||
|
auto pin_iter = network_->connectedPinIterator(drvr_pin);
|
||||||
|
while (pin_iter->hasNext()) {
|
||||||
|
auto pin = pin_iter->next();
|
||||||
|
if (pin != drvr_pin
|
||||||
|
&& network_->isLoad(pin)
|
||||||
|
&& !network_->isHierarchical(pin)
|
||||||
|
&& !reachable_pins.hasKey(pin)) {
|
||||||
|
streamPrint(spice_stream_, "R%d %s %s %.3e\n",
|
||||||
|
res_index,
|
||||||
|
network_->pathName(drvr_pin),
|
||||||
|
network_->pathName(pin),
|
||||||
|
short_ckt_resistance_);
|
||||||
|
res_index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete pin_iter;
|
||||||
|
|
||||||
|
if (parasitic) {
|
||||||
ParasiticNodeIterator *node_iter = parasitics_->nodeIterator(parasitic);
|
ParasiticNodeIterator *node_iter = parasitics_->nodeIterator(parasitic);
|
||||||
while (node_iter->hasNext()) {
|
while (node_iter->hasNext()) {
|
||||||
auto node = node_iter->next();
|
auto node = node_iter->next();
|
||||||
|
|
@ -1094,13 +1211,6 @@ WritePathSpice::writeStageParasitics(Stage stage)
|
||||||
}
|
}
|
||||||
delete node_iter;
|
delete node_iter;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
streamPrint(spice_stream_, "* No parasitics found for this net.\n");
|
|
||||||
streamPrint(spice_stream_, "R1 %s %s %.3e\n",
|
|
||||||
network_->pathName(drvr_pin),
|
|
||||||
network_->pathName(load_pin),
|
|
||||||
short_ckt_resistance_);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -1204,6 +1314,18 @@ WritePathSpice::findPathCellnames(// Return values.
|
||||||
debugPrint1(debug_, "write_spice", 2, "cell %s\n", cell->name());
|
debugPrint1(debug_, "write_spice", 2, "cell %s\n", cell->name());
|
||||||
path_cell_names.insert(cell->name());
|
path_cell_names.insert(cell->name());
|
||||||
}
|
}
|
||||||
|
// Include side receivers.
|
||||||
|
auto drvr_pin = stageDrvrPin(stage);
|
||||||
|
auto pin_iter = network_->connectedPinIterator(drvr_pin);
|
||||||
|
while (pin_iter->hasNext()) {
|
||||||
|
auto pin = pin_iter->next();
|
||||||
|
auto port = network_->libertyPort(pin);
|
||||||
|
if (port) {
|
||||||
|
auto cell = port->libertyCell();
|
||||||
|
path_cell_names.insert(cell->name());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete pin_iter;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1329,6 +1451,13 @@ WritePathSpice::stageGateInputPin(Stage stage)
|
||||||
return path->pin(this);
|
return path->pin(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LibertyPort *
|
||||||
|
WritePathSpice::stageGateInputPort(Stage stage)
|
||||||
|
{
|
||||||
|
auto pin = stageGateInputPin(stage);
|
||||||
|
return network_->libertyPort(pin);
|
||||||
|
}
|
||||||
|
|
||||||
Pin *
|
Pin *
|
||||||
WritePathSpice::stageDrvrPin(Stage stage)
|
WritePathSpice::stageDrvrPin(Stage stage)
|
||||||
{
|
{
|
||||||
|
|
@ -1336,6 +1465,13 @@ WritePathSpice::stageDrvrPin(Stage stage)
|
||||||
return path->pin(this);
|
return path->pin(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LibertyPort *
|
||||||
|
WritePathSpice::stageDrvrPort(Stage stage)
|
||||||
|
{
|
||||||
|
auto pin = stageDrvrPin(stage);
|
||||||
|
return network_->libertyPort(pin);
|
||||||
|
}
|
||||||
|
|
||||||
Pin *
|
Pin *
|
||||||
WritePathSpice::stageLoadPin(Stage stage)
|
WritePathSpice::stageLoadPin(Stage stage)
|
||||||
{
|
{
|
||||||
|
|
@ -1364,6 +1500,20 @@ WritePathSpice::stageLoadPinName(Stage stage)
|
||||||
return network_->pathName(pin);
|
return network_->pathName(pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Instance *
|
||||||
|
WritePathSpice::stageInstance(Stage stage)
|
||||||
|
{
|
||||||
|
auto pin = stageDrvrPin(stage);
|
||||||
|
return network_->instance(pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
LibertyCell *
|
||||||
|
WritePathSpice::stageLibertyCell(Stage stage)
|
||||||
|
{
|
||||||
|
auto pin = stageDrvrPin(stage);
|
||||||
|
return network_->libertyPort(pin)->libertyCell();
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
// fprintf for c++ streams.
|
// fprintf for c++ streams.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue