diff --git a/include/sta/TableModel.hh b/include/sta/TableModel.hh index b7d91e6b..039b21e2 100644 --- a/include/sta/TableModel.hh +++ b/include/sta/TableModel.hh @@ -344,7 +344,6 @@ public: bool &extrapolated) const; float findValue(float axis_value1) const; float findValueClip(float axis_value1) const; - float findValueClipZero(float axis_value1) const; FloatSeq *values() const { return values_; } using Table::findValue; @@ -499,23 +498,35 @@ public: float timeCurrent(float slew, float cap, float time); + float timeVoltage(float slew, + float cap, + float time); float voltageCurrent(float slew, float cap, float volt); + float currentVoltage(float slew, + float cap, + float current); float referenceTime(float slew); void setVdd(float vdd); static bool checkAxes(const TableTemplate *tbl_template); private: + float waveformValue(float slew, + float cap, + float axis_value, + Table1Seq &waveforms); float voltageTime1(float voltage, - size_t wave_index, - float cap); - FloatSeq *voltageTimes(size_t wave_index, - float cap); + size_t wave_index); + void ensureVoltages(); void findVoltages(size_t wave_index, float cap); - const Table1 *voltageCurrents(size_t wave_index, - float cap); + void waveformMinMaxTime(float slew, + float cap, + Table1Seq &waveforms, + // Return values. + float &min_time, + float &max_time); // Row. TableAxisPtr slew_axis_; @@ -523,7 +534,9 @@ private: TableAxisPtr cap_axis_; const RiseFall *rf_; Table1Seq current_waveforms_; + Table1Seq voltage_waveforms_; Table1Seq voltage_currents_; + Table1Seq current_voltages_; FloatTable voltage_times_; Table1 *ref_times_; float vdd_; diff --git a/liberty/TableModel.cc b/liberty/TableModel.cc index 43063b56..ff9753dd 100644 --- a/liberty/TableModel.cc +++ b/liberty/TableModel.cc @@ -876,7 +876,7 @@ Table1::findValueClip(float axis_value1) const float x1l = axis1_->axisValue(axis_index1); float x1u = axis1_->axisValue(axis_index1 + 1); if (x1 < x1l) - return this->value(0); + return 0.0; else if (x1 > x1u) return this->value(axis1_->size() - 1); else { @@ -888,27 +888,6 @@ Table1::findValueClip(float axis_value1) const } } -float -Table1::findValueClipZero(float axis_value1) const -{ - if (axis1_->size() == 1) - return this->value(axis_value1); - else { - size_t axis_index1 = axis1_->findAxisIndex(axis_value1); - float x1 = axis_value1; - float x1l = axis1_->axisValue(axis_index1); - float x1u = axis1_->axisValue(axis_index1 + 1); - if (x1 < x1l || x1 > x1u) - return 0.0; - else { - float y1 = this->value(axis_index1); - float y2 = this->value(axis_index1 + 1); - float dx1 = (x1 - x1l) / (x1u - x1l); - return (1 - dx1) * y1 + dx1 * y2; - } - } -} - string Table1::reportValue(const char *result_name, const LibertyCell *cell, @@ -1588,8 +1567,6 @@ OutputWaveforms::OutputWaveforms(TableAxisPtr slew_axis, cap_axis_(cap_axis), rf_(rf), current_waveforms_(current_waveforms), - voltage_currents_(current_waveforms.size()), - voltage_times_(current_waveforms.size()), ref_times_(ref_times), vdd_(0.0) { @@ -1598,7 +1575,9 @@ OutputWaveforms::OutputWaveforms(TableAxisPtr slew_axis, OutputWaveforms::~OutputWaveforms() { current_waveforms_.deleteContents(); + voltage_waveforms_.deleteContents(); voltage_currents_.deleteContents(); + current_voltages_.deleteContents(); voltage_times_.deleteContents(); delete ref_times_; } @@ -1634,6 +1613,42 @@ float OutputWaveforms::timeCurrent(float slew, float cap, float time) +{ + return waveformValue(slew, cap, time, current_waveforms_); +} + +float +OutputWaveforms::timeVoltage(float slew, + float cap, + float time) +{ + ensureVoltages(); + return waveformValue(slew, cap, time, voltage_waveforms_); +} + +float +OutputWaveforms::voltageCurrent(float slew, + float cap, + float volt) +{ + ensureVoltages(); + return waveformValue(slew, cap, volt, voltage_currents_); +} + +float +OutputWaveforms::currentVoltage(float slew, + float cap, + float current) +{ + ensureVoltages(); + return waveformValue(slew, cap, current, current_voltages_); +} + +float +OutputWaveforms::waveformValue(float slew, + float cap, + float axis_value, + Table1Seq &waveforms) { size_t slew_index = slew_axis_->findAxisIndex(slew); size_t cap_index = cap_axis_->findAxisIndex(cap); @@ -1643,10 +1658,10 @@ OutputWaveforms::timeCurrent(float slew, size_t wave_index10 = (slew_index + 1) * cap_count + cap_index; size_t wave_index11 = (slew_index + 1) * cap_count + (cap_index + 1); - const Table1 *waveform00 = current_waveforms_[wave_index00]; - const Table1 *waveform01 = current_waveforms_[wave_index01]; - const Table1 *waveform10 = current_waveforms_[wave_index10]; - const Table1 *waveform11 = current_waveforms_[wave_index11]; + const Table1 *waveform00 = waveforms[wave_index00]; + const Table1 *waveform01 = waveforms[wave_index01]; + const Table1 *waveform10 = waveforms[wave_index10]; + const Table1 *waveform11 = waveforms[wave_index11]; // Interpolate waveform samples at voltage steps. size_t index1 = slew_index; @@ -1660,16 +1675,16 @@ OutputWaveforms::timeCurrent(float slew, float x2u = cap_axis_->axisValue(index2 + 1); float dx2 = (x2 - x2l) / (x2u - x2l); - float y00 = waveform00->findValueClipZero(time); - float y01 = waveform01->findValueClipZero(time); - float y10 = waveform10->findValueClipZero(time); - float y11 = waveform11->findValueClipZero(time); - float current + float y00 = waveform00->findValueClip(axis_value); + float y01 = waveform01->findValueClip(axis_value); + float y10 = waveform10->findValueClip(axis_value); + float y11 = waveform11->findValueClip(axis_value); + float wave_value = (1 - dx1) * (1 - dx2) * y00 + dx1 * (1 - dx2) * y10 + dx1 * dx2 * y11 + (1 - dx1) * dx2 * y01; - return current; + return wave_value; } float @@ -1688,12 +1703,15 @@ Table1 OutputWaveforms::voltageWaveform(float slew, float cap) { - float volt_step = vdd_ / voltage_waveform_step_count_; + ensureVoltages(); + float min_time, max_time; + waveformMinMaxTime(slew, cap, voltage_waveforms_, min_time, max_time); + float time_step = (max_time - min_time) / voltage_waveform_step_count_; FloatSeq *times = new FloatSeq; FloatSeq *volts = new FloatSeq; - for (size_t v = 0; v <= voltage_waveform_step_count_; v++) { - float volt = v * volt_step; - float time = voltageTime(slew, cap, volt); + for (size_t i = 0; i < voltage_waveform_step_count_; i++) { + float time = min_time + i * time_step; + float volt = timeVoltage(slew, cap, time); times->push_back(time); volts->push_back(volt); } @@ -1701,10 +1719,13 @@ OutputWaveforms::voltageWaveform(float slew, return Table1(volts, time_axis); } -float -OutputWaveforms::voltageTime(float slew, - float cap, - float volt) +void +OutputWaveforms::waveformMinMaxTime(float slew, + float cap, + Table1Seq &waveforms, + // Return values. + float &min_time, + float &max_time) { size_t slew_index = slew_axis_->findAxisIndex(slew); size_t cap_index = cap_axis_->findAxisIndex(cap); @@ -1713,8 +1734,36 @@ OutputWaveforms::voltageTime(float slew, size_t wave_index01 = slew_index * cap_count + (cap_index + 1); size_t wave_index10 = (slew_index + 1) * cap_count + cap_index; size_t wave_index11 = (slew_index + 1) * cap_count + (cap_index + 1); - float cap0 = cap_axis_->axisValue(cap_index); - float cap1 = cap_axis_->axisValue(cap_index + 1); + + const Table1 *waveform00 = waveforms[wave_index00]; + const Table1 *waveform01 = waveforms[wave_index01]; + const Table1 *waveform10 = waveforms[wave_index10]; + const Table1 *waveform11 = waveforms[wave_index11]; + + min_time = waveform00->axis1()->min(); + min_time = min(min_time, waveform01->axis1()->min()); + min_time = min(min_time, waveform10->axis1()->min()); + min_time = min(min_time, waveform11->axis1()->min()); + + max_time = waveform00->axis1()->max(); + max_time = max(max_time, waveform01->axis1()->max()); + max_time = max(max_time, waveform10->axis1()->max()); + max_time = max(max_time, waveform11->axis1()->max()); +} + +float +OutputWaveforms::voltageTime(float slew, + float cap, + float volt) +{ + ensureVoltages(); + size_t slew_index = slew_axis_->findAxisIndex(slew); + size_t cap_index = cap_axis_->findAxisIndex(cap); + size_t cap_count = cap_axis_->size(); + size_t wave_index00 = slew_index * cap_count + cap_index; + size_t wave_index01 = slew_index * cap_count + (cap_index + 1); + size_t wave_index10 = (slew_index + 1) * cap_count + cap_index; + size_t wave_index11 = (slew_index + 1) * cap_count + (cap_index + 1); // Interpolate waveform samples at voltage steps. size_t index1 = slew_index; @@ -1728,10 +1777,10 @@ OutputWaveforms::voltageTime(float slew, float x2u = cap_axis_->axisValue(index2 + 1); float dx2 = (x2 - x2l) / (x2u - x2l); - float y00 = voltageTime1(volt, wave_index00, cap0); - float y01 = voltageTime1(volt, wave_index01, cap1); - float y10 = voltageTime1(volt, wave_index10, cap0); - float y11 = voltageTime1(volt, wave_index11, cap1); + float y00 = voltageTime1(volt, wave_index00); + float y01 = voltageTime1(volt, wave_index01); + float y10 = voltageTime1(volt, wave_index10); + float y11 = voltageTime1(volt, wave_index11); float time = (1 - dx1) * (1 - dx2) * y00 + dx1 * (1 - dx2) * y10 @@ -1742,10 +1791,9 @@ OutputWaveforms::voltageTime(float slew, float OutputWaveforms::voltageTime1(float voltage, - size_t wave_index, - float cap) + size_t wave_index) { - FloatSeq *voltage_times = voltageTimes(wave_index, cap); + FloatSeq *voltage_times = voltage_times_[wave_index]; float volt_step = vdd_ / voltage_waveform_step_count_; size_t volt_idx = voltage / volt_step; float time0 = (*voltage_times)[volt_idx]; @@ -1754,16 +1802,23 @@ OutputWaveforms::voltageTime1(float voltage, return time; } -FloatSeq * -OutputWaveforms::voltageTimes(size_t wave_index, - float cap) +void +OutputWaveforms::ensureVoltages() { - FloatSeq *voltage_times = voltage_times_[wave_index]; - if (voltage_times == nullptr) { - findVoltages(wave_index, cap); - voltage_times = voltage_times_[wave_index]; + if (voltage_waveforms_.empty()) { + size_t size = current_waveforms_.size(); + voltage_waveforms_.resize(size); + voltage_currents_.resize(size); + current_voltages_.resize(size); + voltage_times_.resize(size); + size_t cap_count = cap_axis_->size(); + for (size_t slew_index = 0; slew_index < slew_axis_->size(); slew_index++) { + for (size_t cap_index = 0; cap_index < cap_axis_->size(); cap_index++) { + size_t wave_index = slew_index * cap_count + cap_index; + findVoltages(wave_index, cap_axis_->axisValue(cap_index)); + } + } } - return voltage_times; } void @@ -1774,13 +1829,13 @@ OutputWaveforms::findVoltages(size_t wave_index, criticalError(239, "output waveform vdd = 0.0"); // Integrate current waveform to find voltage waveform. // i = C dv/dt - FloatSeq volts; + FloatSeq *volts = new FloatSeq; Table1 *currents = current_waveforms_[wave_index]; const TableAxis *time_axis = currents->axis1(); float prev_time = time_axis->axisValue(0); float prev_current = currents->value(0); float voltage = 0.0; - volts.push_back(voltage); + volts->push_back(voltage); bool always_rise = true; bool invert = (always_rise && rf_ == RiseFall::fall()); for (size_t i = 1; i < time_axis->size(); i++) { @@ -1788,37 +1843,47 @@ OutputWaveforms::findVoltages(size_t wave_index, float current = currents->value(i); float dv = (current + prev_current) / 2.0 * (time - prev_time) / cap; voltage += invert ? -dv : dv; - volts.push_back(voltage); + volts->push_back(voltage); prev_time = time; prev_current = current; } + Table1 *volt_table = new Table1(volts, currents->axis1ptr()); + voltage_waveforms_[wave_index] = volt_table; // Make voltage -> current table. - FloatSeq *axis_volts = new FloatSeq(volts); + FloatSeq *axis_volts = new FloatSeq(*volts); TableAxisPtr volt_axis = make_shared(TableAxisVariable::input_voltage, axis_volts); FloatSeq *currents1 = new FloatSeq(*currents->values()); Table1 *volt_currents = new Table1(currents1, volt_axis); voltage_currents_[wave_index] = volt_currents; + // Make current -> voltage table. + FloatSeq *axis_currents = new FloatSeq(*currents->values()); + TableAxisPtr current_axis = + make_shared(TableAxisVariable::input_voltage, axis_currents); + FloatSeq *volts1 = new FloatSeq(*volts); + Table1 *current_volts = new Table1(volts1, current_axis); + current_voltages_[wave_index] = current_volts; + // Sample the voltage waveform at uniform intervals to speed up // voltage time lookup. FloatSeq *voltage_times = new FloatSeq; float volt_step = vdd_ / voltage_waveform_step_count_; size_t i = 0; float time0 = time_axis->axisValue(i); - float volt0 = volts[i]; + float volt0 = (*volts)[i]; i = 1; float time1 = time_axis->axisValue(i); - float volt1 = volts[i]; + float volt1 = (*volts)[i]; for (size_t v = 0; v <= voltage_waveform_step_count_; v++) { float volt3 = v * volt_step; - while (volt3 > volt1 && i < volts.size() - 1) { + while (volt3 > volt1 && i < volts->size() - 1) { time0 = time1; volt0 = volt1; i++; time1 = time_axis->axisValue(i); - volt1 = volts[i]; + volt1 = (*volts)[i]; } float time3 = time0 + (time1 - time0) * (volt3 - volt0) / (volt1 - volt0); voltage_times->push_back(time3); @@ -1826,62 +1891,6 @@ OutputWaveforms::findVoltages(size_t wave_index, voltage_times_[wave_index] = voltage_times; } -float -OutputWaveforms::voltageCurrent(float slew, - float cap, - float volt) -{ - size_t slew_index = slew_axis_->findAxisIndex(slew); - size_t cap_index = cap_axis_->findAxisIndex(cap); - size_t cap_count = cap_axis_->size(); - size_t wave_index00 = slew_index * cap_count + cap_index; - size_t wave_index01 = slew_index * cap_count + (cap_index + 1); - size_t wave_index10 = (slew_index + 1) * cap_count + cap_index; - size_t wave_index11 = (slew_index + 1) * cap_count + (cap_index + 1); - float cap0 = cap_axis_->axisValue(cap_index); - float cap1 = cap_axis_->axisValue(cap_index + 1); - - // 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); - - const Table1 *waveform00 = voltageCurrents(wave_index00, cap0); - const Table1 *waveform01 = voltageCurrents(wave_index01, cap1); - const Table1 *waveform10 = voltageCurrents(wave_index10, cap0); - const Table1 *waveform11 = voltageCurrents(wave_index11, cap1); - - float y00 = waveform00->findValueClipZero(volt); - float y01 = waveform01->findValueClipZero(volt); - float y10 = waveform10->findValueClipZero(volt); - float y11 = waveform11->findValueClipZero(volt); - float current - = (1 - dx1) * (1 - dx2) * y00 - + dx1 * (1 - dx2) * y10 - + dx1 * dx2 * y11 - + (1 - dx1) * dx2 * y01; - return current; -} - -const Table1 * -OutputWaveforms::voltageCurrents(size_t wave_index, - float cap) -{ - const Table1 *waveform = voltage_currents_[wave_index]; - if (waveform == nullptr) { - findVoltages(wave_index, cap); - waveform = voltage_currents_[wave_index]; - } - return waveform; -} - //////////////////////////////////////////////////////////////// DriverWaveform::DriverWaveform(const char *name,