2019/02/21 write_path_spice include side load pins

This commit is contained in:
James Cherry 2019-02-21 08:00:06 -08:00
parent 83c8dc3358
commit 1af0963fd4
4 changed files with 238 additions and 85 deletions

2
.gitignore vendored
View File

@ -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

View File

@ -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

Binary file not shown.

View File

@ -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.