diff --git a/dcalc/ArcDcalcWaveforms.cc b/dcalc/ArcDcalcWaveforms.cc index 184607e6..61513e33 100644 --- a/dcalc/ArcDcalcWaveforms.cc +++ b/dcalc/ArcDcalcWaveforms.cc @@ -45,8 +45,9 @@ ArcDcalcWaveforms::inputWaveform(ArcDcalcArg &dcalc_arg, Graph *graph = sta->graph(); Report *report = sta->report(); const Pin *in_pin = dcalc_arg.inPin(); - LibertyPort *port = network->libertyPort(in_pin); - if (port) { + LibertyPort *link_port = network->libertyPort(in_pin); + if (link_port) { + LibertyPort *port = link_port->scenePort(scene, min_max); const RiseFall *in_rf = dcalc_arg.inEdge(); DriverWaveform *driver_waveform = port->driverWaveform(in_rf); if (driver_waveform) { diff --git a/dcalc/ArcDelayCalc.cc b/dcalc/ArcDelayCalc.cc index b615ca47..ecbd1655 100644 --- a/dcalc/ArcDelayCalc.cc +++ b/dcalc/ArcDelayCalc.cc @@ -186,7 +186,7 @@ ArcDcalcArg::drvrCell() const return arc_->to()->libertyCell(); } -const LibertyLibrary * +LibertyLibrary * ArcDcalcArg::drvrLibrary() const { return arc_->to()->libertyLibrary(); @@ -198,6 +198,13 @@ ArcDcalcArg::drvrEdge() const return arc_->toEdge()->asRiseFall(); } +void +ArcDcalcArg::setSceneArc(const Scene *scene, + const MinMax *min_max) +{ + arc_ = arc_->sceneArc(scene->libertyIndex(min_max)); +} + const Net * ArcDcalcArg::drvrNet(const Network *network) const { diff --git a/dcalc/DelayCalcBase.cc b/dcalc/DelayCalcBase.cc index 214aec7d..ed6566b5 100644 --- a/dcalc/DelayCalcBase.cc +++ b/dcalc/DelayCalcBase.cc @@ -227,6 +227,7 @@ DelayCalcBase::setDcalcArgParasiticSlew(ArcDcalcArg &gate, gate.edge(), scene, min_max); gate.setInSlew(in_slew); + gate.setSceneArc(scene, min_max); } } diff --git a/dcalc/PrimaDelayCalc.cc b/dcalc/PrimaDelayCalc.cc index db30ef1f..a5ea608c 100644 --- a/dcalc/PrimaDelayCalc.cc +++ b/dcalc/PrimaDelayCalc.cc @@ -183,6 +183,7 @@ PrimaDelayCalc::gateDelay(const Pin *drvr_pin, ArcDcalcArgSeq dcalc_args; dcalc_args.emplace_back(nullptr, drvr_pin, nullptr, arc, in_slew, load_cap, parasitic); + dcalc_args[0].setSceneArc(scene, min_max); ArcDcalcResultSeq dcalc_results = gateDelays(dcalc_args, load_pin_index_map, scene, min_max); return dcalc_results[0]; @@ -256,9 +257,10 @@ PrimaDelayCalc::checkArgs(ArcDcalcArgSeq &dcalc_args, if (output_waveforms->slewAxis()->inBounds(in_slew)) { if (output_waveforms->capAxis()->inBounds(dcalc_arg.loadCap())) { output_waveforms_[drvr_idx] = output_waveforms; - debugPrint(debug_, "prima", 1, "{} {}", + debugPrint(debug_, "prima", 1, "{} {} {}", 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(); drvr_cell->ensureVoltageWaveforms(scenes_); } @@ -362,7 +364,7 @@ PrimaDelayCalc::simulate1(const MatrixSd &G, v_ = v_prev_ = x_to_v * x_init; time_step_ = time_step_prev_ = timeStep(); - debugPrint(debug_, "ccs_dcalc", 1, "time step {}", + debugPrint(debug_, "prima", 1, "time step {}", delayAsString(time_step_, this)); MatrixSd A(order, order); @@ -402,7 +404,7 @@ PrimaDelayCalc::simulate1(const MatrixSd &G, v_ = x_to_v * x; 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), units_->capacitanceUnit()->asString(ceff_[0]), voltage(dcalc_arg.drvrPin()), @@ -427,7 +429,7 @@ PrimaDelayCalc::simulate1(const MatrixSd &G, double PrimaDelayCalc::timeStep() { - // Needs to use LTE for time step dynamic control. + // Should use LTE for dynamic time step control. return driverResistance() * load_cap_ * .02; } @@ -443,7 +445,8 @@ PrimaDelayCalc::driverResistance() { const Pin *drvr_pin = (*dcalc_args_)[0].drvrPin(); 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 @@ -526,7 +529,7 @@ PrimaDelayCalc::placeNode(ParasiticNode *node, const Pin *pin = parasitics_->pin(node); if (pin) { pin_node_map_[pin] = index; - debugPrint(debug_, "ccs_dcalc", 1, "pin {} node {}", + debugPrint(debug_, "prima", 1, "pin {} node {}", 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("C", C_); reportMatrix("B", B_); @@ -834,7 +837,8 @@ PrimaDelayCalc::measureThresholds(double time) if ((v_prev < th && th <= v) || (v_prev > th && th >= v)) { double t_cross = 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)); threshold_times_[node_idx][m] = t_cross; } @@ -882,7 +886,7 @@ PrimaDelayCalc::dcalcResults() dcalc_result.setGateDelay(gate_delay2); 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), delayAsString(drvr_slew, this)); @@ -895,7 +899,7 @@ PrimaDelayCalc::dcalcResults() ThresholdTimes &drvr_times = threshold_times_[drvr_node]; double wire_delay = wire_times[threshold_vth] - drvr_times[threshold_vth]; 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), drvr_rf_->shortName(), delayAsString(wire_delay, this), @@ -987,7 +991,7 @@ PrimaDelayCalc::primaReduce() // solve x_init = Vq * x~_init for x~_init xq_init_ = Vq_.colPivHouseholderQr().solve(x_init_); - if (debug_->check("ccs_dcalc", 3)) { + if (debug_->check("prima", 3)) { reportMatrix("Vq", Vq_); reportMatrix("G~", Gq_); reportMatrix("C~", Cq_); @@ -1050,7 +1054,7 @@ PrimaDelayCalc::primaReduce2() // solve x_init = Vq * x~_init for x~_init xq_init_ = Vq_.colPivHouseholderQr().solve(x_init_); - if (debug_->check("ccs_dcalc", 3)) { + if (debug_->check("prima", 3)) { reportMatrix("Vq", Vq_); reportMatrix("G~", Gq_); reportMatrix("C~", Cq_); diff --git a/include/sta/ArcDelayCalc.hh b/include/sta/ArcDelayCalc.hh index eacad445..d2bf03af 100644 --- a/include/sta/ArcDelayCalc.hh +++ b/include/sta/ArcDelayCalc.hh @@ -76,11 +76,13 @@ public: const Pin *drvrPin() const { return drvr_pin_; } Vertex *drvrVertex(const Graph *graph) const; LibertyCell *drvrCell() const; - const LibertyLibrary *drvrLibrary() const; + LibertyLibrary *drvrLibrary() const; const RiseFall *drvrEdge() const; const Net *drvrNet(const Network *network) const; Edge *edge() const { return edge_; } const TimingArc *arc() const { return arc_; } + void setSceneArc(const Scene *scene, + const MinMax *min_max); const Slew &inSlew() const { return in_slew_; } float inSlewFlt() const; void setInSlew(Slew in_slew); diff --git a/spice/WritePathSpice.cc b/spice/WritePathSpice.cc index d98e2fd6..7a8973dc 100644 --- a/spice/WritePathSpice.cc +++ b/spice/WritePathSpice.cc @@ -72,6 +72,7 @@ public: void writeSpice(); private: + void initPowerGnd(); void writeHeader(); void writePrintStmt(); void writeStageInstances(); @@ -150,6 +151,7 @@ private: using WriteSpice::writeMeasureDelayStmt; using WriteSpice::writeMeasureSlewStmt; using WriteSpice::findSlew; + using WriteSpice::initPowerGnd; }; //////////////////////////////////////////////////////////////// @@ -187,7 +189,6 @@ WritePathSpice::WritePathSpice(const Path *path, path_expanded_(sta), written_insts_(network_) { - initPowerGnd(); } void @@ -196,6 +197,8 @@ WritePathSpice::writeSpice() spice_stream_.open(spice_filename_); if (spice_stream_.is_open()) { path_expanded_.expand(path_, true); + + initPowerGnd(); // Find subckt port names as a side-effect of writeSubckts. writeSubckts(); writeHeader(); @@ -212,6 +215,27 @@ WritePathSpice::writeSpice() 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 WritePathSpice::writeHeader() { @@ -330,7 +354,7 @@ WritePathSpice::writeInputWaveform() const TimingArc *next_arc = stageGateArc(input_stage + 1); 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 time0 = dt * threshold; @@ -518,7 +542,7 @@ WritePathSpice::writeGateStage(Stage stage) const RiseFall *input_rf = gate_input_path->transition(this); const Edge *gate_edge = stageGateEdge(stage); - LibertyPortLogicValues port_values; + PortLogicValues port_values; bool is_clked; gatePortValues(input_pin, drvr_pin, input_rf, drvr_rf, gate_edge, port_values, is_clked); diff --git a/spice/WriteSpice.cc b/spice/WriteSpice.cc index c08039b6..e3aafb53 100644 --- a/spice/WriteSpice.cc +++ b/spice/WriteSpice.cc @@ -76,17 +76,18 @@ WriteSpice::WriteSpice(std::string_view spice_filename, ckt_sim_(ckt_sim), scene_(scene), min_max_(min_max), - default_library_(network_->defaultLibertyLibrary()), + threshold_library_(nullptr), bdd_(sta), parasitics_(scene->parasitics(min_max)) { } void -WriteSpice::initPowerGnd() +WriteSpice::initPowerGnd(LibertyLibrary *threshold_library) { + threshold_library_ = threshold_library; bool exists = false; - default_library_->supplyVoltage(power_name_, power_voltage_, exists); + threshold_library_->supplyVoltage(power_name_, power_voltage_, exists); if (!exists) { const OperatingConditions *op_cond = scene_->sdc()->operatingConditions(min_max_); @@ -94,7 +95,7 @@ WriteSpice::initPowerGnd() op_cond = network_->defaultLibertyLibrary()->defaultOperatingConditions(); power_voltage_ = op_cond->voltage(); } - default_library_->supplyVoltage(gnd_name_, gnd_voltage_, exists); + threshold_library_->supplyVoltage(gnd_name_, gnd_voltage_, exists); if (!exists) gnd_voltage_ = 0.0; } @@ -309,10 +310,11 @@ WriteSpice::writeSubcktInst(const Instance *inst) // Power/ground and input voltage sources. void WriteSpice::writeSubcktInstVoltSrcs(const Instance *inst, - LibertyPortLogicValues &port_values, + PortLogicValues &port_values, 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(); StringSeq &spice_port_names = cell_spice_port_names_[cell_name]; std::string inst_name = network_->pathName(inst); @@ -339,7 +341,7 @@ WriteSpice::writeSubcktInstVoltSrcs(const Instance *inst, if (port_value == LogicValue::unknown) { bool has_value; LogicValue value; - findKeyValue(port_values, port, value, has_value); + findKeyValue(port_values, port->name(), value, has_value); if (has_value) port_value = value; } @@ -732,7 +734,7 @@ WriteSpice::writeWaveformEdge(const RiseFall *rf, volt0 = power_voltage_; volt1 = gnd_voltage_; } - float threshold = default_library_->inputThreshold(rf); + float threshold = threshold_library_->inputThreshold(rf); float dt = railToRailSlew(slew, rf); float time0 = time - dt * threshold; float time1 = time0 + dt; @@ -745,8 +747,8 @@ float WriteSpice::railToRailSlew(float slew, const RiseFall *rf) { - float lower = default_library_->slewLowerThreshold(rf); - float upper = default_library_->slewUpperThreshold(rf); + float lower = threshold_library_->slewLowerThreshold(rf); + float upper = threshold_library_->slewUpperThreshold(rf); return slew / (upper - lower); } @@ -760,7 +762,7 @@ WriteSpice::gatePortValues(const Pin *input_pin, const RiseFall *drvr_rf, const Edge *gate_edge, // Return values. - LibertyPortLogicValues &port_values, + PortLogicValues &port_values, bool &is_clked) { is_clked = false; @@ -783,7 +785,7 @@ WriteSpice::gatePortValues(const Instance *, const RiseFall *input_rf, const RiseFall *drvr_rf, // Return values. - LibertyPortLogicValues &port_values) + PortLogicValues &port_values) { DdManager *cudd_mgr = bdd_.cuddMgr(); DdNode *bdd = bdd_.funcBdd(expr); @@ -827,7 +829,7 @@ WriteSpice::gatePortValues(const Instance *, port_value = LogicValue::unknown; 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 FuncExpr *drvr_func, // Return values. - LibertyPortLogicValues &port_values, + PortLogicValues &port_values, bool &is_clked) { is_clked = false; @@ -870,7 +872,7 @@ void WriteSpice::seqPortValues(Sequential *seq, const RiseFall *rf, // Return values. - LibertyPortLogicValues &port_values) + PortLogicValues &port_values) { FuncExpr *data = seq->data(); // 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); if (port) { TimingSense sense = data->portTimingSense(port); + const std::string &port_name = port->name(); switch (sense) { case TimingSense::positive_unate: if (rf == RiseFall::rise()) - port_values[port] = LogicValue::one; + port_values[port_name] = LogicValue::one; else - port_values[port] = LogicValue::zero; + port_values[port_name] = LogicValue::zero; break; case TimingSense::negative_unate: if (rf == RiseFall::rise()) - port_values[port] = LogicValue::zero; + port_values[port_name] = LogicValue::zero; else - port_values[port] = LogicValue::one; + port_values[port_name] = LogicValue::one; break; case TimingSense::non_unate: case TimingSense::none: @@ -954,7 +957,7 @@ WriteSpice::writeSubcktInstLoads(const Pin *drvr_pin, sta::print(spice_stream_, "* Load pins\n"); PinSeq drvr_loads = drvrLoads(drvr_pin); // Do not sensitize side load gates. - LibertyPortLogicValues port_values; + PortLogicValues port_values; for (const Pin *load_pin : drvr_loads) { const Instance *load_inst = network_->instance(load_pin); 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 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); - 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, from_pin_name, to_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_view spice_rf = spiceTrans(rf); - float lower = power_voltage_ * default_library_->slewLowerThreshold(rf); - float upper = power_voltage_ * default_library_->slewUpperThreshold(rf); + float lower = power_voltage_ * threshold_library_->slewLowerThreshold(rf); + float upper = power_voltage_ * threshold_library_->slewUpperThreshold(rf); float threshold1, threshold2; if (rf == RiseFall::rise()) { threshold1 = lower; diff --git a/spice/WriteSpice.hh b/spice/WriteSpice.hh index b44e6c52..b1349d15 100644 --- a/spice/WriteSpice.hh +++ b/spice/WriteSpice.hh @@ -43,7 +43,8 @@ namespace sta { using ParasiticNodeMap = std::map; using CellSpicePortNames = std::map>; -using LibertyPortLogicValues = std::map; +// Use port name so lookup works across scenes. +using PortLogicValues = std::map; // Utilities for writing a spice deck. class WriteSpice : public StaState @@ -61,7 +62,7 @@ public: const StaState *sta); protected: - void initPowerGnd(); + void initPowerGnd(LibertyLibrary *threshold_library); void writeHeader(std::string &title, float max_time, float time_step); @@ -73,7 +74,7 @@ protected: StringSeq &tokens); void writeSubcktInst(const Instance *inst); void writeSubcktInstVoltSrcs(const Instance *inst, - LibertyPortLogicValues &port_values, + PortLogicValues &port_values, const PinSet &excluded_input_pins); float pgPortVoltage(const LibertyPort *pg_port); void writeVoltageSource(std::string_view inst_name, @@ -120,7 +121,7 @@ protected: void seqPortValues(Sequential *seq, const RiseFall *rf, // Return values. - LibertyPortLogicValues &port_values); + PortLogicValues &port_values); LibertyPort *onePort(FuncExpr *expr); void writeMeasureDelayStmt(const Pin *from_pin, const RiseFall *from_rf, @@ -143,14 +144,14 @@ protected: const RiseFall *drvr_rf, const Edge *gate_edge, // Return values. - LibertyPortLogicValues &port_values, + PortLogicValues &port_values, bool &is_clked); void regPortValues(const Pin *input_pin, const RiseFall *drvr_rf, const LibertyPort *drvr_port, const FuncExpr *drvr_func, // Return values. - LibertyPortLogicValues &port_values, + PortLogicValues &port_values, bool &is_clked); void gatePortValues(const Instance *inst, const FuncExpr *expr, @@ -158,7 +159,7 @@ protected: const RiseFall *input_rf, const RiseFall *drvr_rf, // Return values. - LibertyPortLogicValues &port_values); + PortLogicValues &port_values); void writeSubcktInstLoads(const Pin *drvr_pin, const Pin *path_load, const PinSet &excluded_input_pins, @@ -179,7 +180,7 @@ protected: const MinMax *min_max_; std::ofstream spice_stream_; - LibertyLibrary *default_library_; + LibertyLibrary *threshold_library_; float power_voltage_; float gnd_voltage_; float max_time_;