prima mcmm bugs
Signed-off-by: James Cherry <cherry@CerezoBook.local>
This commit is contained in:
parent
7fdc304e12
commit
c00b847b20
|
|
@ -45,8 +45,9 @@ ArcDcalcWaveforms::inputWaveform(ArcDcalcArg &dcalc_arg,
|
||||||
Graph *graph = sta->graph();
|
Graph *graph = sta->graph();
|
||||||
Report *report = sta->report();
|
Report *report = sta->report();
|
||||||
const Pin *in_pin = dcalc_arg.inPin();
|
const Pin *in_pin = dcalc_arg.inPin();
|
||||||
LibertyPort *port = network->libertyPort(in_pin);
|
LibertyPort *link_port = network->libertyPort(in_pin);
|
||||||
if (port) {
|
if (link_port) {
|
||||||
|
LibertyPort *port = link_port->scenePort(scene, min_max);
|
||||||
const RiseFall *in_rf = dcalc_arg.inEdge();
|
const RiseFall *in_rf = dcalc_arg.inEdge();
|
||||||
DriverWaveform *driver_waveform = port->driverWaveform(in_rf);
|
DriverWaveform *driver_waveform = port->driverWaveform(in_rf);
|
||||||
if (driver_waveform) {
|
if (driver_waveform) {
|
||||||
|
|
|
||||||
|
|
@ -186,7 +186,7 @@ ArcDcalcArg::drvrCell() const
|
||||||
return arc_->to()->libertyCell();
|
return arc_->to()->libertyCell();
|
||||||
}
|
}
|
||||||
|
|
||||||
const LibertyLibrary *
|
LibertyLibrary *
|
||||||
ArcDcalcArg::drvrLibrary() const
|
ArcDcalcArg::drvrLibrary() const
|
||||||
{
|
{
|
||||||
return arc_->to()->libertyLibrary();
|
return arc_->to()->libertyLibrary();
|
||||||
|
|
@ -198,6 +198,13 @@ ArcDcalcArg::drvrEdge() const
|
||||||
return arc_->toEdge()->asRiseFall();
|
return arc_->toEdge()->asRiseFall();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ArcDcalcArg::setSceneArc(const Scene *scene,
|
||||||
|
const MinMax *min_max)
|
||||||
|
{
|
||||||
|
arc_ = arc_->sceneArc(scene->libertyIndex(min_max));
|
||||||
|
}
|
||||||
|
|
||||||
const Net *
|
const Net *
|
||||||
ArcDcalcArg::drvrNet(const Network *network) const
|
ArcDcalcArg::drvrNet(const Network *network) const
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -227,6 +227,7 @@ DelayCalcBase::setDcalcArgParasiticSlew(ArcDcalcArg &gate,
|
||||||
gate.edge(),
|
gate.edge(),
|
||||||
scene, min_max);
|
scene, min_max);
|
||||||
gate.setInSlew(in_slew);
|
gate.setInSlew(in_slew);
|
||||||
|
gate.setSceneArc(scene, min_max);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -183,6 +183,7 @@ PrimaDelayCalc::gateDelay(const Pin *drvr_pin,
|
||||||
ArcDcalcArgSeq dcalc_args;
|
ArcDcalcArgSeq dcalc_args;
|
||||||
dcalc_args.emplace_back(nullptr, drvr_pin, nullptr, arc, in_slew, load_cap,
|
dcalc_args.emplace_back(nullptr, drvr_pin, nullptr, arc, in_slew, load_cap,
|
||||||
parasitic);
|
parasitic);
|
||||||
|
dcalc_args[0].setSceneArc(scene, min_max);
|
||||||
ArcDcalcResultSeq dcalc_results = gateDelays(dcalc_args, load_pin_index_map,
|
ArcDcalcResultSeq dcalc_results = gateDelays(dcalc_args, load_pin_index_map,
|
||||||
scene, min_max);
|
scene, min_max);
|
||||||
return dcalc_results[0];
|
return dcalc_results[0];
|
||||||
|
|
@ -256,9 +257,10 @@ PrimaDelayCalc::checkArgs(ArcDcalcArgSeq &dcalc_args,
|
||||||
if (output_waveforms->slewAxis()->inBounds(in_slew)) {
|
if (output_waveforms->slewAxis()->inBounds(in_slew)) {
|
||||||
if (output_waveforms->capAxis()->inBounds(dcalc_arg.loadCap())) {
|
if (output_waveforms->capAxis()->inBounds(dcalc_arg.loadCap())) {
|
||||||
output_waveforms_[drvr_idx] = output_waveforms;
|
output_waveforms_[drvr_idx] = output_waveforms;
|
||||||
debugPrint(debug_, "prima", 1, "{} {}",
|
debugPrint(debug_, "prima", 1, "{} {} {}",
|
||||||
dcalc_arg.drvrCell()->name(),
|
dcalc_arg.drvrCell()->name(),
|
||||||
dcalc_arg.drvrEdge()->to_string().c_str());
|
dcalc_arg.drvrEdge()->to_string().c_str(),
|
||||||
|
scene->name());
|
||||||
LibertyCell *drvr_cell = dcalc_arg.drvrCell();
|
LibertyCell *drvr_cell = dcalc_arg.drvrCell();
|
||||||
drvr_cell->ensureVoltageWaveforms(scenes_);
|
drvr_cell->ensureVoltageWaveforms(scenes_);
|
||||||
}
|
}
|
||||||
|
|
@ -362,7 +364,7 @@ PrimaDelayCalc::simulate1(const MatrixSd &G,
|
||||||
v_ = v_prev_ = x_to_v * x_init;
|
v_ = v_prev_ = x_to_v * x_init;
|
||||||
|
|
||||||
time_step_ = time_step_prev_ = timeStep();
|
time_step_ = time_step_prev_ = timeStep();
|
||||||
debugPrint(debug_, "ccs_dcalc", 1, "time step {}",
|
debugPrint(debug_, "prima", 1, "time step {}",
|
||||||
delayAsString(time_step_, this));
|
delayAsString(time_step_, this));
|
||||||
|
|
||||||
MatrixSd A(order, order);
|
MatrixSd A(order, order);
|
||||||
|
|
@ -402,7 +404,7 @@ PrimaDelayCalc::simulate1(const MatrixSd &G,
|
||||||
v_ = x_to_v * x;
|
v_ = x_to_v * x;
|
||||||
|
|
||||||
const ArcDcalcArg &dcalc_arg = (*dcalc_args_)[0];
|
const ArcDcalcArg &dcalc_arg = (*dcalc_args_)[0];
|
||||||
debugPrint(debug_, "ccs_dcalc", 3, "{} ceff {} VDrvr {:.4f} Idrvr {}",
|
debugPrint(debug_, "prima", 3, "{} ceff {} VDrvr {:.4f} Idrvr {}",
|
||||||
delayAsString(time, this),
|
delayAsString(time, this),
|
||||||
units_->capacitanceUnit()->asString(ceff_[0]),
|
units_->capacitanceUnit()->asString(ceff_[0]),
|
||||||
voltage(dcalc_arg.drvrPin()),
|
voltage(dcalc_arg.drvrPin()),
|
||||||
|
|
@ -427,7 +429,7 @@ PrimaDelayCalc::simulate1(const MatrixSd &G,
|
||||||
double
|
double
|
||||||
PrimaDelayCalc::timeStep()
|
PrimaDelayCalc::timeStep()
|
||||||
{
|
{
|
||||||
// Needs to use LTE for time step dynamic control.
|
// Should use LTE for dynamic time step control.
|
||||||
return driverResistance() * load_cap_ * .02;
|
return driverResistance() * load_cap_ * .02;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -443,7 +445,8 @@ PrimaDelayCalc::driverResistance()
|
||||||
{
|
{
|
||||||
const Pin *drvr_pin = (*dcalc_args_)[0].drvrPin();
|
const Pin *drvr_pin = (*dcalc_args_)[0].drvrPin();
|
||||||
LibertyPort *drvr_port = network_->libertyPort(drvr_pin);
|
LibertyPort *drvr_port = network_->libertyPort(drvr_pin);
|
||||||
return drvr_port->driveResistance(drvr_rf_, min_max_);
|
LibertyPort *scene_port = drvr_port->scenePort(scene_, min_max_);
|
||||||
|
return scene_port->driveResistance(drvr_rf_, min_max_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -526,7 +529,7 @@ PrimaDelayCalc::placeNode(ParasiticNode *node,
|
||||||
const Pin *pin = parasitics_->pin(node);
|
const Pin *pin = parasitics_->pin(node);
|
||||||
if (pin) {
|
if (pin) {
|
||||||
pin_node_map_[pin] = index;
|
pin_node_map_[pin] = index;
|
||||||
debugPrint(debug_, "ccs_dcalc", 1, "pin {} node {}",
|
debugPrint(debug_, "prima", 1, "pin {} node {}",
|
||||||
network_->pathName(pin), index);
|
network_->pathName(pin), index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -606,7 +609,7 @@ PrimaDelayCalc::stampEqns()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (debug_->check("ccs_dcalc", 3)) {
|
if (debug_->check("prima", 3)) {
|
||||||
reportMatrix("G", G_);
|
reportMatrix("G", G_);
|
||||||
reportMatrix("C", C_);
|
reportMatrix("C", C_);
|
||||||
reportMatrix("B", B_);
|
reportMatrix("B", B_);
|
||||||
|
|
@ -834,7 +837,8 @@ PrimaDelayCalc::measureThresholds(double time)
|
||||||
if ((v_prev < th && th <= v) || (v_prev > th && th >= v)) {
|
if ((v_prev < th && th <= v) || (v_prev > th && th >= v)) {
|
||||||
double t_cross =
|
double t_cross =
|
||||||
time - time_step_ + (th - v_prev) * time_step_ / (v - v_prev);
|
time - time_step_ + (th - v_prev) * time_step_ / (v - v_prev);
|
||||||
debugPrint(debug_, "ccs_measure", 1, "node {} cross {:.2f} {}", node_idx, th,
|
debugPrint(debug_, "prima_measure", 1, "node {} cross {:.2f} {}",
|
||||||
|
node_idx, th,
|
||||||
delayAsString(t_cross, this));
|
delayAsString(t_cross, this));
|
||||||
threshold_times_[node_idx][m] = t_cross;
|
threshold_times_[node_idx][m] = t_cross;
|
||||||
}
|
}
|
||||||
|
|
@ -882,7 +886,7 @@ PrimaDelayCalc::dcalcResults()
|
||||||
dcalc_result.setGateDelay(gate_delay2);
|
dcalc_result.setGateDelay(gate_delay2);
|
||||||
dcalc_result.setDrvrSlew(drvr_slew2);
|
dcalc_result.setDrvrSlew(drvr_slew2);
|
||||||
|
|
||||||
debugPrint(debug_, "ccs_dcalc", 2, "{} gate delay {} slew {}",
|
debugPrint(debug_, "prima", 2, "{} gate delay {} slew {}",
|
||||||
network_->pathName(drvr_pin), delayAsString(gate_delay, this),
|
network_->pathName(drvr_pin), delayAsString(gate_delay, this),
|
||||||
delayAsString(drvr_slew, this));
|
delayAsString(drvr_slew, this));
|
||||||
|
|
||||||
|
|
@ -895,7 +899,7 @@ PrimaDelayCalc::dcalcResults()
|
||||||
ThresholdTimes &drvr_times = threshold_times_[drvr_node];
|
ThresholdTimes &drvr_times = threshold_times_[drvr_node];
|
||||||
double wire_delay = wire_times[threshold_vth] - drvr_times[threshold_vth];
|
double wire_delay = wire_times[threshold_vth] - drvr_times[threshold_vth];
|
||||||
double load_slew = std::abs(wire_times[threshold_vh] - wire_times[threshold_vl]);
|
double load_slew = std::abs(wire_times[threshold_vh] - wire_times[threshold_vl]);
|
||||||
debugPrint(debug_, "ccs_dcalc", 2, "load {} {} delay {} slew {}",
|
debugPrint(debug_, "prima", 2, "load {} {} delay {} slew {}",
|
||||||
network_->pathName(load_pin),
|
network_->pathName(load_pin),
|
||||||
drvr_rf_->shortName(),
|
drvr_rf_->shortName(),
|
||||||
delayAsString(wire_delay, this),
|
delayAsString(wire_delay, this),
|
||||||
|
|
@ -987,7 +991,7 @@ PrimaDelayCalc::primaReduce()
|
||||||
// solve x_init = Vq * x~_init for x~_init
|
// solve x_init = Vq * x~_init for x~_init
|
||||||
xq_init_ = Vq_.colPivHouseholderQr().solve(x_init_);
|
xq_init_ = Vq_.colPivHouseholderQr().solve(x_init_);
|
||||||
|
|
||||||
if (debug_->check("ccs_dcalc", 3)) {
|
if (debug_->check("prima", 3)) {
|
||||||
reportMatrix("Vq", Vq_);
|
reportMatrix("Vq", Vq_);
|
||||||
reportMatrix("G~", Gq_);
|
reportMatrix("G~", Gq_);
|
||||||
reportMatrix("C~", Cq_);
|
reportMatrix("C~", Cq_);
|
||||||
|
|
@ -1050,7 +1054,7 @@ PrimaDelayCalc::primaReduce2()
|
||||||
// solve x_init = Vq * x~_init for x~_init
|
// solve x_init = Vq * x~_init for x~_init
|
||||||
xq_init_ = Vq_.colPivHouseholderQr().solve(x_init_);
|
xq_init_ = Vq_.colPivHouseholderQr().solve(x_init_);
|
||||||
|
|
||||||
if (debug_->check("ccs_dcalc", 3)) {
|
if (debug_->check("prima", 3)) {
|
||||||
reportMatrix("Vq", Vq_);
|
reportMatrix("Vq", Vq_);
|
||||||
reportMatrix("G~", Gq_);
|
reportMatrix("G~", Gq_);
|
||||||
reportMatrix("C~", Cq_);
|
reportMatrix("C~", Cq_);
|
||||||
|
|
|
||||||
|
|
@ -76,11 +76,13 @@ public:
|
||||||
const Pin *drvrPin() const { return drvr_pin_; }
|
const Pin *drvrPin() const { return drvr_pin_; }
|
||||||
Vertex *drvrVertex(const Graph *graph) const;
|
Vertex *drvrVertex(const Graph *graph) const;
|
||||||
LibertyCell *drvrCell() const;
|
LibertyCell *drvrCell() const;
|
||||||
const LibertyLibrary *drvrLibrary() const;
|
LibertyLibrary *drvrLibrary() const;
|
||||||
const RiseFall *drvrEdge() const;
|
const RiseFall *drvrEdge() const;
|
||||||
const Net *drvrNet(const Network *network) const;
|
const Net *drvrNet(const Network *network) const;
|
||||||
Edge *edge() const { return edge_; }
|
Edge *edge() const { return edge_; }
|
||||||
const TimingArc *arc() const { return arc_; }
|
const TimingArc *arc() const { return arc_; }
|
||||||
|
void setSceneArc(const Scene *scene,
|
||||||
|
const MinMax *min_max);
|
||||||
const Slew &inSlew() const { return in_slew_; }
|
const Slew &inSlew() const { return in_slew_; }
|
||||||
float inSlewFlt() const;
|
float inSlewFlt() const;
|
||||||
void setInSlew(Slew in_slew);
|
void setInSlew(Slew in_slew);
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ public:
|
||||||
void writeSpice();
|
void writeSpice();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void initPowerGnd();
|
||||||
void writeHeader();
|
void writeHeader();
|
||||||
void writePrintStmt();
|
void writePrintStmt();
|
||||||
void writeStageInstances();
|
void writeStageInstances();
|
||||||
|
|
@ -150,6 +151,7 @@ private:
|
||||||
using WriteSpice::writeMeasureDelayStmt;
|
using WriteSpice::writeMeasureDelayStmt;
|
||||||
using WriteSpice::writeMeasureSlewStmt;
|
using WriteSpice::writeMeasureSlewStmt;
|
||||||
using WriteSpice::findSlew;
|
using WriteSpice::findSlew;
|
||||||
|
using WriteSpice::initPowerGnd;
|
||||||
};
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
@ -187,7 +189,6 @@ WritePathSpice::WritePathSpice(const Path *path,
|
||||||
path_expanded_(sta),
|
path_expanded_(sta),
|
||||||
written_insts_(network_)
|
written_insts_(network_)
|
||||||
{
|
{
|
||||||
initPowerGnd();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -196,6 +197,8 @@ WritePathSpice::writeSpice()
|
||||||
spice_stream_.open(spice_filename_);
|
spice_stream_.open(spice_filename_);
|
||||||
if (spice_stream_.is_open()) {
|
if (spice_stream_.is_open()) {
|
||||||
path_expanded_.expand(path_, true);
|
path_expanded_.expand(path_, true);
|
||||||
|
|
||||||
|
initPowerGnd();
|
||||||
// Find subckt port names as a side-effect of writeSubckts.
|
// Find subckt port names as a side-effect of writeSubckts.
|
||||||
writeSubckts();
|
writeSubckts();
|
||||||
writeHeader();
|
writeHeader();
|
||||||
|
|
@ -212,6 +215,27 @@ WritePathSpice::writeSpice()
|
||||||
throw FileNotWritable(spice_filename_);
|
throw FileNotWritable(spice_filename_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
WritePathSpice::initPowerGnd()
|
||||||
|
{
|
||||||
|
Scene *scene = path_->scene(this);
|
||||||
|
const MinMax *min_max = path_->minMax(this);
|
||||||
|
LibertyLibrary *threshold_lib = nullptr;
|
||||||
|
for (size_t i = 0; i < path_expanded_.size(); i++) {
|
||||||
|
const Path *path = path_expanded_.path(i);
|
||||||
|
const Pin *pin = path->pin(this);
|
||||||
|
const LibertyPort *port = network_->libertyPort(pin);
|
||||||
|
if (port) {
|
||||||
|
threshold_lib = port->scenePort(scene, min_max)->libertyLibrary();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (threshold_lib)
|
||||||
|
initPowerGnd(threshold_lib);
|
||||||
|
else
|
||||||
|
report_->error(1606, "No instance with Liberty cell found in path.");
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
WritePathSpice::writeHeader()
|
WritePathSpice::writeHeader()
|
||||||
{
|
{
|
||||||
|
|
@ -330,7 +354,7 @@ WritePathSpice::writeInputWaveform()
|
||||||
const TimingArc *next_arc = stageGateArc(input_stage + 1);
|
const TimingArc *next_arc = stageGateArc(input_stage + 1);
|
||||||
float slew0 = findSlew(input_path, rf, next_arc);
|
float slew0 = findSlew(input_path, rf, next_arc);
|
||||||
|
|
||||||
float threshold = default_library_->inputThreshold(rf);
|
float threshold = threshold_library_->inputThreshold(rf);
|
||||||
float dt = railToRailSlew(slew0, rf);
|
float dt = railToRailSlew(slew0, rf);
|
||||||
float time0 = dt * threshold;
|
float time0 = dt * threshold;
|
||||||
|
|
||||||
|
|
@ -518,7 +542,7 @@ WritePathSpice::writeGateStage(Stage stage)
|
||||||
const RiseFall *input_rf = gate_input_path->transition(this);
|
const RiseFall *input_rf = gate_input_path->transition(this);
|
||||||
const Edge *gate_edge = stageGateEdge(stage);
|
const Edge *gate_edge = stageGateEdge(stage);
|
||||||
|
|
||||||
LibertyPortLogicValues port_values;
|
PortLogicValues port_values;
|
||||||
bool is_clked;
|
bool is_clked;
|
||||||
gatePortValues(input_pin, drvr_pin, input_rf, drvr_rf, gate_edge,
|
gatePortValues(input_pin, drvr_pin, input_rf, drvr_rf, gate_edge,
|
||||||
port_values, is_clked);
|
port_values, is_clked);
|
||||||
|
|
|
||||||
|
|
@ -76,17 +76,18 @@ WriteSpice::WriteSpice(std::string_view spice_filename,
|
||||||
ckt_sim_(ckt_sim),
|
ckt_sim_(ckt_sim),
|
||||||
scene_(scene),
|
scene_(scene),
|
||||||
min_max_(min_max),
|
min_max_(min_max),
|
||||||
default_library_(network_->defaultLibertyLibrary()),
|
threshold_library_(nullptr),
|
||||||
bdd_(sta),
|
bdd_(sta),
|
||||||
parasitics_(scene->parasitics(min_max))
|
parasitics_(scene->parasitics(min_max))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
WriteSpice::initPowerGnd()
|
WriteSpice::initPowerGnd(LibertyLibrary *threshold_library)
|
||||||
{
|
{
|
||||||
|
threshold_library_ = threshold_library;
|
||||||
bool exists = false;
|
bool exists = false;
|
||||||
default_library_->supplyVoltage(power_name_, power_voltage_, exists);
|
threshold_library_->supplyVoltage(power_name_, power_voltage_, exists);
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
const OperatingConditions *op_cond =
|
const OperatingConditions *op_cond =
|
||||||
scene_->sdc()->operatingConditions(min_max_);
|
scene_->sdc()->operatingConditions(min_max_);
|
||||||
|
|
@ -94,7 +95,7 @@ WriteSpice::initPowerGnd()
|
||||||
op_cond = network_->defaultLibertyLibrary()->defaultOperatingConditions();
|
op_cond = network_->defaultLibertyLibrary()->defaultOperatingConditions();
|
||||||
power_voltage_ = op_cond->voltage();
|
power_voltage_ = op_cond->voltage();
|
||||||
}
|
}
|
||||||
default_library_->supplyVoltage(gnd_name_, gnd_voltage_, exists);
|
threshold_library_->supplyVoltage(gnd_name_, gnd_voltage_, exists);
|
||||||
if (!exists)
|
if (!exists)
|
||||||
gnd_voltage_ = 0.0;
|
gnd_voltage_ = 0.0;
|
||||||
}
|
}
|
||||||
|
|
@ -309,10 +310,11 @@ WriteSpice::writeSubcktInst(const Instance *inst)
|
||||||
// Power/ground and input voltage sources.
|
// Power/ground and input voltage sources.
|
||||||
void
|
void
|
||||||
WriteSpice::writeSubcktInstVoltSrcs(const Instance *inst,
|
WriteSpice::writeSubcktInstVoltSrcs(const Instance *inst,
|
||||||
LibertyPortLogicValues &port_values,
|
PortLogicValues &port_values,
|
||||||
const PinSet &excluded_input_pins)
|
const PinSet &excluded_input_pins)
|
||||||
{
|
{
|
||||||
LibertyCell *cell = network_->libertyCell(inst);
|
LibertyCell *link_cell = network_->libertyCell(inst);
|
||||||
|
LibertyCell *cell = link_cell->sceneCell(scene_, min_max_);
|
||||||
const std::string &cell_name = cell->name();
|
const std::string &cell_name = cell->name();
|
||||||
StringSeq &spice_port_names = cell_spice_port_names_[cell_name];
|
StringSeq &spice_port_names = cell_spice_port_names_[cell_name];
|
||||||
std::string inst_name = network_->pathName(inst);
|
std::string inst_name = network_->pathName(inst);
|
||||||
|
|
@ -339,7 +341,7 @@ WriteSpice::writeSubcktInstVoltSrcs(const Instance *inst,
|
||||||
if (port_value == LogicValue::unknown) {
|
if (port_value == LogicValue::unknown) {
|
||||||
bool has_value;
|
bool has_value;
|
||||||
LogicValue value;
|
LogicValue value;
|
||||||
findKeyValue(port_values, port, value, has_value);
|
findKeyValue(port_values, port->name(), value, has_value);
|
||||||
if (has_value)
|
if (has_value)
|
||||||
port_value = value;
|
port_value = value;
|
||||||
}
|
}
|
||||||
|
|
@ -732,7 +734,7 @@ WriteSpice::writeWaveformEdge(const RiseFall *rf,
|
||||||
volt0 = power_voltage_;
|
volt0 = power_voltage_;
|
||||||
volt1 = gnd_voltage_;
|
volt1 = gnd_voltage_;
|
||||||
}
|
}
|
||||||
float threshold = default_library_->inputThreshold(rf);
|
float threshold = threshold_library_->inputThreshold(rf);
|
||||||
float dt = railToRailSlew(slew, rf);
|
float dt = railToRailSlew(slew, rf);
|
||||||
float time0 = time - dt * threshold;
|
float time0 = time - dt * threshold;
|
||||||
float time1 = time0 + dt;
|
float time1 = time0 + dt;
|
||||||
|
|
@ -745,8 +747,8 @@ float
|
||||||
WriteSpice::railToRailSlew(float slew,
|
WriteSpice::railToRailSlew(float slew,
|
||||||
const RiseFall *rf)
|
const RiseFall *rf)
|
||||||
{
|
{
|
||||||
float lower = default_library_->slewLowerThreshold(rf);
|
float lower = threshold_library_->slewLowerThreshold(rf);
|
||||||
float upper = default_library_->slewUpperThreshold(rf);
|
float upper = threshold_library_->slewUpperThreshold(rf);
|
||||||
return slew / (upper - lower);
|
return slew / (upper - lower);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -760,7 +762,7 @@ WriteSpice::gatePortValues(const Pin *input_pin,
|
||||||
const RiseFall *drvr_rf,
|
const RiseFall *drvr_rf,
|
||||||
const Edge *gate_edge,
|
const Edge *gate_edge,
|
||||||
// Return values.
|
// Return values.
|
||||||
LibertyPortLogicValues &port_values,
|
PortLogicValues &port_values,
|
||||||
bool &is_clked)
|
bool &is_clked)
|
||||||
{
|
{
|
||||||
is_clked = false;
|
is_clked = false;
|
||||||
|
|
@ -783,7 +785,7 @@ WriteSpice::gatePortValues(const Instance *,
|
||||||
const RiseFall *input_rf,
|
const RiseFall *input_rf,
|
||||||
const RiseFall *drvr_rf,
|
const RiseFall *drvr_rf,
|
||||||
// Return values.
|
// Return values.
|
||||||
LibertyPortLogicValues &port_values)
|
PortLogicValues &port_values)
|
||||||
{
|
{
|
||||||
DdManager *cudd_mgr = bdd_.cuddMgr();
|
DdManager *cudd_mgr = bdd_.cuddMgr();
|
||||||
DdNode *bdd = bdd_.funcBdd(expr);
|
DdNode *bdd = bdd_.funcBdd(expr);
|
||||||
|
|
@ -827,7 +829,7 @@ WriteSpice::gatePortValues(const Instance *,
|
||||||
port_value = LogicValue::unknown;
|
port_value = LogicValue::unknown;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
port_values[port] = port_value;
|
port_values[port->name()] = port_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -844,7 +846,7 @@ WriteSpice::regPortValues(const Pin *input_pin,
|
||||||
const LibertyPort *drvr_port,
|
const LibertyPort *drvr_port,
|
||||||
const FuncExpr *drvr_func,
|
const FuncExpr *drvr_func,
|
||||||
// Return values.
|
// Return values.
|
||||||
LibertyPortLogicValues &port_values,
|
PortLogicValues &port_values,
|
||||||
bool &is_clked)
|
bool &is_clked)
|
||||||
{
|
{
|
||||||
is_clked = false;
|
is_clked = false;
|
||||||
|
|
@ -870,7 +872,7 @@ void
|
||||||
WriteSpice::seqPortValues(Sequential *seq,
|
WriteSpice::seqPortValues(Sequential *seq,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
// Return values.
|
// Return values.
|
||||||
LibertyPortLogicValues &port_values)
|
PortLogicValues &port_values)
|
||||||
{
|
{
|
||||||
FuncExpr *data = seq->data();
|
FuncExpr *data = seq->data();
|
||||||
// SHOULD choose values for all ports of data to make output rise/fall
|
// SHOULD choose values for all ports of data to make output rise/fall
|
||||||
|
|
@ -878,18 +880,19 @@ WriteSpice::seqPortValues(Sequential *seq,
|
||||||
LibertyPort *port = onePort(data);
|
LibertyPort *port = onePort(data);
|
||||||
if (port) {
|
if (port) {
|
||||||
TimingSense sense = data->portTimingSense(port);
|
TimingSense sense = data->portTimingSense(port);
|
||||||
|
const std::string &port_name = port->name();
|
||||||
switch (sense) {
|
switch (sense) {
|
||||||
case TimingSense::positive_unate:
|
case TimingSense::positive_unate:
|
||||||
if (rf == RiseFall::rise())
|
if (rf == RiseFall::rise())
|
||||||
port_values[port] = LogicValue::one;
|
port_values[port_name] = LogicValue::one;
|
||||||
else
|
else
|
||||||
port_values[port] = LogicValue::zero;
|
port_values[port_name] = LogicValue::zero;
|
||||||
break;
|
break;
|
||||||
case TimingSense::negative_unate:
|
case TimingSense::negative_unate:
|
||||||
if (rf == RiseFall::rise())
|
if (rf == RiseFall::rise())
|
||||||
port_values[port] = LogicValue::zero;
|
port_values[port_name] = LogicValue::zero;
|
||||||
else
|
else
|
||||||
port_values[port] = LogicValue::one;
|
port_values[port_name] = LogicValue::one;
|
||||||
break;
|
break;
|
||||||
case TimingSense::non_unate:
|
case TimingSense::non_unate:
|
||||||
case TimingSense::none:
|
case TimingSense::none:
|
||||||
|
|
@ -954,7 +957,7 @@ WriteSpice::writeSubcktInstLoads(const Pin *drvr_pin,
|
||||||
sta::print(spice_stream_, "* Load pins\n");
|
sta::print(spice_stream_, "* Load pins\n");
|
||||||
PinSeq drvr_loads = drvrLoads(drvr_pin);
|
PinSeq drvr_loads = drvrLoads(drvr_pin);
|
||||||
// Do not sensitize side load gates.
|
// Do not sensitize side load gates.
|
||||||
LibertyPortLogicValues port_values;
|
PortLogicValues port_values;
|
||||||
for (const Pin *load_pin : drvr_loads) {
|
for (const Pin *load_pin : drvr_loads) {
|
||||||
const Instance *load_inst = network_->instance(load_pin);
|
const Instance *load_inst = network_->instance(load_pin);
|
||||||
if (load_pin != path_load && network_->direction(load_pin)->isAnyInput()
|
if (load_pin != path_load && network_->direction(load_pin)->isAnyInput()
|
||||||
|
|
@ -978,9 +981,9 @@ WriteSpice::writeMeasureDelayStmt(const Pin *from_pin,
|
||||||
std::string_view prefix)
|
std::string_view prefix)
|
||||||
{
|
{
|
||||||
std::string from_pin_name = network_->pathName(from_pin);
|
std::string from_pin_name = network_->pathName(from_pin);
|
||||||
float from_threshold = power_voltage_ * default_library_->inputThreshold(from_rf);
|
float from_threshold = power_voltage_ * threshold_library_->inputThreshold(from_rf);
|
||||||
std::string to_pin_name = network_->pathName(to_pin);
|
std::string to_pin_name = network_->pathName(to_pin);
|
||||||
float to_threshold = power_voltage_ * default_library_->inputThreshold(to_rf);
|
float to_threshold = power_voltage_ * threshold_library_->inputThreshold(to_rf);
|
||||||
sta::print(spice_stream_, ".measure tran {}_{}_delay_{}\n", prefix,
|
sta::print(spice_stream_, ".measure tran {}_{}_delay_{}\n", prefix,
|
||||||
from_pin_name, to_pin_name);
|
from_pin_name, to_pin_name);
|
||||||
sta::print(spice_stream_, "+trig v({}) val={:.3f} {}=last\n", from_pin_name,
|
sta::print(spice_stream_, "+trig v({}) val={:.3f} {}=last\n", from_pin_name,
|
||||||
|
|
@ -996,8 +999,8 @@ WriteSpice::writeMeasureSlewStmt(const Pin *pin,
|
||||||
{
|
{
|
||||||
std::string pin_name = network_->pathName(pin);
|
std::string pin_name = network_->pathName(pin);
|
||||||
std::string_view spice_rf = spiceTrans(rf);
|
std::string_view spice_rf = spiceTrans(rf);
|
||||||
float lower = power_voltage_ * default_library_->slewLowerThreshold(rf);
|
float lower = power_voltage_ * threshold_library_->slewLowerThreshold(rf);
|
||||||
float upper = power_voltage_ * default_library_->slewUpperThreshold(rf);
|
float upper = power_voltage_ * threshold_library_->slewUpperThreshold(rf);
|
||||||
float threshold1, threshold2;
|
float threshold1, threshold2;
|
||||||
if (rf == RiseFall::rise()) {
|
if (rf == RiseFall::rise()) {
|
||||||
threshold1 = lower;
|
threshold1 = lower;
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,8 @@ namespace sta {
|
||||||
|
|
||||||
using ParasiticNodeMap = std::map<const ParasiticNode*, int>;
|
using ParasiticNodeMap = std::map<const ParasiticNode*, int>;
|
||||||
using CellSpicePortNames = std::map<std::string, StringSeq, std::less<>>;
|
using CellSpicePortNames = std::map<std::string, StringSeq, std::less<>>;
|
||||||
using LibertyPortLogicValues = std::map<const LibertyPort*, LogicValue>;
|
// Use port name so lookup works across scenes.
|
||||||
|
using PortLogicValues = std::map<std::string, LogicValue>;
|
||||||
|
|
||||||
// Utilities for writing a spice deck.
|
// Utilities for writing a spice deck.
|
||||||
class WriteSpice : public StaState
|
class WriteSpice : public StaState
|
||||||
|
|
@ -61,7 +62,7 @@ public:
|
||||||
const StaState *sta);
|
const StaState *sta);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void initPowerGnd();
|
void initPowerGnd(LibertyLibrary *threshold_library);
|
||||||
void writeHeader(std::string &title,
|
void writeHeader(std::string &title,
|
||||||
float max_time,
|
float max_time,
|
||||||
float time_step);
|
float time_step);
|
||||||
|
|
@ -73,7 +74,7 @@ protected:
|
||||||
StringSeq &tokens);
|
StringSeq &tokens);
|
||||||
void writeSubcktInst(const Instance *inst);
|
void writeSubcktInst(const Instance *inst);
|
||||||
void writeSubcktInstVoltSrcs(const Instance *inst,
|
void writeSubcktInstVoltSrcs(const Instance *inst,
|
||||||
LibertyPortLogicValues &port_values,
|
PortLogicValues &port_values,
|
||||||
const PinSet &excluded_input_pins);
|
const PinSet &excluded_input_pins);
|
||||||
float pgPortVoltage(const LibertyPort *pg_port);
|
float pgPortVoltage(const LibertyPort *pg_port);
|
||||||
void writeVoltageSource(std::string_view inst_name,
|
void writeVoltageSource(std::string_view inst_name,
|
||||||
|
|
@ -120,7 +121,7 @@ protected:
|
||||||
void seqPortValues(Sequential *seq,
|
void seqPortValues(Sequential *seq,
|
||||||
const RiseFall *rf,
|
const RiseFall *rf,
|
||||||
// Return values.
|
// Return values.
|
||||||
LibertyPortLogicValues &port_values);
|
PortLogicValues &port_values);
|
||||||
LibertyPort *onePort(FuncExpr *expr);
|
LibertyPort *onePort(FuncExpr *expr);
|
||||||
void writeMeasureDelayStmt(const Pin *from_pin,
|
void writeMeasureDelayStmt(const Pin *from_pin,
|
||||||
const RiseFall *from_rf,
|
const RiseFall *from_rf,
|
||||||
|
|
@ -143,14 +144,14 @@ protected:
|
||||||
const RiseFall *drvr_rf,
|
const RiseFall *drvr_rf,
|
||||||
const Edge *gate_edge,
|
const Edge *gate_edge,
|
||||||
// Return values.
|
// Return values.
|
||||||
LibertyPortLogicValues &port_values,
|
PortLogicValues &port_values,
|
||||||
bool &is_clked);
|
bool &is_clked);
|
||||||
void regPortValues(const Pin *input_pin,
|
void regPortValues(const Pin *input_pin,
|
||||||
const RiseFall *drvr_rf,
|
const RiseFall *drvr_rf,
|
||||||
const LibertyPort *drvr_port,
|
const LibertyPort *drvr_port,
|
||||||
const FuncExpr *drvr_func,
|
const FuncExpr *drvr_func,
|
||||||
// Return values.
|
// Return values.
|
||||||
LibertyPortLogicValues &port_values,
|
PortLogicValues &port_values,
|
||||||
bool &is_clked);
|
bool &is_clked);
|
||||||
void gatePortValues(const Instance *inst,
|
void gatePortValues(const Instance *inst,
|
||||||
const FuncExpr *expr,
|
const FuncExpr *expr,
|
||||||
|
|
@ -158,7 +159,7 @@ protected:
|
||||||
const RiseFall *input_rf,
|
const RiseFall *input_rf,
|
||||||
const RiseFall *drvr_rf,
|
const RiseFall *drvr_rf,
|
||||||
// Return values.
|
// Return values.
|
||||||
LibertyPortLogicValues &port_values);
|
PortLogicValues &port_values);
|
||||||
void writeSubcktInstLoads(const Pin *drvr_pin,
|
void writeSubcktInstLoads(const Pin *drvr_pin,
|
||||||
const Pin *path_load,
|
const Pin *path_load,
|
||||||
const PinSet &excluded_input_pins,
|
const PinSet &excluded_input_pins,
|
||||||
|
|
@ -179,7 +180,7 @@ protected:
|
||||||
const MinMax *min_max_;
|
const MinMax *min_max_;
|
||||||
|
|
||||||
std::ofstream spice_stream_;
|
std::ofstream spice_stream_;
|
||||||
LibertyLibrary *default_library_;
|
LibertyLibrary *threshold_library_;
|
||||||
float power_voltage_;
|
float power_voltage_;
|
||||||
float gnd_voltage_;
|
float gnd_voltage_;
|
||||||
float max_time_;
|
float max_time_;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue