Merge branch 'master' into master

This commit is contained in:
James Cherry 2019-01-20 09:56:23 -08:00 committed by GitHub
commit 3c779e4cf9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 228 additions and 168 deletions

2
README
View File

@ -32,7 +32,7 @@ See INSTALL for installation and build instructions. Alternatively, run using Do
* Liberty
* SDC
* SDF
* RSPF/DSPF/SPEF
* SPEF
## Exception path support
* False path

View File

@ -1127,20 +1127,14 @@ ConcreteNetwork::makeConcreteInstance(ConcreteCell *cell,
}
void
ConcreteNetwork::makeInternalPins(Instance *inst)
ConcreteNetwork::makePins(Instance *inst)
{
LibertyCell *lib_cell = libertyCell(inst);
if (lib_cell && lib_cell->hasInternalPorts()) {
CellPortBitIterator *port_iterator = portBitIterator(cell(inst));
while (port_iterator->hasNext()) {
Port *port = port_iterator->next();
LibertyPort *lib_port = libertyPort(port);
if (lib_port->direction()->isInternal()
&& lib_cell->hasTimingArcs(lib_port))
makePin(inst, port, NULL);
}
delete port_iterator;
CellPortBitIterator *port_iterator = portBitIterator(cell(inst));
while (port_iterator->hasNext()) {
Port *port = port_iterator->next();
makePin(inst, port, NULL);
}
delete port_iterator;
}
void

View File

@ -185,7 +185,7 @@ public:
virtual Instance *makeInstance(LibertyCell *cell,
const char *name,
Instance *parent);
void makeInternalPins(Instance *inst);
void makePins(Instance *inst);
// For linking.
virtual Instance *makeInstance(Cell *cell,
const char *name,

View File

@ -482,8 +482,7 @@ public:
virtual Instance *makeInstance(LibertyCell *cell,
const char *name,
Instance *parent) = 0;
// Make liberty internal pins.
virtual void makeInternalPins(Instance *inst) = 0;
virtual void makePins(Instance *inst) = 0;
virtual void swapCell(Instance *inst,
LibertyCell *cell) = 0;
// Deleting instance also deletes instance pins.

View File

@ -903,9 +903,9 @@ NetworkNameAdapter::makeInstance(LibertyCell *cell,
}
void
NetworkNameAdapter::makeInternalPins(Instance *inst)
NetworkNameAdapter::makePins(Instance *inst)
{
network_edit_->makeInternalPins(inst);
network_edit_->makePins(inst);
}
void

View File

@ -122,7 +122,7 @@ public:
virtual Instance *makeInstance(LibertyCell *cell,
const char *name,
Instance *parent);
virtual void makeInternalPins(Instance *inst);
virtual void makePins(Instance *inst);
virtual void swapCell(Instance *inst,
LibertyCell *cell);
virtual Net *makeNet(const char *name,

View File

@ -3565,7 +3565,7 @@ Sta::makeInstance(const char *name,
{
NetworkEdit *network = networkCmdEdit();
Instance *inst = network->makeInstance(cell, name, parent);
network->makeInternalPins(inst);
network->makePins(inst);
makeInstanceAfter(inst);
return inst;
}
@ -3645,20 +3645,17 @@ Sta::disconnectPin(Pin *pin)
//
////////////////////////////////////////////////////////////////
// Network::makeInternalPins with connectPinAfter.
// Network::makePins with connectPinAfter.
void
Sta::makeInstanceAfter(Instance *inst)
{
LibertyCell *lib_cell = network_->libertyCell(inst);
if (lib_cell && lib_cell->hasInternalPorts()) {
if (lib_cell) {
LibertyCellPortBitIterator port_iter(lib_cell);
while (port_iter.hasNext()) {
LibertyPort *lib_port = port_iter.next();
if (lib_port->direction()->isInternal()
&& lib_cell->hasTimingArcs(lib_port)) {
Pin *pin = network_->findPin(inst, lib_port);
connectPinAfter(pin);
}
Pin *pin = network_->findPin(inst, lib_port);
connectPinAfter(pin);
}
}
}

View File

@ -37,6 +37,7 @@
#include "PathRef.hh"
#include "PathExpanded.hh"
#include "StaState.hh"
#include "Sim.hh"
#include "WritePathSpice.hh"
namespace sta {
@ -49,6 +50,7 @@ typedef Vector<string> StringVector;
typedef Map<string, StringVector*> CellSpicePortNames;
typedef int Stage;
typedef Map<ParasiticNode*, int> ParasiticNodeMap;
typedef Map<LibertyPort*, LogicValue> LibertyPortLogicValues;
void
split(const string &text,
@ -88,6 +90,7 @@ private:
void writeGateStage(Stage stage);
void writeStageVoltageSources(LibertyCell *cell,
StringVector *spice_port_names,
const Instance *inst,
const char *inst_name,
LibertyPort *from_port,
LibertyPort *drvr_port);
@ -105,14 +108,29 @@ private:
void initNodeMap(const char *net_name);
const char *spiceTrans(const TransRiseFall *tr);
void writeMeasureDelayStmt(Stage stage,
Path *input_path);
Path *from_path,
Path *to_path);
void writeMeasureSlewStmt(Stage stage,
Path *path);
void sensitizationValues(const Instance *inst,
FuncExpr *expr,
LibertyPort *from_port,
// Return values.
LibertyPortLogicValues &port_values);
// Stage "accessors".
//
// stage
// |---------------|
// |\ |\
// -------| >---/\/\/----| >---
// gate |/ drvr load|/
// input
//
// A path from an input port has no GateInputPath.
// Internally a stage index from stageFirst() to stageLast()
// is turned into an index into path_expanded_.
// A path from an input port has no GateInputPath.
//
Stage stageFirst();
Stage stageLast();
string stageName(Stage stage);
@ -149,9 +167,8 @@ private:
const char *net_name_;
float power_voltage_;
float gnd_voltage_;
// Resistance to use to simulate a short circuit between spice nodes.
static const float short_ckt_resistance_;
float short_ckt_resistance_;
};
////////////////////////////////////////////////////////////////
@ -200,8 +217,6 @@ writePathSpice(Path *path,
writer.writeSpice();
}
const float WritePathSpice::short_ckt_resistance_ = .0001;
WritePathSpice::WritePathSpice(Path *path,
const char *spice_filename,
const char *subckt_filename,
@ -219,7 +234,8 @@ WritePathSpice::WritePathSpice(Path *path,
power_name_(power_name),
gnd_name_(gnd_name),
path_expanded_(sta),
net_name_(NULL)
net_name_(NULL),
short_ckt_resistance_(.0001)
{
auto lib = network_->defaultLibertyLibrary();
power_voltage_ = lib->supplyVoltage(power_name_);
@ -369,41 +385,51 @@ WritePathSpice::writeMeasureStmts()
streamPrint(spice_stream_, "********************\n\n");
for (auto stage = stageFirst(); stage <= stageLast(); stage++) {
auto input_path = (stage == stageFirst())
? stageDrvrPath(stage)
: stageGateInputPath(stage);
writeMeasureDelayStmt(stage, input_path);
writeMeasureSlewStmt(stage, input_path);
auto gate_input_path = stageGateInputPath(stage);
auto drvr_path = stageDrvrPath(stage);
auto load_path = stageLoadPath(stage);
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);
if (stage == stageLast())
writeMeasureSlewStmt(stage, stageLoadPath(stage));
writeMeasureSlewStmt(stage, load_path);
}
streamPrint(spice_stream_, "\n");
}
void
WritePathSpice::writeMeasureDelayStmt(Stage stage,
Path *input_path)
Path *from_path,
Path *to_path)
{
auto lib = network_->defaultLibertyLibrary();
auto input_pin_name = network_->pathName(input_path->pin(this));
auto input_tr = input_path->transition(this);
auto input_threshold = power_voltage_ * lib->inputThreshold(input_tr);
auto from_pin_name = network_->pathName(from_path->pin(this));
auto from_tr = from_path->transition(this);
auto from_threshold = power_voltage_ * lib->inputThreshold(from_tr);
auto load_path = stageLoadPath(stage);
auto load_pin_name = stageLoadPinName(stage);
auto load_tr = load_path->transition(this);
auto load_threshold = power_voltage_ * lib->inputThreshold(load_tr);
auto to_pin_name = network_->pathName(to_path->pin(this));
auto to_tr = to_path->transition(this);
auto to_threshold = power_voltage_ * lib->inputThreshold(to_tr);
streamPrint(spice_stream_,
".measure tran %s_%s_delay_%s trig v(%s) val=%.3f %s=last targ v(%s) val=%.3f %s=last\n",
".measure tran %s_%s_delay_%s\n",
stageName(stage).c_str(),
input_pin_name,
load_pin_name,
input_pin_name,
input_threshold,
spiceTrans(input_tr),
load_pin_name,
load_threshold,
spiceTrans(load_tr));
from_pin_name,
to_pin_name);
streamPrint(spice_stream_,
"+trig v(%s) val=%.3f %s=last\n",
from_pin_name,
from_threshold,
spiceTrans(from_tr));
streamPrint(spice_stream_,
"+targ v(%s) val=%.3f %s=last\n",
to_pin_name,
to_threshold,
spiceTrans(to_tr));
}
void
@ -426,12 +452,16 @@ WritePathSpice::writeMeasureSlewStmt(Stage stage,
threshold2 = lower;
}
streamPrint(spice_stream_,
".measure tran %s_%s_slew trig v(%s) val=%.3f %s=last targ v(%s) val=%.3f %s=last\n",
".measure tran %s_%s_slew\n",
stageName(stage).c_str(),
pin_name,
pin_name);
streamPrint(spice_stream_,
"+trig v(%s) val=%.3f %s=last\n",
pin_name,
threshold1,
spice_tr,
spice_tr);
streamPrint(spice_stream_,
"+targ v(%s) val=%.3f %s=last\n",
pin_name,
threshold2,
spice_tr);
@ -515,74 +545,18 @@ WritePathSpice::writeGateStage(Stage stage)
streamPrint(spice_stream_, " %s\n", cell_name);
writeStageVoltageSources(cell, spice_port_names,
inst_name,
inst, inst_name,
network_->libertyPort(input_pin),
network_->libertyPort(drvr_pin));
writeStageParasitics(stage);
streamPrint(spice_stream_, ".ends\n\n");
}
typedef Map<LibertyPort*, LogicValue> 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: {
auto left = expr->left();
auto 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: {
auto left = expr->left();
auto 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.
auto left = expr->left();
auto 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
WritePathSpice::writeStageVoltageSources(LibertyCell *cell,
StringVector *spice_port_names,
const Instance *inst,
const char *inst_name,
LibertyPort *from_port,
LibertyPort *drvr_port)
@ -591,7 +565,7 @@ WritePathSpice::writeStageVoltageSources(LibertyCell *cell,
auto drvr_port_name = drvr_port->name();
auto lib = cell->libertyLibrary();
LibertyPortLogicValues port_values;
sensitizationValues(drvr_port->function(), from_port, port_values);
sensitizationValues(inst, 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);
@ -614,49 +588,127 @@ WritePathSpice::writeStageVoltageSources(LibertyCell *cell,
auto 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
const Pin *pin = network_->findPin(inst, port);
// Look for tie high/low or propagated constant values.
LogicValue port_value = sim_->logicValue(pin);
if (port_value == logic_unknown) {
bool has_value;
LogicValue value;
port_values.findKey(port, value, has_value);
if (has_value)
port_value = value;
}
if (port_value == logic_zero)
pg_port_name = port->relatedGroundPin();
else if (port_value == logic_one)
pg_port_name = port->relatedPowerPin();
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);
}
else
report_->error("port %s %s not found,\n",
subckt_port_name,
pg_port_name);
}
}
}
}
}
// Find the logic values for expression inputs to enable paths from_port.
void
WritePathSpice::sensitizationValues(const Instance *inst,
FuncExpr *expr,
LibertyPort *from_port,
// Return values.
LibertyPortLogicValues &port_values)
{
auto left = expr->left();
auto right = expr->right();
switch (expr->op()) {
case FuncExpr::op_port:
break;
case FuncExpr::op_not:
sensitizationValues(inst, expr->left(), from_port, port_values);
break;
case FuncExpr::op_or:
if (left->hasPort(from_port)
&& right->op() == FuncExpr::op_port)
port_values[right->port()] = logic_zero;
else if (left->hasPort(from_port)
&& right->op() == FuncExpr::op_not
&& right->left()->op() == FuncExpr::op_port)
// from_port + !right_port
port_values[right->left()->port()] = logic_one;
else if (right->hasPort(from_port)
&& left->op() == FuncExpr::op_port)
port_values[left->port()] = logic_zero;
else if (right->hasPort(from_port)
&& left->op() == FuncExpr::op_not
&& left->left()->op() == FuncExpr::op_port)
// from_port + !left_port
port_values[left->left()->port()] = logic_one;
else {
sensitizationValues(inst, expr->left(), from_port, port_values);
sensitizationValues(inst, expr->right(), from_port, port_values);
}
break;
case FuncExpr::op_and:
if (left->hasPort(from_port)
&& right->op() == FuncExpr::op_port)
port_values[right->port()] = logic_one;
else if (left->hasPort(from_port)
&& right->op() == FuncExpr::op_not
&& right->left()->op() == FuncExpr::op_port)
// from_port * !right_port
port_values[right->left()->port()] = logic_zero;
else if (right->hasPort(from_port)
&& left->op() == FuncExpr::op_port)
port_values[left->port()] = logic_one;
else if (right->hasPort(from_port)
&& left->op() == FuncExpr::op_not
&& left->left()->op() == FuncExpr::op_port)
// from_port * !left_port
port_values[left->left()->port()] = logic_zero;
else {
sensitizationValues(inst, expr->left(), from_port, port_values);
sensitizationValues(inst, expr->right(), from_port, port_values);
}
break;
case FuncExpr::op_xor:
// Need to know timing arc sense to get this 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;
else {
sensitizationValues(inst, expr->left(), from_port, port_values);
sensitizationValues(inst, expr->right(), from_port, port_values);
}
break;
case FuncExpr::op_one:
case FuncExpr::op_zero:
break;
}
}
class ParasiticNodeNameLess
{
public:
@ -699,7 +751,8 @@ findParasiticDevicesNodes(ParasiticNode *node,
if (!devices.hasKey(device)) {
devices.insert(device);
auto other_node = parasitics->otherNode(device, node);
findParasiticDevicesNodes(other_node, parasitics, nodes, devices);
if (other_node)
findParasiticDevicesNodes(other_node, parasitics, nodes, devices);
}
}
delete device_iter;
@ -717,7 +770,7 @@ WritePathSpice::writeStageParasitics(Stage stage)
int resistor_index = 1;
int cap_index = 1;
if (parasitic) {
Net *net = network_->net(drvr_pin);
auto net = network_->net(drvr_pin);
auto net_name =
net ? network_->pathName(net) : network_->pathName(drvr_pin);
initNodeMap(net_name);
@ -756,18 +809,22 @@ WritePathSpice::writeStageParasitics(Stage stage)
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++;
if (cap > 0.0) {
streamPrint(spice_stream_, "C%d %s 0 %.3e\n",
cap_index,
nodeName(node),
cap);
cap_index++;
}
}
}
else
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

