Merge remote-tracking branch 'parallax/master'

Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
This commit is contained in:
Matt Liberty 2024-08-04 09:33:38 -07:00
commit 2a8accc2ea
26 changed files with 621 additions and 196 deletions

View File

@ -339,23 +339,26 @@ find_package(TCL)
set(TCL_READLINE 0)
# check for tclReadline
if (USE_TCL_READLINE)
find_library(TCL_READLINE_LIBRARY tclreadline)
set(TCL_READLINE_POSSIBLE_NAMES
tclreadline-2.1.0
tclreadline-2.3.2
tclreadline-2.3.6
tclreadline-2.3.7
tclreadline-2.3.8
)
find_library(TCL_READLINE_LIBRARY
NAMES tclreadline ${TCL_READLINE_POSSIBLE_NAMES}
PATHS ${TCL_LIB_PATHS}
)
if (TCL_READLINE_LIBRARY)
message(STATUS "TCL readline: ${TCL_READLINE_LIBRARY}")
message(STATUS "TCL readline library: ${TCL_READLINE_LIBRARY}")
# Referenced by StaConfig.hh.cmake
set(TCL_READLINE 1)
endif()
get_filename_component(TCL_READLINE_LIB_DIR "${TCL_READLINE_LIBRARY}" PATH)
get_filename_component(TCL_READLINE_LIB_PARENT "${TCL_READLINE_LIB_DIR}" PATH)
find_file(TCL_READLINE_HEADER tclreadline.h
PATHS ${TCL_READLINE_LIB_PARENT}
PATH_SUFFIXES include
NO_DEFAULT_PATH
)
message(STATUS "TCL readline header: ${TCL_READLINE_HEADER}")
get_filename_component(TCL_READLINE_INCLUDE "${TCL_READLINE_HEADER}" PATH)
else()
message(STATUS "TCL readline: not found")
find_path(TCL_READLINE_INCLUDE tclreadline.h)
if (TCL_READLINE_INCLUDE)
message(STATUS "TCL readline header: ${TCL_READLINE_INCLUDE}/tclreadline.h")
endif()
endif()

View File

