diff --git a/include/sta/TableModel.hh b/include/sta/TableModel.hh index cb45eb1f..9c3d197d 100644 --- a/include/sta/TableModel.hh +++ b/include/sta/TableModel.hh @@ -487,7 +487,8 @@ public: TableAxisPtr cap_axis, const RiseFall *rf, Table1Seq ¤t_waveforms, - Table1 *ref_times); + Table1 *ref_times, + LibertyLibrary *library); ~OutputWaveforms(); const RiseFall *rf() const { return rf_; } const TableAxis *slewAxis() const { return slew_axis_.get(); } @@ -509,19 +510,18 @@ public: float cap, float volt); float referenceTime(float slew); - void setVdd(float vdd); static bool checkAxes(const TableTemplate *tbl_template); private: + void makeWaveforms(); + void findVoltages(size_t wave_index, + float cap); float waveformValue(float slew, float cap, float axis_value, Table1Seq &waveforms); float voltageTime1(float voltage, size_t wave_index); - void ensureVoltages(); - void findVoltages(size_t wave_index, - float cap); void waveformMinMaxTime(float slew, float cap, Table1Seq &waveforms, diff --git a/liberty/LibertyReader.cc b/liberty/LibertyReader.cc index f26d7076..f650ea4c 100644 --- a/liberty/LibertyReader.cc +++ b/liberty/LibertyReader.cc @@ -2550,7 +2550,8 @@ LibertyReader::endOutputCurrentRiseFall(LibertyGroup *group) Table1 *ref_time_tbl = new Table1(ref_times, slew_axis); OutputWaveforms *output_current = new OutputWaveforms(slew_axis, cap_axis, rf_, current_waveforms, - ref_time_tbl); + ref_time_tbl, + library_); timing_->setOutputWaveforms(rf_, output_current); output_currents_.deleteContentsClear(); } diff --git a/liberty/TableModel.cc b/liberty/TableModel.cc index 46439beb..3c17b1ab 100644 --- a/liberty/TableModel.cc +++ b/liberty/TableModel.cc @@ -1570,14 +1570,17 @@ OutputWaveforms::OutputWaveforms(TableAxisPtr slew_axis, TableAxisPtr cap_axis, const RiseFall *rf, Table1Seq ¤t_waveforms, - Table1 *ref_times) : + Table1 *ref_times, + LibertyLibrary *library) : slew_axis_(slew_axis), cap_axis_(cap_axis), rf_(rf), current_waveforms_(current_waveforms), - ref_times_(ref_times), - vdd_(0.0) + ref_times_(ref_times) { + bool vdd_exists; + library->supplyVoltage("VDD", vdd_, vdd_exists); + makeWaveforms(); } OutputWaveforms::~OutputWaveforms() @@ -1606,218 +1609,18 @@ OutputWaveforms::checkAxes(const TableTemplate *tbl_template) && axis3->variable() == TableAxisVariable::time); } -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_index = slew_index * cap_axis_->size() + cap_index; - return current_waveforms_[wave_index]; -} - -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::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); - 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); - - 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; - 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 = 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 wave_value; -} - -float -OutputWaveforms::referenceTime(float slew) -{ - return ref_times_->findValue(slew); -} - void -OutputWaveforms::setVdd(float vdd) +OutputWaveforms::makeWaveforms() { - vdd_ = vdd; -} - -Table1 -OutputWaveforms::voltageWaveform(float slew, - float cap) -{ - 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 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); - } - TableAxisPtr time_axis = make_shared(TableAxisVariable::time, times); - return Table1(volts, time_axis); -} - -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); + size_t size = current_waveforms_.size(); + voltage_waveforms_.resize(size); + voltage_currents_.resize(size); + voltage_times_.resize(size); 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); - - 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; - 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 = 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 - + dx1 * dx2 * y11 - + (1 - dx1) * dx2 * y01; - return time; -} - -float -OutputWaveforms::voltageTime1(float voltage, - size_t wave_index) -{ - FloatSeq *voltage_times = voltage_times_[wave_index]; - float volt_step = vdd_ / voltage_waveform_step_count_; - size_t volt_idx = voltage / volt_step; - if (volt_idx >= voltage_times->size() - 1) - return (*voltage_times)[voltage_times->size() - 1]; - else { - float time0 = (*voltage_times)[volt_idx]; - float time1 = (*voltage_times)[volt_idx + 1]; - float time = time0 + (time1 - time0) * (voltage - volt_step * volt_idx); - return time; - } -} - -void -OutputWaveforms::ensureVoltages() -{ - if (voltage_waveforms_.empty()) { - size_t size = current_waveforms_.size(); - voltage_waveforms_.resize(size); - voltage_currents_.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)); - } + 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)); } } } @@ -1884,6 +1687,194 @@ OutputWaveforms::findVoltages(size_t wave_index, voltage_times_[wave_index] = voltage_times; } +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_index = slew_index * cap_axis_->size() + cap_index; + return current_waveforms_[wave_index]; +} + +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) +{ + return waveformValue(slew, cap, time, voltage_waveforms_); +} + +float +OutputWaveforms::voltageCurrent(float slew, + float cap, + float volt) +{ + return waveformValue(slew, cap, volt, voltage_currents_); +} + +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); + 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); + + 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; + 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 = 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 wave_value; +} + +float +OutputWaveforms::referenceTime(float slew) +{ + return ref_times_->findValue(slew); +} + +Table1 +OutputWaveforms::voltageWaveform(float slew, + float cap) +{ + 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 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); + } + TableAxisPtr time_axis = make_shared(TableAxisVariable::time, times); + return Table1(volts, time_axis); +} + +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); + 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); + + 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) +{ + 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; + 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 = 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 + + dx1 * dx2 * y11 + + (1 - dx1) * dx2 * y01; + return time; +} + +float +OutputWaveforms::voltageTime1(float voltage, + size_t wave_index) +{ + FloatSeq *voltage_times = voltage_times_[wave_index]; + float volt_step = vdd_ / voltage_waveform_step_count_; + size_t volt_idx = voltage / volt_step; + if (volt_idx >= voltage_times->size() - 1) + return (*voltage_times)[voltage_times->size() - 1]; + else { + float time0 = (*voltage_times)[volt_idx]; + float time1 = (*voltage_times)[volt_idx + 1]; + float time = time0 + (time1 - time0) * (voltage - volt_step * volt_idx); + return time; + } +} + //////////////////////////////////////////////////////////////// DriverWaveform::DriverWaveform(const char *name, diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i index 628c4fd9..d6d3b692 100644 --- a/tcl/StaTcl.i +++ b/tcl/StaTcl.i @@ -4378,7 +4378,6 @@ voltage_current(float in_slew, if (gate_model) { OutputWaveforms *waveforms = gate_model->outputWaveforms(); if (waveforms) { - waveforms->setVdd(.7); float current = waveforms->voltageCurrent(in_slew, load_cap, voltage); return current; }