View File

@ -1926,7 +1926,7 @@ define_cmd_args "write_path_spice" { -path_args path_args\
-ground ground}
proc write_path_spice { args } {
parse_key_args "write_spice" args \
parse_key_args "write_path_spice" args \
keys {-spice_directory -lib_subckt_file -model_file \
-power -ground -path_args} \
flags {}

View File

@ -4651,7 +4651,7 @@ liberty_supply_exists(const char *supply_name)
{
auto network = Sta::sta()->network();
auto lib = network->defaultLibertyLibrary();
return lib->supplyExists(supply_name);
return lib && lib->supplyExists(supply_name);
}
void

View File

@ -1805,8 +1805,18 @@ VerilogReader::makeModuleInstNetwork(VerilogModuleInst *mod_inst,
if (cell) {
Instance *inst = network_->makeInstance(cell, mod_inst->instanceName(),
parent);
network_->makeInternalPins(inst);
bool is_leaf = network_->isLeaf(cell);
if (is_leaf) {
// Make all pins.
LibertyCell *lib_cell = network_->libertyCell(cell);
if (lib_cell) {
LibertyCellPortBitIterator port_iter(lib_cell);
while (port_iter.hasNext()) {
LibertyPort *port = port_iter.next();
network_->makePin(inst, reinterpret_cast<Port*>(port), NULL);
}
}
}
VerilogBindingTbl bindings(zero_net_name_, one_net_name_);
if (mod_inst->hasPins()) {
if (mod_inst->namedPins())
@ -1945,8 +1955,12 @@ VerilogReader::makeInstPin(Instance *inst,
Net *net = NULL;
if (net_name)
net = parent_bindings->ensureNetBinding(net_name, parent, network_);
// Guard against repeated port name.
if (network_->findPin(inst, port) == NULL) {
if (is_leaf) {
// Connect leaf pin to net.
if (net)
network_->connect(inst, port, net);
}
else {
Pin *pin = network_->makePin(inst, port, net);
if (!is_leaf && net) {
const char *port_name = network_->name(port);
@ -1990,10 +2004,9 @@ VerilogReader::makeLibertyInst(VerilogLibertyInst *lib_inst,
}
network_->makePin(inst, reinterpret_cast<Port*>(port), net);
}
// Make internal pin.
if (port->direction()->isInternal()
&& lib_cell->hasTimingArcs(port))
network_->makePin(inst, reinterpret_cast<Port*>(port), NULL);
else
// Make unconnected pin.
network_->makePin(inst, reinterpret_cast<Port*>(port), NULL);
}
}