@ -54,7 +54,7 @@ ArcDcalcWaveforms::inputWaveform(ArcDcalcArg &dcalc_arg,
library->supplyVoltage("VDD", vdd, vdd_exists);
if (!vdd_exists)
report->error(1751, "VDD not defined in library %s", library->name());
Waveform in_waveform = driver_waveform->waveform(in_slew);
Waveform in_waveform = driver_waveform->waveform(delayAsFloat(in_slew));
// Delay time axis.
FloatSeq *time_values = new FloatSeq;
for (float time : *in_waveform.axis1()->values())

View File

@ -104,7 +104,8 @@ CcsCeffDelayCalc::gateDelay(const Pin *drvr_pin,
vl_ = drvr_library->slewLowerThreshold(drvr_rf_) * vdd_;
vh_ = drvr_library->slewUpperThreshold(drvr_rf_) * vdd_;
drvr_cell->ensureVoltageWaveforms(dcalc_ap);
const DcalcAnalysisPtSeq &dcalc_aps = corners_->dcalcAnalysisPts();
drvr_cell->ensureVoltageWaveforms(dcalc_aps);
in_slew_ = delayAsFloat(in_slew);
output_waveforms_ = output_waveforms;
ref_time_ = output_waveforms_->referenceTime(in_slew_);

View File

@ -202,15 +202,17 @@ PrimaDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
dcalc_ap_ = dcalc_ap;
drvr_rf_ = dcalc_args[0].arc()->toEdge()->asRiseFall();
parasitic_network_ = dcalc_args[0].parasitic();
load_cap_ = dcalc_args[0].loadCap();
bool failed = false;
output_waveforms_.resize(drvr_count_);
const DcalcAnalysisPtSeq &dcalc_aps = corners_->dcalcAnalysisPts();
for (size_t drvr_idx = 0; drvr_idx < drvr_count_; drvr_idx++) {
ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx];
GateTableModel *table_model = dcalc_arg.arc()->gateTableModel(dcalc_ap);
if (table_model && dcalc_arg.parasitic()) {
OutputWaveforms *output_waveforms = table_model->outputWaveforms();
Slew in_slew = dcalc_arg.inSlew();
float in_slew = dcalc_arg.inSlewFlt();
if (output_waveforms
// Bounds check because extrapolating waveforms does not work for shit.
&& output_waveforms->slewAxis()->inBounds(in_slew)
@ -225,7 +227,7 @@ PrimaDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
drvr_library->supplyVoltage("VDD", vdd_, vdd_exists);
if (!vdd_exists)
report_->error(1720, "VDD not defined in library %s", drvr_library->name());
drvr_cell->ensureVoltageWaveforms(dcalc_ap);
drvr_cell->ensureVoltageWaveforms(dcalc_aps);
if (drvr_idx == 0) {
vth_ = drvr_library->outputThreshold(drvr_rf_) * vdd_;
vl_ = drvr_library->slewLowerThreshold(drvr_rf_) * vdd_;
@ -321,7 +323,7 @@ PrimaDelayCalc::simulate1(const MatrixSd &G,
v_ = v_prev_ = x_to_v * x_init;
// voltageTime is always for a rising waveform so 0.0v is initial voltage.
double time_begin = output_waveforms_[0]->voltageTime((*dcalc_args_)[0].inSlew(),
double time_begin = output_waveforms_[0]->voltageTime((*dcalc_args_)[0].inSlewFlt(),
ceff_[0], 0.0);
// Limit in case load voltage waveforms don't get to final value.
double time_end = time_begin + maxTime();
@ -368,7 +370,7 @@ PrimaDelayCalc::timeStep()
double
PrimaDelayCalc::maxTime()
{
return (*dcalc_args_)[0].inSlew()
return (*dcalc_args_)[0].inSlewFlt()
+ (driverResistance() + resistance_sum_) * load_cap_ * 4;
}
@ -484,7 +486,7 @@ PrimaDelayCalc::initCeffIdrvr()
ceff_[drvr_idx] = load_cap_;
// voltageTime is always for a rising waveform so 0.0v is initial voltage.
drvr_current_[drvr_idx] =
output_waveforms_[drvr_idx]->voltageCurrent(dcalc_arg.inSlew(),
output_waveforms_[drvr_idx]->voltageCurrent(dcalc_arg.inSlewFlt(),
ceff_[drvr_idx], 0.0);
}
}
@ -615,7 +617,7 @@ PrimaDelayCalc::updateCeffIdrvr()
drvr_current_[drvr_idx] = 0.0;
else
drvr_current_[drvr_idx] =
output_waveforms_[drvr_idx]->voltageCurrent(dcalc_arg.inSlew(),
output_waveforms_[drvr_idx]->voltageCurrent(dcalc_arg.inSlewFlt(),
ceff_[drvr_idx], v1);
}
else {
@ -631,7 +633,7 @@ PrimaDelayCalc::updateCeffIdrvr()
}
else
drvr_current_[drvr_idx] =
output_waveforms_[drvr_idx]->voltageCurrent(dcalc_arg.inSlew(),
output_waveforms_[drvr_idx]->voltageCurrent(dcalc_arg.inSlewFlt(),
ceff_[drvr_idx],
vdd_ - v1);
}
@ -708,7 +710,7 @@ PrimaDelayCalc::dcalcResults()
const LibertyLibrary *drvr_library = dcalc_arg.drvrLibrary();
size_t drvr_node = pin_node_map_[drvr_pin];
ThresholdTimes &drvr_times = threshold_times_[drvr_node];
float ref_time = output_waveforms_[drvr_idx]->referenceTime(dcalc_arg.inSlew());
float ref_time = output_waveforms_[drvr_idx]->referenceTime(dcalc_arg.inSlewFlt());
ArcDelay gate_delay = drvr_times[threshold_vth] - ref_time;
Slew drvr_slew = abs(drvr_times[threshold_vh] - drvr_times[threshold_vl]);
dcalc_result.setGateDelay(gate_delay);

Binary file not shown.

Binary file not shown.

View File

@ -230,7 +230,7 @@ proc report_pin_constant { pin } {
################################################################
proc report_disabled_edges {} {
proc_redirect report_disabled_edges {
foreach edge [disabled_edges_sorted] {
if { [$edge role] == "wire" } {
set from_pin_name [get_full_name [[$edge from] pin]]

View File

@ -80,6 +80,7 @@ typedef Vector<InternalPowerAttrs*> InternalPowerAttrsSeq;
typedef Map<const char *, float, CharPtrLess> SupplyVoltageMap;
typedef Map<const char *, LibertyPgPort*, CharPtrLess> LibertyPgPortMap;
typedef Map<const char *, DriverWaveform*, CharPtrLess> DriverWaveformMap;
typedef Vector<DcalcAnalysisPt*> DcalcAnalysisPtSeq;
enum class ClockGateType { none, latch_posedge, latch_negedge, other };
@ -532,7 +533,7 @@ public:
// Check all liberty cells to make sure they exist
// for all the defined corners.
static void checkLibertyCorners();
void ensureVoltageWaveforms(const DcalcAnalysisPt *dcalc_ap);
void ensureVoltageWaveforms(const DcalcAnalysisPtSeq &dcalc_aps);
protected:
void addPort(ConcretePort *port);
@ -555,7 +556,10 @@ protected:
const LibertyPort *en,
const RiseFall *en_rf,
const LibertyPort *q,
const TimingArcSet *en_to_q,
Report *report);
bool condMatch(const TimingArcSet *arc_set1,
const TimingArcSet *arc_set2);
void findDefaultCondArcs();
void translatePresetClrCheckRoles();
void inferLatchRoles(Report *report,
@ -837,6 +841,7 @@ protected:
void setMinPort(LibertyPort *min);
void addScaledPort(OperatingConditions *op_cond,
LibertyPort *scaled_port);
RiseFallMinMax clkTreeDelays1() const;
LibertyCell *liberty_cell_;
BusDcl *bus_dcl_;

View File

@ -80,9 +80,9 @@ public:
const Unit *unit() const { return unit_; }
const char *asString(const Network *network) const;
const char *stringValue() const { return string_; }
float floatValue() const { return float_; }
bool boolValue() const { return bool_; }
const char *stringValue() const; // valid for type string
float floatValue() const; // valid for type float
bool boolValue() const; // valid for type bool
const LibertyLibrary *libertyLibrary() const { return liberty_library_; }
const LibertyCell *libertyCell() const { return liberty_cell_; }
const LibertyPort *libertyPort() const { return liberty_port_; }

View File

@ -497,7 +497,7 @@ public:
const TableAxis *capAxis() const { return cap_axis_.get(); }
// Make voltage wavefroms from liberty time/current values.
// Required before voltageTime, timeVoltage, voltageCurrent.
void makeVoltageWaveforms(float vdd);
void ensureVoltageWaveforms(float vdd);
float timeCurrent(float slew,
float cap,
float time);

View File

@ -1729,11 +1729,13 @@ LibertyCell::makeLatchEnables(Report *report,
LibertyPort *en = en_to_q->from();
LibertyPort *q = en_to_q->to();
for (TimingArcSet *d_to_q : timingArcSets(nullptr, q)) {
if (d_to_q->role() == TimingRole::latchDtoQ()) {
if (d_to_q->role() == TimingRole::latchDtoQ()
&& condMatch(en_to_q, d_to_q)) {
LibertyPort *d = d_to_q->from();
const RiseFall *en_rf = en_to_q->isRisingFallingEdge();
if (en_rf) {
TimingArcSet *setup_check = findLatchSetup(d, en, en_rf, q, report);
TimingArcSet *setup_check = findLatchSetup(d, en, en_rf, q, d_to_q,
report);
LatchEnable *latch_enable = makeLatchEnable(d, en, en_rf, q, d_to_q,
en_to_q,
setup_check,
@ -1766,11 +1768,22 @@ LibertyCell::makeLatchEnables(Report *report,
}
}
bool
LibertyCell::condMatch(const TimingArcSet *arc_set1,
const TimingArcSet *arc_set2)
{
FuncExpr *cond1 = arc_set1->cond();
FuncExpr *cond2 = arc_set2->cond();
return (cond1 == nullptr && cond2 == nullptr)
|| FuncExpr::equiv(cond1, cond2);
}
TimingArcSet *
LibertyCell::findLatchSetup(const LibertyPort *d,
const LibertyPort *en,
const RiseFall *en_rf,
const LibertyPort *q,
const TimingArcSet *en_to_q,
Report *report)
{
TimingArcSetSeq en_d_arcs = timingArcSets(en, d);
@ -1779,7 +1792,8 @@ LibertyCell::findLatchSetup(const LibertyPort *d,
if (arc_set->role() == TimingRole::setup()) {
for (TimingArc *arc : arc_set->arcs()) {
const RiseFall *from_rf = arc->fromEdge()->asRiseFall();
if (from_rf == en_rf->opposite())
if (from_rf == en_rf->opposite()
&& condMatch(arc_set, en_to_q))
return arc_set;
}
}
@ -1875,16 +1889,18 @@ LibertyCell::inferLatchRoles(Report *report,
for (TimingArcSet *d_to_q : timingArcSets(nullptr, q)) {
// Look for combinational d->q arcs.
TimingRole *d_to_q_role = d_to_q->role();
if ((d_to_q_role == TimingRole::combinational()
&& d_to_q->arcCount() == 2
&& (d_to_q->sense() == TimingSense::positive_unate
|| d_to_q->sense() == TimingSense::negative_unate))
// Previously identified as D->Q arc.
|| d_to_q_role == TimingRole::latchDtoQ()) {
if (((d_to_q_role == TimingRole::combinational()
&& d_to_q->arcCount() == 2
&& (d_to_q->sense() == TimingSense::positive_unate
|| d_to_q->sense() == TimingSense::negative_unate))
// Previously identified as D->Q arc.
|| d_to_q_role == TimingRole::latchDtoQ())
&& condMatch(en_to_q, d_to_q)) {
LibertyPort *d = d_to_q->from();
const RiseFall *en_rf = en_to_q->isRisingFallingEdge();
if (en_rf) {
TimingArcSet *setup_check = findLatchSetup(d, en, en_rf, q, report);
TimingArcSet *setup_check = findLatchSetup(d, en, en_rf, q, en_to_q,
report);
makeLatchEnable(d, en, en_rf, q, d_to_q, en_to_q, setup_check, debug);
d_to_q->setRole(TimingRole::latchDtoQ());
en_to_q->setRole(TimingRole::latchEnToQ());
@ -1933,7 +1949,7 @@ LibertyCell::latchCheckEnableEdge(TimingArcSet *check_set)
}
void
LibertyCell::ensureVoltageWaveforms(const DcalcAnalysisPt *dcalc_ap)
LibertyCell::ensureVoltageWaveforms(const DcalcAnalysisPtSeq &dcalc_aps)
{
if (!have_voltage_waveforms_) {
float vdd = 0.0; // shutup gcc
@ -1943,11 +1959,13 @@ LibertyCell::ensureVoltageWaveforms(const DcalcAnalysisPt *dcalc_ap)
criticalError(1120, "library missing vdd");
for (TimingArcSet *arc_set : timingArcSets()) {
for (TimingArc *arc : arc_set->arcs()) {
GateTableModel *model = arc->gateTableModel(dcalc_ap);
if (model) {
OutputWaveforms *output_waveforms = model->outputWaveforms();
if (output_waveforms)
output_waveforms->makeVoltageWaveforms(vdd);
for (const DcalcAnalysisPt *dcalc_ap : dcalc_aps) {
GateTableModel *model = arc->gateTableModel(dcalc_ap);
if (model) {
OutputWaveforms *output_waveforms = model->outputWaveforms();
if (output_waveforms)
output_waveforms->ensureVoltageWaveforms(vdd);
}
}
}
}
@ -2627,11 +2645,17 @@ LibertyPort::setDriverWaveform(DriverWaveform *driver_waveform,
RiseFallMinMax
LibertyPort::clockTreePathDelays() const
{
return clkTreeDelays();
return clkTreeDelays1();
}
RiseFallMinMax
LibertyPort::clkTreeDelays() const
{
return clkTreeDelays1();
}
RiseFallMinMax
LibertyPort::clkTreeDelays1() const
{
RiseFallMinMax delays;
for (const RiseFall *from_rf : RiseFall::range()) {

View File

@ -289,9 +289,9 @@ timing_arc_sets()
void
ensure_voltage_waveforms()
{
Corner *corner = Sta::sta()->cmdCorner();
DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(MinMax::max());
self->ensureVoltageWaveforms(dcalc_ap);
Corners *corners = Sta::sta()->corners();
const DcalcAnalysisPtSeq &dcalc_aps = corners->dcalcAnalysisPts();
self->ensureVoltageWaveforms(dcalc_aps);
}
} // LibertyCell methods

View File

@ -2351,7 +2351,8 @@ TimingGroup::makeTableModels(LibertyCell *cell,
if (delay == nullptr)
reader->libWarn(1211, line_, "missing cell_%s.", rf->name());
}
} else if (constraint)
}
else if (constraint)
attrs_->setModel(rf, new CheckTableModel(cell, constraint,
constraint_sigma_[rf_index]));
}
@ -2401,23 +2402,34 @@ LibertyReader::makeTimingArcs(const char *from_port_name,
else {
// bus -> bus
if (timing->isOneToOne()) {
if (static_cast<int>(from_port_iter.size()) == to_port->size()) {
LibertyPortMemberIterator to_iter(to_port);
while (from_port_iter.hasNext() && to_iter.hasNext()) {
LibertyPort *from_port_bit = from_port_iter.next();
LibertyPort *to_port_bit = to_iter.next();
if (from_port_bit->direction()->isOutput())
libWarn(1215, timing->line(), "timing group from output port.");
builder_.makeTimingArcs(cell_, from_port_bit, to_port_bit,
related_out_port, timing->attrs(),
timing->line());
}
}
else
int from_size = from_port_iter.size();
int to_size = to_port->size();
LibertyPortMemberIterator to_port_iter(to_port);
// warn about different sizes
if (from_size != to_size)
libWarn(1216, timing->line(),
"timing port %s and related port %s are different sizes.",
from_port_name,
to_port->name());
// align to/from iterators for one-to-one mapping
while (from_size > to_size) {
from_size--;
from_port_iter.next();
}
while (to_size > from_size) {
to_size--;
to_port_iter.next();
}
// make timing arcs
while (from_port_iter.hasNext() && to_port_iter.hasNext()) {
LibertyPort *from_port_bit = from_port_iter.next();
LibertyPort *to_port_bit = to_port_iter.next();
if (from_port_bit->direction()->isOutput())
libWarn(1215, timing->line(), "timing group from output port.");
builder_.makeTimingArcs(cell_, from_port_bit, to_port_bit,
related_out_port, timing->attrs(),
timing->line());
}
}
else {
while (from_port_iter.hasNext()) {
@ -2534,16 +2546,17 @@ LibertyReader::endReceiverCapacitanceRiseFall(LibertyGroup *group)
if (ReceiverModel::checkAxes(table_)) {
TableModel *table_model = new TableModel(table_, tbl_template_,
scale_factor_type_, rf_);
if (timing_ && receiver_model_ == nullptr) {
if (receiver_model_ == nullptr) {
receiver_model_ = make_shared<ReceiverModel>();
timing_->setReceiverModel(receiver_model_);
if (timing_)
timing_->setReceiverModel(receiver_model_);
}
receiver_model_->setCapacitanceModel(table_model, index_, rf_);
}
else
libWarn(1219, group, "unsupported model axis.");
endTableModel();
}
endTableModel();
}
////////////////////////////////////////////////////////////////
@ -2576,50 +2589,52 @@ LibertyReader::beginOutputCurrent(RiseFall *rf,
void
LibertyReader::endOutputCurrentRiseFall(LibertyGroup *group)
{
Set<float> slew_set, cap_set;
FloatSeq *slew_values = new FloatSeq;
FloatSeq *cap_values = new FloatSeq;
for (OutputWaveform *waveform : output_currents_) {
float slew = waveform->slew();
if (!slew_set.hasKey(slew)) {
slew_set.insert(slew);
slew_values->push_back(slew);
if (timing_) {
Set<float> slew_set, cap_set;
FloatSeq *slew_values = new FloatSeq;
FloatSeq *cap_values = new FloatSeq;
for (OutputWaveform *waveform : output_currents_) {
float slew = waveform->slew();
if (!slew_set.hasKey(slew)) {
slew_set.insert(slew);
slew_values->push_back(slew);
}
float cap = waveform->cap();
if (!cap_set.hasKey(cap)) {
cap_set.insert(cap);
cap_values->push_back(cap);
}
}
float cap = waveform->cap();
if (!cap_set.hasKey(cap)) {
cap_set.insert(cap);
cap_values->push_back(cap);
sort(slew_values, std::less<float>());
sort(cap_values, std::less<float>());
TableAxisPtr slew_axis = make_shared<TableAxis>(TableAxisVariable::input_net_transition,
slew_values);
TableAxisPtr cap_axis = make_shared<TableAxis>(TableAxisVariable::total_output_net_capacitance,
cap_values);
FloatSeq *ref_times = new FloatSeq(slew_values->size());
Table1Seq current_waveforms(slew_axis->size() * cap_axis->size());
for (OutputWaveform *waveform : output_currents_) {
size_t slew_index, cap_index;
bool slew_exists, cap_exists;
slew_axis->findAxisIndex(waveform->slew(), slew_index, slew_exists);
cap_axis->findAxisIndex(waveform->cap(), cap_index, cap_exists);
if (slew_exists && cap_exists) {
size_t index = slew_index * cap_axis->size() + cap_index;
current_waveforms[index] = waveform->stealCurrents();
(*ref_times)[slew_index] = waveform->referenceTime();
}
else
libWarn(1221, group, "output current waveform %.2e %.2e not found.",
waveform->slew(),
waveform->cap());
}
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);
timing_->setOutputWaveforms(rf_, output_current);
output_currents_.deleteContentsClear();
}
sort(slew_values, std::less<float>());
sort(cap_values, std::less<float>());
TableAxisPtr slew_axis = make_shared<TableAxis>(TableAxisVariable::input_net_transition,
slew_values);
TableAxisPtr cap_axis = make_shared<TableAxis>(TableAxisVariable::total_output_net_capacitance,
cap_values);
FloatSeq *ref_times = new FloatSeq(slew_values->size());
Table1Seq current_waveforms(slew_axis->size() * cap_axis->size());
for (OutputWaveform *waveform : output_currents_) {
size_t slew_index, cap_index;
bool slew_exists, cap_exists;
slew_axis->findAxisIndex(waveform->slew(), slew_index, slew_exists);
cap_axis->findAxisIndex(waveform->cap(), cap_index, cap_exists);
if (slew_exists && cap_exists) {
size_t index = slew_index * cap_axis->size() + cap_index;
current_waveforms[index] = waveform->stealCurrents();
(*ref_times)[slew_index] = waveform->referenceTime();
}
else
libWarn(1221, group, "output current waveform %.2e %.2e not found.",
waveform->slew(),
waveform->cap());
}
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);
timing_->setOutputWaveforms(rf_, output_current);
output_currents_.deleteContentsClear();
}
void

View File

@ -1664,17 +1664,19 @@ OutputWaveforms::checkAxes(const TableTemplate *tbl_template)
}
void
OutputWaveforms::makeVoltageWaveforms(float vdd)
OutputWaveforms::ensureVoltageWaveforms(float vdd)
{
vdd_ = vdd;
size_t size = current_waveforms_.size();
voltage_waveforms_.resize(size);
voltage_currents_.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_count; cap_index++) {
size_t wave_index = slew_index * cap_count + cap_index;
findVoltages(wave_index, cap_axis_->axisValue(cap_index));
if (voltage_waveforms_.empty()) {
vdd_ = vdd;
size_t size = current_waveforms_.size();
voltage_waveforms_.resize(size);
voltage_currents_.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_count; cap_index++) {
size_t wave_index = slew_index * cap_count + cap_index;
findVoltages(wave_index, cap_axis_->axisValue(cap_index));
}
}
}
}

View File

@ -29,6 +29,7 @@
namespace sta {
using std::abs;
using std::min;
using std::to_string;

103
sdc/Sdc.i
View File

@ -1270,30 +1270,41 @@ all_outputs_cmd()
return sta->sdc()->allOutputs();
}
template <typename T> Vector<T*>
filter_objects(const char *property,
const char *op,
const char *pattern,
Vector<T*> *objects)
{
Vector<T*> filtered_objects;
if (objects) {
Sta *sta = Sta::sta();
bool exact_match = stringEq(op, "==");
bool pattern_match = stringEq(op, "=~");
bool not_match = stringEq(op, "!=");
bool not_pattern_match = stringEq(op, "!~");
for (T *object : *objects) {
PropertyValue value(getProperty(object, property, sta));
const char *prop = value.asString(sta->network());
if (prop &&
((exact_match && stringEq(prop, pattern))
|| (not_match && !stringEq(prop, pattern))
|| (pattern_match && patternMatch(pattern, prop))
|| (not_pattern_match && !patternMatch(pattern, prop))))
filtered_objects.push_back(object);
}
delete objects;
}
return filtered_objects;
}
PortSeq
filter_ports(const char *property,
const char *op,
const char *pattern,
PortSeq *ports)
{
PortSeq filtered_ports;
if (ports) {
Sta *sta = Sta::sta();
bool exact_match = stringEq(op, "==");
bool pattern_match = stringEq(op, "=~");
bool not_match = stringEq(op, "!=");
for (const Port *port : *ports) {
PropertyValue value(getProperty(port, property, sta));
const char *prop = value.stringValue();
if (prop &&
((exact_match && stringEq(prop, pattern))
|| (not_match && !stringEq(prop, pattern))
|| (pattern_match && patternMatch(pattern, prop))))
filtered_ports.push_back(port);
}
delete ports;
}
return filtered_ports;
return filter_objects<const Port>(property, op, pattern, ports);
}
InstanceSeq
@ -1302,25 +1313,7 @@ filter_insts(const char *property,
const char *pattern,
InstanceSeq *insts)
{
InstanceSeq filtered_insts;
if (insts) {
Sta *sta = Sta::sta();
cmdLinkedNetwork();
bool exact_match = stringEq(op, "==");
bool pattern_match = stringEq(op, "=~");
bool not_match = stringEq(op, "!=");
for (const Instance *inst : *insts) {
PropertyValue value(getProperty(inst, property, sta));
const char *prop = value.stringValue();
if (prop &&
((exact_match && stringEq(prop, pattern))
|| (not_match && !stringEq(prop, pattern))
|| (pattern_match && patternMatch(pattern, prop))))
filtered_insts.push_back(inst);
}
delete insts;
}
return filtered_insts;
return filter_objects<const Instance>(property, op, pattern, insts);
}
PinSeq
@ -1329,24 +1322,7 @@ filter_pins(const char *property,
const char *pattern,
PinSeq *pins)
{
PinSeq filtered_pins;
if (pins) {
Sta *sta = Sta::sta();
bool exact_match = stringEq(op, "==");
bool pattern_match = stringEq(op, "=~");
bool not_match = stringEq(op, "!=");
for (const Pin *pin : *pins) {
PropertyValue value(getProperty(pin, property, sta));
const char *prop = value.asString(sta->sdcNetwork());
if (prop &&
((exact_match && stringEq(prop, pattern))
|| (not_match && !stringEq(prop, pattern))
|| (pattern_match && patternMatch(pattern, prop))))
filtered_pins.push_back(pin);
}
delete pins;
}
return filtered_pins;
return filter_objects<const Pin>(property, op, pattern, pins);
}
EdgeSeq
@ -1355,22 +1331,7 @@ filter_timing_arcs(const char *property,
const char *pattern,
EdgeSeq *edges)
{
Sta *sta = Sta::sta();
EdgeSeq filtered_edges;
bool exact_match = stringEq(op, "==");
bool pattern_match = stringEq(op, "=~");
bool not_match = stringEq(op, "!=");
for (Edge *edge : *edges) {
PropertyValue value(getProperty(edge, property, sta));
const char *prop = value.stringValue();
if (prop &&
((exact_match && stringEq(prop, pattern))
|| (not_match && !stringEq(prop, pattern))
|| (pattern_match && patternMatch(pattern, prop))))
filtered_edges.push_back(edge);
}
delete edges;
return filtered_edges;
return filter_objects<sta::Edge>(property, op, pattern, edges);
}
////////////////////////////////////////////////////////////////

View File

@ -935,7 +935,7 @@ proc get_ports { args } {
return $ports
}
variable filter_regexp1 {@?([a-zA-Z_]+) *(==|!=|=~) *([0-9a-zA-Z_\*]+)}
variable filter_regexp1 {@?([a-zA-Z_]+) *(==|!=|=~|!~) *([0-9a-zA-Z_\*]+)}
variable filter_or_regexp "($filter_regexp1) *\\|\\| *($filter_regexp1)"
variable filter_and_regexp "($filter_regexp1) *&& *($filter_regexp1)"

View File

@ -126,6 +126,35 @@ PropertyUnknown::what() const noexcept
////////////////////////////////////////////////////////////////
class PropertyTypeWrong : public Exception
{
public:
PropertyTypeWrong(const char *accessor,
const char *type);
virtual ~PropertyTypeWrong() {}
virtual const char *what() const noexcept;
private:
const char *accessor_;
const char *type_;
};
PropertyTypeWrong::PropertyTypeWrong(const char *accessor,
const char *type) :
Exception(),
accessor_(accessor),
type_(type)
{
}
const char *
PropertyTypeWrong::what() const noexcept
{
return stringPrint("property accessor %s is only valid for %s properties.",
accessor_, type_);
}
////////////////////////////////////////////////////////////////
PropertyValue::PropertyValue() :
type_(type_none),
unit_(nullptr)
@ -620,6 +649,30 @@ PropertyValue::asString(const Network *network) const
return nullptr;
}
const char *
PropertyValue::stringValue() const
{
if (type_ != Type::type_string)
throw PropertyTypeWrong("stringValue", "string");
return string_;
}
float
PropertyValue::floatValue() const
{
if (type_ != Type::type_float)
throw PropertyTypeWrong("floatValue", "float");
return float_;
}
bool
PropertyValue::boolValue() const
{
if (type_ != Type::type_bool)
throw PropertyTypeWrong("boolValue", "boolt");
return bool_;
}
////////////////////////////////////////////////////////////////
PropertyValue

View File

@ -148,6 +148,7 @@ Sim::funcBddSim(const FuncExpr *expr,
}
}
}
delete pin_iter;
return bdd;
}

View File

@ -192,7 +192,7 @@ tclListNetworkSet1(Tcl_Obj *const source,
return set;
}
StringSet *
static StringSet *
tclListSetConstChar(Tcl_Obj *const source,
Tcl_Interp *interp)
{
@ -212,7 +212,7 @@ tclListSetConstChar(Tcl_Obj *const source,
return nullptr;
}
StringSeq *
static StringSeq *
tclListSeqConstChar(Tcl_Obj *const source,
Tcl_Interp *interp)
{
@ -232,7 +232,7 @@ tclListSeqConstChar(Tcl_Obj *const source,
return nullptr;
}
StdStringSet *
static StdStringSet *
tclListSetStdString(Tcl_Obj *const source,
Tcl_Interp *interp)
{
@ -317,7 +317,7 @@ setPtrTclList(SET_TYPE *set,
////////////////////////////////////////////////////////////////
void
static void
tclArgError(Tcl_Interp *interp,
const char *msg,
const char *arg)
@ -330,7 +330,7 @@ tclArgError(Tcl_Interp *interp,
stringDelete(error);
}
void
static void
objectListNext(const char *list,
const char *type,
// Return values.
@ -366,7 +366,7 @@ objectListNext(const char *list,
}
}
Tcl_Obj *
static Tcl_Obj *
tclArcDcalcArg(ArcDcalcArg &gate,
Tcl_Interp *interp)
{
@ -405,7 +405,7 @@ tclArcDcalcArg(ArcDcalcArg &gate,
return list;
}
ArcDcalcArg
static ArcDcalcArg
arcDcalcArgTcl(Tcl_Obj *obj,
Tcl_Interp *interp)
{

View File

@ -0,0 +1,93 @@
library (one_to_one_mismatched_width) {
delay_model : "table_lookup";
simulation : false;
capacitive_load_unit (1,pF);
leakage_power_unit : "1pW";
current_unit : "1A";
pulling_resistance_unit : "1kohm";
time_unit : "1ns";
voltage_unit : "1v";
library_features : "report_delay_calculation";
input_threshold_pct_rise : 50;
input_threshold_pct_fall : 50;
output_threshold_pct_rise : 50;
output_threshold_pct_fall : 50;
slew_lower_threshold_pct_rise : 30;
slew_lower_threshold_pct_fall : 30;
slew_upper_threshold_pct_rise : 70;
slew_upper_threshold_pct_fall : 70;
slew_derate_from_library : 1.0;
nom_process : 1.0;
nom_temperature : 85.0;
nom_voltage : 0.75;
type (bus8) {
base_type : "array";
data_type : "bit";
bit_width : 8;
bit_from : 7;
bit_to : 0;
}
type (bus4) {
base_type : "array";
data_type : "bit";
bit_width : 4;
bit_from : 3;
bit_to : 0;
}
cell (inv_8_to_4) {
bus (A) {
capacitance : 1;
bus_type : "bus8";
direction : "input";
}
bus (Y) {
function : "!A";
bus_type : "bus4";
direction : "output";
timing () {
related_pin : "A";
cell_rise (scalar) {
values ("1");
}
cell_fall (scalar) {
values ("1");
}
rise_transition (scalar) {
values ("1");
}
fall_transition (scalar) {
values ("1");
}
}
}
}
cell (inv_4_to_8) {
bus (A) {
capacitance : 1;
bus_type : "bus4";
direction : "input";
}
bus (Y) {
function : "!A";
bus_type : "bus8";
direction : "output";
timing () {
related_pin : "A";
cell_rise (scalar) {
values ("1");
}
cell_fall (scalar) {
values ("1");
}
rise_transition (scalar) {
values ("1");
}
fall_transition (scalar) {
values ("1");
}
}
}
}
}

View File

@ -0,0 +1,220 @@
Warning: liberty_arcs_one2one.lib line 48, timing port A and related port Y are different sizes.
Warning: liberty_arcs_one2one.lib line 76, timing port A and related port Y are different sizes.
TEST 1:
Startpoint: a[0] (input port clocked by clk)
Endpoint: y[0] (output port clocked by clk)
Path Group: clk
Path Type: max
Delay Time Description
---------------------------------------------------------
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 v input external delay
0.00 0.00 v a[0] (in)
1.00 1.00 ^ partial_wide_inv_cell/Y[0] (inv_8_to_4)
0.00 1.00 ^ y[0] (out)
1.00 data arrival time
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 clock reconvergence pessimism
0.00 0.00 output external delay
0.00 data required time
---------------------------------------------------------
0.00 data required time
-1.00 data arrival time
---------------------------------------------------------
-1.00 slack (VIOLATED)
Startpoint: a[1] (input port clocked by clk)
Endpoint: y[1] (output port clocked by clk)
Path Group: clk
Path Type: max
Delay Time Description
---------------------------------------------------------
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 v input external delay
0.00 0.00 v a[1] (in)
1.00 1.00 ^ partial_wide_inv_cell/Y[1] (inv_8_to_4)
0.00 1.00 ^ y[1] (out)
1.00 data arrival time
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 clock reconvergence pessimism
0.00 0.00 output external delay
0.00 data required time
---------------------------------------------------------
0.00 data required time
-1.00 data arrival time
---------------------------------------------------------
-1.00 slack (VIOLATED)
Startpoint: a[2] (input port clocked by clk)
Endpoint: y[2] (output port clocked by clk)
Path Group: clk
Path Type: max
Delay Time Description
---------------------------------------------------------
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 v input external delay
0.00 0.00 v a[2] (in)
1.00 1.00 ^ partial_wide_inv_cell/Y[2] (inv_8_to_4)
0.00 1.00 ^ y[2] (out)
1.00 data arrival time
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 clock reconvergence pessimism
0.00 0.00 output external delay
0.00 data required time
---------------------------------------------------------
0.00 data required time
-1.00 data arrival time
---------------------------------------------------------
-1.00 slack (VIOLATED)
Startpoint: a[3] (input port clocked by clk)
Endpoint: y[3] (output port clocked by clk)
Path Group: clk
Path Type: max
Delay Time Description
---------------------------------------------------------
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 v input external delay
0.00 0.00 v a[3] (in)
1.00 1.00 ^ partial_wide_inv_cell/Y[3] (inv_8_to_4)
0.00 1.00 ^ y[3] (out)
1.00 data arrival time
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 clock reconvergence pessimism
0.00 0.00 output external delay
0.00 data required time
---------------------------------------------------------
0.00 data required time
-1.00 data arrival time
---------------------------------------------------------
-1.00 slack (VIOLATED)
TEST 2:
Startpoint: a[0] (input port clocked by clk)
Endpoint: y[0] (output port clocked by clk)
Path Group: clk
Path Type: max
Delay Time Description
---------------------------------------------------------
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 v input external delay
0.00 0.00 v a[0] (in)
1.00 1.00 ^ partial_wide_inv_cell/Y[0] (inv_4_to_8)
0.00 1.00 ^ y[0] (out)
1.00 data arrival time
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 clock reconvergence pessimism
0.00 0.00 output external delay
0.00 data required time
---------------------------------------------------------
0.00 data required time
-1.00 data arrival time
---------------------------------------------------------
-1.00 slack (VIOLATED)
Startpoint: a[1] (input port clocked by clk)
Endpoint: y[1] (output port clocked by clk)
Path Group: clk
Path Type: max
Delay Time Description
---------------------------------------------------------
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 v input external delay
0.00 0.00 v a[1] (in)
1.00 1.00 ^ partial_wide_inv_cell/Y[1] (inv_4_to_8)
0.00 1.00 ^ y[1] (out)
1.00 data arrival time
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 clock reconvergence pessimism
0.00 0.00 output external delay
0.00 data required time
---------------------------------------------------------
0.00 data required time
-1.00 data arrival time
---------------------------------------------------------
-1.00 slack (VIOLATED)
Startpoint: a[2] (input port clocked by clk)
Endpoint: y[2] (output port clocked by clk)
Path Group: clk
Path Type: max
Delay Time Description
---------------------------------------------------------
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 v input external delay
0.00 0.00 v a[2] (in)
1.00 1.00 ^ partial_wide_inv_cell/Y[2] (inv_4_to_8)
0.00 1.00 ^ y[2] (out)
1.00 data arrival time
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 clock reconvergence pessimism
0.00 0.00 output external delay
0.00 data required time
---------------------------------------------------------
0.00 data required time
-1.00 data arrival time
---------------------------------------------------------
-1.00 slack (VIOLATED)
Startpoint: a[3] (input port clocked by clk)
Endpoint: y[3] (output port clocked by clk)
Path Group: clk
Path Type: max
Delay Time Description
---------------------------------------------------------
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 v input external delay
0.00 0.00 v a[3] (in)
1.00 1.00 ^ partial_wide_inv_cell/Y[3] (inv_4_to_8)
0.00 1.00 ^ y[3] (out)
1.00 data arrival time
0.00 0.00 clock clk (rise edge)
0.00 0.00 clock network delay (ideal)
0.00 0.00 clock reconvergence pessimism
0.00 0.00 output external delay
0.00 data required time
---------------------------------------------------------
0.00 data required time
-1.00 data arrival time
---------------------------------------------------------
-1.00 slack (VIOLATED)

View File

@ -0,0 +1,17 @@
read_liberty liberty_arcs_one2one.lib
puts "TEST 1:"
read_verilog liberty_arcs_one2one_1.v
link_design liberty_arcs_one2one_1
create_clock -name clk -period 0
set_input_delay -clock clk 0 [all_inputs]
set_output_delay -clock clk 0 [all_outputs]
report_checks -group_count 5
puts "TEST 2:"
read_verilog liberty_arcs_one2one_2.v
link_design liberty_arcs_one2one_2
create_clock -name clk -period 0
set_input_delay -clock clk 0 [all_inputs]
set_output_delay -clock clk 0 [all_outputs]
report_checks -group_count 5

View File

@ -0,0 +1,13 @@
// Liberty file test: one-to-one mapping with mismatched bit widths
// Should generate warning but still create timing arcs between bits with same index
module liberty_arcs_one2one_1 (
input wire [7:0] a,
output wire [3:0] y
);
inv_8_to_4 partial_wide_inv_cell (
.A(a),
.Y(y)
);
endmodule

View File

@ -0,0 +1,13 @@
// Liberty file test: one-to-one mapping with mismatched bit widths
// Should generate warning but still create timing arcs between bits with same index
module liberty_arcs_one2one_2 (
input wire [3:0] a,
output wire [7:0] y
);
inv_4_to_8 partial_wide_inv_cell (
.A(a),
.Y(y)
);
endmodule

View File

@ -124,6 +124,7 @@ record_example_tests {
record_sta_tests {
prima3
verilog_attribute
liberty_arcs_one2one
}
define_test_group fast [group_tests all]