diff --git a/include/sta/TableModel.hh b/include/sta/TableModel.hh index ca75d838..33d92236 100644 --- a/include/sta/TableModel.hh +++ b/include/sta/TableModel.hh @@ -507,12 +507,19 @@ public: const RiseFall *rf() const { return rf_; } Table1 voltageWaveform(float in_slew, float load_cap); - Table1 currentWaveform(float slew, - float cap); + float timeToVoltage(float in_slew, + float load_cap, + float voltage); + const Table1 *currentWaveform(float slew, + float cap); float referenceTime(float slew); static bool checkAxes(TableTemplate *tbl_template); private: + float timeToVoltage(const Table1 *waveform, + float voltage); + size_t findValueIndex(const Table1 *table, + float value); Table1 *voltageWaveform(size_t wave_index, float cap); diff --git a/liberty/TableModel.cc b/liberty/TableModel.cc index 397ae233..7c97e66d 100644 --- a/liberty/TableModel.cc +++ b/liberty/TableModel.cc @@ -1615,43 +1615,95 @@ OutputWaveforms::checkAxes(TableTemplate *tbl_template) && axis3->variable() == TableAxisVariable::time); } -Table1 -OutputWaveforms::voltageWaveform(float slew, +const Table1 * +OutputWaveforms::currentWaveform(float slew, float cap) { size_t slew_index = slew_axis_->findAxisIndex(slew); size_t cap_index = cap_axis_->findAxisIndex(cap); - size_t wave_index00 = slew_index * slew_axis_->size() + cap_index; - size_t wave_index01 = slew_index * slew_axis_->size() + (cap_index + 1); - size_t wave_index10 = (slew_index + 1) * slew_axis_->size() + cap_index; - size_t wave_index11 = (slew_index + 1) * slew_axis_->size() + (cap_index + 1); + size_t wave_index = slew_index * cap_axis_->size() + cap_index; + return current_waveforms_[wave_index]; +} + +float +OutputWaveforms::referenceTime(float slew) +{ + return ref_times_->findValue(slew); +} + +float +OutputWaveforms::timeToVoltage(float slew, + float cap, + float volt) +{ + size_t slew_index = slew_axis_->findAxisIndex(slew); + size_t cap_index = cap_axis_->findAxisIndex(cap); + size_t slew_count = slew_axis_->size(); + size_t wave_index00 = slew_index * slew_count + cap_index; + size_t wave_index01 = slew_index * slew_count + (cap_index + 1); + size_t wave_index10 = (slew_index + 1) * slew_count + cap_index; + size_t wave_index11 = (slew_index + 1) * slew_count + (cap_index + 1); float cap0 = cap_axis_->axisValue(cap_index); float cap1 = cap_axis_->axisValue(cap_index + 1); const Table1 *values00 = voltageWaveform(wave_index00, cap0); const Table1 *values01 = voltageWaveform(wave_index01, cap1); const Table1 *values10 = voltageWaveform(wave_index10, cap0); const Table1 *values11 = voltageWaveform(wave_index11, cap1); - TableAxisPtr time_axis00 = values00->axis1(); - TableAxisPtr time_axis01 = values01->axis1(); - TableAxisPtr time_axis10 = values10->axis1(); - TableAxisPtr time_axis11 = values11->axis1(); - // Find time axis min/max. - size_t time_step_count = 20; - float time_min = time_axis00->min(); - time_min = min(time_min, time_axis01->min()); - time_min = min(time_min, time_axis10->min()); - time_min = min(time_min, time_axis11->min()); - float time_max = time_axis00->max(); - time_max = max(time_max, time_axis01->max()); - time_max = max(time_max, time_axis10->max()); - time_max = max(time_max, time_axis11->max()); - float time_step = (time_max - time_min) / time_step_count; + TableAxisPtr time_axis00 = values00->axis1(); + + // Interpolate waveform samples at voltage steps. + size_t index1 = slew_index; + size_t index2 = cap_index; + float x1 = slew; + float x2 = cap; + float x1l = slew_axis_->axisValue(index1); + float x1u = slew_axis_->axisValue(index1 + 1); + float dx1 = (x1 - x1l) / (x1u - x1l); + float x2l = cap_axis_->axisValue(index2); + float x2u = cap_axis_->axisValue(index2 + 1); + float dx2 = (x2 - x2l) / (x2u - x2l); + + float y00 = timeToVoltage(values00, volt); + float y01 = timeToVoltage(values01, volt); + float y10 = timeToVoltage(values10, volt); + float y11 = timeToVoltage(values11, volt); + float time + = (1 - dx1) * (1 - dx2) * y00 + + dx1 * (1 - dx2) * y10 + + dx1 * dx2 * y11 + + (1 - dx1) * dx2 * y01; + return time; +} + +Table1 +OutputWaveforms::voltageWaveform(float slew, + float cap) +{ + size_t slew_index = slew_axis_->findAxisIndex(slew); + size_t cap_index = cap_axis_->findAxisIndex(cap); + size_t slew_count = slew_axis_->size(); + size_t wave_index00 = slew_index * slew_count + cap_index; + size_t wave_index01 = slew_index * slew_count + (cap_index + 1); + size_t wave_index10 = (slew_index + 1) * slew_count + cap_index; + size_t wave_index11 = (slew_index + 1) * slew_count + (cap_index + 1); + float cap0 = cap_axis_->axisValue(cap_index); + float cap1 = cap_axis_->axisValue(cap_index + 1); + const Table1 *values00 = voltageWaveform(wave_index00, cap0); + const Table1 *values01 = voltageWaveform(wave_index01, cap1); + const Table1 *values10 = voltageWaveform(wave_index10, cap0); + const Table1 *values11 = voltageWaveform(wave_index11, cap1); + + TableAxisPtr time_axis00 = values00->axis1(); + + size_t volt_step_count = 20; + float volt_max = values00->value(time_axis00->size() - 1); + float volt_step = volt_max / volt_step_count; FloatSeq *time_values = new FloatSeq; TableAxisPtr time_axis = make_shared(time_axis00->variable(), time_values); - // Interpolate waveform samples at time steps. + // Interpolate waveform samples at voltage steps. size_t index1 = slew_index; size_t index2 = cap_index; float x1 = slew; @@ -1663,30 +1715,77 @@ OutputWaveforms::voltageWaveform(float slew, float x2u = cap_axis_->axisValue(index2 + 1); float dx2 = (x2 - x2l) / (x2u - x2l); FloatSeq *values = new FloatSeq; - float prev_value = 0.0; - constexpr float value_tol = .0001; - for (size_t i = 0; i <= time_step_count; i++) { - float time = time_min + time_step * i; - if (time > time_max) - break; - float y00 = values00->findValueClip(time); - float y10 = values10->findValueClip(time); - float y11 = values11->findValueClip(time); - float y01 = values01->findValueClip(time); - float value + float prev_time = 0.0; + for (size_t i = 0; i <= volt_step_count; i++) { + float volt = volt_step * i; + + float y00 = timeToVoltage(values00, volt); + float y01 = timeToVoltage(values01, volt); + float y10 = timeToVoltage(values10, volt); + float y11 = timeToVoltage(values11, volt); + float time = (1 - dx1) * (1 - dx2) * y00 + dx1 * (1 - dx2) * y10 + dx1 * dx2 * y11 + (1 - dx1) * dx2 * y01; - if (i == 0 || abs(value - prev_value) > value_tol) { + if (i == 0 || time > prev_time) { time_values->push_back(time); - values->push_back(value); + values->push_back(volt); } - prev_value = value; + prev_time = time; } return Table1(values, time_axis); } +float +OutputWaveforms::timeToVoltage(const Table1 *waveform, + float voltage) +{ + size_t index1 = findValueIndex(waveform, voltage); + TableAxisPtr axis = waveform->axis1(); + float axis_value1 = axis->axisValue(index1); + float axis_value2 = axis->axisValue(index1 + 1); + + float x1 = voltage; + float x1l = waveform->value(index1); + float x1u = waveform->value(index1 + 1); + float y1 = axis_value1; + float y2 = axis_value2; + float dx1 = (x1 - x1l) / (x1u - x1l); + return (1 - dx1) * y1 + dx1 * y2; +} + +// Bisection search. +// Assumes monotonic table entries +// Copies TableAxis::findAxisIndex. +size_t +OutputWaveforms::findValueIndex(const Table1 *table, + float value) +{ + FloatSeq *values_ = table->values(); + int index_max = static_cast(values_->size()) - 1; + if (value <= (*values_)[0] || index_max == 0) + return 0; + else if (value >= (*values_)[index_max]) + // Return max-1 for value too large so interpolation pts are index,index+1. + return index_max - 1; + else { + int lower = -1; + int upper = index_max + 1; + bool ascend = ((*values_)[index_max] >= (*values_)[0]); + while (upper - lower > 1) { + int mid = (upper + lower) / 2; + if ((value >= (*values_)[mid]) == ascend) + lower = mid; + else + upper = mid; + } + return lower; + } +} + +// Integrate current waveform to find voltage waveform. +// i = C dv/dt Table1 * OutputWaveforms::voltageWaveform(size_t wave_index, float cap) @@ -1698,8 +1797,6 @@ OutputWaveforms::voltageWaveform(size_t wave_index, voltages = new Table1(voltages1, currents->axis1()); voltage_waveforms_[wave_index] = voltages; - // i = C dv/dt - // Integrate current waveform to find voltage waveform. TableAxisPtr time_axis = currents->axis1(); float prev_time = time_axis->axisValue(0); float prev_current = currents->value(0); @@ -1724,82 +1821,6 @@ OutputWaveforms::voltageWaveform(size_t wave_index, return voltages; } -Table1 -OutputWaveforms::currentWaveform(float slew, - float cap) -{ - size_t slew_index = slew_axis_->findAxisIndex(slew); - size_t cap_index = cap_axis_->findAxisIndex(cap); - size_t wave_index00 = slew_index * slew_axis_->size() + cap_index; - size_t wave_index01 = slew_index * slew_axis_->size() + (cap_index + 1); - size_t wave_index10 = (slew_index + 1) * slew_axis_->size() + cap_index; - size_t wave_index11 = (slew_index + 1) * slew_axis_->size() + (cap_index + 1); - const Table1 *values00 = current_waveforms_[wave_index00]; - const Table1 *values01 = current_waveforms_[wave_index01]; - const Table1 *values10 = current_waveforms_[wave_index10]; - const Table1 *values11 = current_waveforms_[wave_index11]; - TableAxisPtr time_axis00 = values00->axis1(); - TableAxisPtr time_axis01 = values01->axis1(); - TableAxisPtr time_axis10 = values10->axis1(); - TableAxisPtr time_axis11 = values11->axis1(); - - // Find time axis min/max. - size_t time_step_count = 20; - float time_min = time_axis00->min(); - time_min = min(time_min, time_axis01->min()); - time_min = min(time_min, time_axis10->min()); - time_min = min(time_min, time_axis11->min()); - float time_max = time_axis00->max(); - time_max = max(time_max, time_axis01->max()); - time_max = max(time_max, time_axis10->max()); - time_max = max(time_max, time_axis11->max()); - float time_step = (time_max - time_min) / time_step_count; - FloatSeq *time_values = new FloatSeq; - TableAxisPtr time_axis = make_shared(time_axis00->variable(), - time_values); - - // Interpolate waveform samples at time steps. - size_t index1 = slew_index; - size_t index2 = cap_index; - float x1 = slew; - float x2 = cap; - float x1l = slew_axis_->axisValue(index1); - float x1u = slew_axis_->axisValue(index1 + 1); - float dx1 = (x1 - x1l) / (x1u - x1l); - float x2l = cap_axis_->axisValue(index2); - float x2u = cap_axis_->axisValue(index2 + 1); - float dx2 = (x2 - x2l) / (x2u - x2l); - FloatSeq *values = new FloatSeq; - float prev_value = 0.0; - constexpr float value_tol = 1e-6; - for (size_t i = 0; i <= time_step_count; i++) { - float time = time_min + time_step * i; - if (time > time_max) - break; - float y00 = values00->findValueClip(time); - float y10 = values10->findValueClip(time); - float y11 = values11->findValueClip(time); - float y01 = values01->findValueClip(time); - float value - = (1 - dx1) * (1 - dx2) * y00 - + dx1 * (1 - dx2) * y10 - + dx1 * dx2 * y11 - + (1 - dx1) * dx2 * y01; - if (i == 0 || abs(value - prev_value) > value_tol) { - time_values->push_back(time); - values->push_back(value); - } - prev_value = value; - } - return Table1(values, time_axis); -} - -float -OutputWaveforms::referenceTime(float slew) -{ - return ref_times_->findValue(slew); -} - //////////////////////////////////////////////////////////////// DriverWaveform::DriverWaveform(const char *name, diff --git a/search/WritePathSpice.cc b/search/WritePathSpice.cc index b9f1fcd4..5cf43181 100644 --- a/search/WritePathSpice.cc +++ b/search/WritePathSpice.cc @@ -1464,7 +1464,7 @@ WritePathSpice::writeStagePiElmore(Pin *drvr_pin, float c2, rpi, c1; parasitics_->piModel(parasitic, c2, rpi, c1); const char *c1_node = "n1"; - streamPrint(spice_stream_, "Rpi %s %s %.3e\n", + streamPrint(spice_stream_, "RPI %s %s %.3e\n", network_->pathName(drvr_pin), c1_node, rpi); diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i index a50f8aba..0dd0b32a 100644 --- a/tcl/StaTcl.i +++ b/tcl/StaTcl.i @@ -909,24 +909,26 @@ using namespace sta; %typemap(out) Table1 { Table1 &table = $1; - Tcl_Obj *list3 = Tcl_NewListObj(0, nullptr); - Tcl_Obj *list1 = Tcl_NewListObj(0, nullptr); - for (float f : *table.axis1()->values()) { - Tcl_Obj *obj = Tcl_NewDoubleObj(f); - Tcl_ListObjAppendElement(interp, list1, obj); + if (table.axis1()) { + Tcl_Obj *list3 = Tcl_NewListObj(0, nullptr); + Tcl_Obj *list1 = Tcl_NewListObj(0, nullptr); + for (float f : *table.axis1()->values()) { + Tcl_Obj *obj = Tcl_NewDoubleObj(f); + Tcl_ListObjAppendElement(interp, list1, obj); + } + Tcl_Obj *list2 = Tcl_NewListObj(0, nullptr); + for (float f : *table.values()) { + Tcl_Obj *obj = Tcl_NewDoubleObj(f); + Tcl_ListObjAppendElement(interp, list2, obj); + } + Tcl_ListObjAppendElement(interp, list3, list1); + Tcl_ListObjAppendElement(interp, list3, list2); + Tcl_SetObjResult(interp, list3); } - Tcl_Obj *list2 = Tcl_NewListObj(0, nullptr); - for (float f : *table.values()) { - Tcl_Obj *obj = Tcl_NewDoubleObj(f); - Tcl_ListObjAppendElement(interp, list2, obj); - } - Tcl_ListObjAppendElement(interp, list3, list1); - Tcl_ListObjAppendElement(interp, list3, list2); - Tcl_SetObjResult(interp, list3); } -%typemap(out) Table1* { - Table1 *table = $1; +%typemap(out) const Table1* { + const Table1 *table = $1; Tcl_Obj *list3 = Tcl_NewListObj(0, nullptr); if (table) { Tcl_Obj *list1 = Tcl_NewListObj(0, nullptr); @@ -5708,7 +5710,7 @@ voltage_waveform(float in_slew, return Table1(); } -Table1 +const Table1 * current_waveform(float in_slew, float load_cap) { @@ -5716,11 +5718,11 @@ current_waveform(float in_slew, if (gate_model) { OutputWaveforms *waveforms = gate_model->outputWaveforms(); if (waveforms) { - Table1 waveform = waveforms->currentWaveform(in_slew, load_cap); + const Table1 *waveform = waveforms->currentWaveform(in_slew, load_cap); return waveform; } } - return Table1(); + return nullptr; } } // TimingArc methods