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) set(TCL_READLINE 0)
# check for tclReadline # check for tclReadline
if (USE_TCL_READLINE) 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) if (TCL_READLINE_LIBRARY)
message(STATUS "TCL readline: ${TCL_READLINE_LIBRARY}") message(STATUS "TCL readline library: ${TCL_READLINE_LIBRARY}")
# Referenced by StaConfig.hh.cmake # Referenced by StaConfig.hh.cmake
set(TCL_READLINE 1) set(TCL_READLINE 1)
endif()
get_filename_component(TCL_READLINE_LIB_DIR "${TCL_READLINE_LIBRARY}" PATH) find_path(TCL_READLINE_INCLUDE tclreadline.h)
get_filename_component(TCL_READLINE_LIB_PARENT "${TCL_READLINE_LIB_DIR}" PATH) if (TCL_READLINE_INCLUDE)
find_file(TCL_READLINE_HEADER tclreadline.h message(STATUS "TCL readline header: ${TCL_READLINE_INCLUDE}/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")
endif() endif()
endif() endif()

View File

@ -54,7 +54,7 @@ ArcDcalcWaveforms::inputWaveform(ArcDcalcArg &dcalc_arg,
library->supplyVoltage("VDD", vdd, vdd_exists); library->supplyVoltage("VDD", vdd, vdd_exists);
if (!vdd_exists) if (!vdd_exists)
report->error(1751, "VDD not defined in library %s", library->name()); 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. // Delay time axis.
FloatSeq *time_values = new FloatSeq; FloatSeq *time_values = new FloatSeq;
for (float time : *in_waveform.axis1()->values()) 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_; vl_ = drvr_library->slewLowerThreshold(drvr_rf_) * vdd_;
vh_ = drvr_library->slewUpperThreshold(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); in_slew_ = delayAsFloat(in_slew);
output_waveforms_ = output_waveforms; output_waveforms_ = output_waveforms;
ref_time_ = output_waveforms_->referenceTime(in_slew_); ref_time_ = output_waveforms_->referenceTime(in_slew_);

View File

@ -202,15 +202,17 @@ PrimaDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
dcalc_ap_ = dcalc_ap; dcalc_ap_ = dcalc_ap;
drvr_rf_ = dcalc_args[0].arc()->toEdge()->asRiseFall(); drvr_rf_ = dcalc_args[0].arc()->toEdge()->asRiseFall();
parasitic_network_ = dcalc_args[0].parasitic(); parasitic_network_ = dcalc_args[0].parasitic();
load_cap_ = dcalc_args[0].loadCap();
bool failed = false; bool failed = false;
output_waveforms_.resize(drvr_count_); output_waveforms_.resize(drvr_count_);
const DcalcAnalysisPtSeq &dcalc_aps = corners_->dcalcAnalysisPts();
for (size_t drvr_idx = 0; drvr_idx < drvr_count_; drvr_idx++) { for (size_t drvr_idx = 0; drvr_idx < drvr_count_; drvr_idx++) {
ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx]; ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx];
GateTableModel *table_model = dcalc_arg.arc()->gateTableModel(dcalc_ap); GateTableModel *table_model = dcalc_arg.arc()->gateTableModel(dcalc_ap);
if (table_model && dcalc_arg.parasitic()) { if (table_model && dcalc_arg.parasitic()) {
OutputWaveforms *output_waveforms = table_model->outputWaveforms(); OutputWaveforms *output_waveforms = table_model->outputWaveforms();
Slew in_slew = dcalc_arg.inSlew(); float in_slew = dcalc_arg.inSlewFlt();
if (output_waveforms if (output_waveforms
// Bounds check because extrapolating waveforms does not work for shit. // Bounds check because extrapolating waveforms does not work for shit.
&& output_waveforms->slewAxis()->inBounds(in_slew) && output_waveforms->slewAxis()->inBounds(in_slew)
@ -225,7 +227,7 @@ PrimaDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args,
drvr_library->supplyVoltage("VDD", vdd_, vdd_exists); drvr_library->supplyVoltage("VDD", vdd_, vdd_exists);
if (!vdd_exists) if (!vdd_exists)
report_->error(1720, "VDD not defined in library %s", drvr_library->name()); 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) { if (drvr_idx == 0) {
vth_ = drvr_library->outputThreshold(drvr_rf_) * vdd_; vth_ = drvr_library->outputThreshold(drvr_rf_) * vdd_;
vl_ = drvr_library->slewLowerThreshold(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; v_ = v_prev_ = x_to_v * x_init;
// voltageTime is always for a rising waveform so 0.0v is initial voltage. // 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); ceff_[0], 0.0);
// Limit in case load voltage waveforms don't get to final value. // Limit in case load voltage waveforms don't get to final value.
double time_end = time_begin + maxTime(); double time_end = time_begin + maxTime();
@ -368,7 +370,7 @@ PrimaDelayCalc::timeStep()
double double
PrimaDelayCalc::maxTime() PrimaDelayCalc::maxTime()
{ {
return (*dcalc_args_)[0].inSlew() return (*dcalc_args_)[0].inSlewFlt()
+ (driverResistance() + resistance_sum_) * load_cap_ * 4; + (driverResistance() + resistance_sum_) * load_cap_ * 4;
} }
@ -484,7 +486,7 @@ PrimaDelayCalc::initCeffIdrvr()
ceff_[drvr_idx] = load_cap_; ceff_[drvr_idx] = load_cap_;
// voltageTime is always for a rising waveform so 0.0v is initial voltage. // voltageTime is always for a rising waveform so 0.0v is initial voltage.
drvr_current_[drvr_idx] = 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); ceff_[drvr_idx], 0.0);
} }
} }
@ -615,7 +617,7 @@ PrimaDelayCalc::updateCeffIdrvr()
drvr_current_[drvr_idx] = 0.0; drvr_current_[drvr_idx] = 0.0;
else else
drvr_current_[drvr_idx] = drvr_current_[drvr_idx] =
output_waveforms_[drvr_idx]->voltageCurrent(dcalc_arg.inSlew(), output_waveforms_[drvr_idx]->voltageCurrent(dcalc_arg.inSlewFlt(),
ceff_[drvr_idx], v1); ceff_[drvr_idx], v1);
} }
else { else {
@ -631,7 +633,7 @@ PrimaDelayCalc::updateCeffIdrvr()
} }
else else
drvr_current_[drvr_idx] = drvr_current_[drvr_idx] =
output_waveforms_[drvr_idx]->voltageCurrent(dcalc_arg.inSlew(), output_waveforms_[drvr_idx]->voltageCurrent(dcalc_arg.inSlewFlt(),
ceff_[drvr_idx], ceff_[drvr_idx],
vdd_ - v1); vdd_ - v1);
} }
@ -708,7 +710,7 @@ PrimaDelayCalc::dcalcResults()
const LibertyLibrary *drvr_library = dcalc_arg.drvrLibrary(); const LibertyLibrary *drvr_library = dcalc_arg.drvrLibrary();
size_t drvr_node = pin_node_map_[drvr_pin]; size_t drvr_node = pin_node_map_[drvr_pin];
ThresholdTimes &drvr_times = threshold_times_[drvr_node]; 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; ArcDelay gate_delay = drvr_times[threshold_vth] - ref_time;
Slew drvr_slew = abs(drvr_times[threshold_vh] - drvr_times[threshold_vl]); Slew drvr_slew = abs(drvr_times[threshold_vh] - drvr_times[threshold_vl]);
dcalc_result.setGateDelay(gate_delay); 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] { foreach edge [disabled_edges_sorted] {
if { [$edge role] == "wire" } { if { [$edge role] == "wire" } {
set from_pin_name [get_full_name [[$edge from] pin]] 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 *, float, CharPtrLess> SupplyVoltageMap;
typedef Map<const char *, LibertyPgPort*, CharPtrLess> LibertyPgPortMap; typedef Map<const char *, LibertyPgPort*, CharPtrLess> LibertyPgPortMap;
typedef Map<const char *, DriverWaveform*, CharPtrLess> DriverWaveformMap; typedef Map<const char *, DriverWaveform*, CharPtrLess> DriverWaveformMap;
typedef Vector<DcalcAnalysisPt*> DcalcAnalysisPtSeq;
enum class ClockGateType { none, latch_posedge, latch_negedge, other }; enum class ClockGateType { none, latch_posedge, latch_negedge, other };
@ -532,7 +533,7 @@ public:
// Check all liberty cells to make sure they exist // Check all liberty cells to make sure they exist
// for all the defined corners. // for all the defined corners.
static void checkLibertyCorners(); static void checkLibertyCorners();
void ensureVoltageWaveforms(const DcalcAnalysisPt *dcalc_ap); void ensureVoltageWaveforms(const DcalcAnalysisPtSeq &dcalc_aps);
protected: protected:
void addPort(ConcretePort *port); void addPort(ConcretePort *port);
@ -555,7 +556,10 @@ protected:
const LibertyPort *en, const LibertyPort *en,
const RiseFall *en_rf, const RiseFall *en_rf,
const LibertyPort *q, const LibertyPort *q,
const TimingArcSet *en_to_q,
Report *report); Report *report);
bool condMatch(const TimingArcSet *arc_set1,
const TimingArcSet *arc_set2);
void findDefaultCondArcs(); void findDefaultCondArcs();
void translatePresetClrCheckRoles(); void translatePresetClrCheckRoles();
void inferLatchRoles(Report *report, void inferLatchRoles(Report *report,
@ -837,6 +841,7 @@ protected:
void setMinPort(LibertyPort *min); void setMinPort(LibertyPort *min);
void addScaledPort(OperatingConditions *op_cond, void addScaledPort(OperatingConditions *op_cond,
LibertyPort *scaled_port); LibertyPort *scaled_port);
RiseFallMinMax clkTreeDelays1() const;
LibertyCell *liberty_cell_; LibertyCell *liberty_cell_;
BusDcl *bus_dcl_; BusDcl *bus_dcl_;

View File

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

View File

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

View File

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

View File

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

View File

@ -2351,7 +2351,8 @@ TimingGroup::makeTableModels(LibertyCell *cell,
if (delay == nullptr) if (delay == nullptr)
reader->libWarn(1211, line_, "missing cell_%s.", rf->name()); reader->libWarn(1211, line_, "missing cell_%s.", rf->name());
} }
} else if (constraint) }
else if (constraint)
attrs_->setModel(rf, new CheckTableModel(cell, constraint, attrs_->setModel(rf, new CheckTableModel(cell, constraint,
constraint_sigma_[rf_index])); constraint_sigma_[rf_index]));
} }
@ -2401,11 +2402,28 @@ LibertyReader::makeTimingArcs(const char *from_port_name,
else { else {
// bus -> bus // bus -> bus
if (timing->isOneToOne()) { if (timing->isOneToOne()) {
if (static_cast<int>(from_port_iter.size()) == to_port->size()) { int from_size = from_port_iter.size();
LibertyPortMemberIterator to_iter(to_port); int to_size = to_port->size();
while (from_port_iter.hasNext() && to_iter.hasNext()) { 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 *from_port_bit = from_port_iter.next();
LibertyPort *to_port_bit = to_iter.next(); LibertyPort *to_port_bit = to_port_iter.next();
if (from_port_bit->direction()->isOutput()) if (from_port_bit->direction()->isOutput())
libWarn(1215, timing->line(), "timing group from output port."); libWarn(1215, timing->line(), "timing group from output port.");
builder_.makeTimingArcs(cell_, from_port_bit, to_port_bit, builder_.makeTimingArcs(cell_, from_port_bit, to_port_bit,
@ -2413,12 +2431,6 @@ LibertyReader::makeTimingArcs(const char *from_port_name,
timing->line()); timing->line());
} }
} }
else
libWarn(1216, timing->line(),
"timing port %s and related port %s are different sizes.",
from_port_name,
to_port->name());
}
else { else {
while (from_port_iter.hasNext()) { while (from_port_iter.hasNext()) {
LibertyPort *from_port_bit = from_port_iter.next(); LibertyPort *from_port_bit = from_port_iter.next();
@ -2534,17 +2546,18 @@ LibertyReader::endReceiverCapacitanceRiseFall(LibertyGroup *group)
if (ReceiverModel::checkAxes(table_)) { if (ReceiverModel::checkAxes(table_)) {
TableModel *table_model = new TableModel(table_, tbl_template_, TableModel *table_model = new TableModel(table_, tbl_template_,
scale_factor_type_, rf_); scale_factor_type_, rf_);
if (timing_ && receiver_model_ == nullptr) { if (receiver_model_ == nullptr) {
receiver_model_ = make_shared<ReceiverModel>(); receiver_model_ = make_shared<ReceiverModel>();
if (timing_)
timing_->setReceiverModel(receiver_model_); timing_->setReceiverModel(receiver_model_);
} }
receiver_model_->setCapacitanceModel(table_model, index_, rf_); receiver_model_->setCapacitanceModel(table_model, index_, rf_);
} }
else else
libWarn(1219, group, "unsupported model axis."); libWarn(1219, group, "unsupported model axis.");
}
endTableModel(); endTableModel();
} }
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
@ -2576,6 +2589,7 @@ LibertyReader::beginOutputCurrent(RiseFall *rf,
void void
LibertyReader::endOutputCurrentRiseFall(LibertyGroup *group) LibertyReader::endOutputCurrentRiseFall(LibertyGroup *group)
{ {
if (timing_) {
Set<float> slew_set, cap_set; Set<float> slew_set, cap_set;
FloatSeq *slew_values = new FloatSeq; FloatSeq *slew_values = new FloatSeq;
FloatSeq *cap_values = new FloatSeq; FloatSeq *cap_values = new FloatSeq;
@ -2621,6 +2635,7 @@ LibertyReader::endOutputCurrentRiseFall(LibertyGroup *group)
timing_->setOutputWaveforms(rf_, output_current); timing_->setOutputWaveforms(rf_, output_current);
output_currents_.deleteContentsClear(); output_currents_.deleteContentsClear();
} }
}
void void
LibertyReader::beginVector(LibertyGroup *group) LibertyReader::beginVector(LibertyGroup *group)

View File

@ -1664,8 +1664,9 @@ OutputWaveforms::checkAxes(const TableTemplate *tbl_template)
} }
void void
OutputWaveforms::makeVoltageWaveforms(float vdd) OutputWaveforms::ensureVoltageWaveforms(float vdd)
{ {
if (voltage_waveforms_.empty()) {
vdd_ = vdd; vdd_ = vdd;
size_t size = current_waveforms_.size(); size_t size = current_waveforms_.size();
voltage_waveforms_.resize(size); voltage_waveforms_.resize(size);
@ -1678,6 +1679,7 @@ OutputWaveforms::makeVoltageWaveforms(float vdd)
} }
} }
} }
}
void void
OutputWaveforms::findVoltages(size_t wave_index, OutputWaveforms::findVoltages(size_t wave_index,

View File

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

103
sdc/Sdc.i
View File

@ -1270,30 +1270,41 @@ all_outputs_cmd()
return sta->sdc()->allOutputs(); 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 PortSeq
filter_ports(const char *property, filter_ports(const char *property,
const char *op, const char *op,
const char *pattern, const char *pattern,
PortSeq *ports) PortSeq *ports)
{ {
PortSeq filtered_ports; return filter_objects<const Port>(property, op, pattern, 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;
} }
InstanceSeq InstanceSeq
@ -1302,25 +1313,7 @@ filter_insts(const char *property,
const char *pattern, const char *pattern,
InstanceSeq *insts) InstanceSeq *insts)
{ {
InstanceSeq filtered_insts; return filter_objects<const Instance>(property, op, pattern, 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;
} }
PinSeq PinSeq
@ -1329,24 +1322,7 @@ filter_pins(const char *property,
const char *pattern, const char *pattern,
PinSeq *pins) PinSeq *pins)
{ {
PinSeq filtered_pins; return filter_objects<const Pin>(property, op, pattern, 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;
} }
EdgeSeq EdgeSeq
@ -1355,22 +1331,7 @@ filter_timing_arcs(const char *property,
const char *pattern, const char *pattern,
EdgeSeq *edges) EdgeSeq *edges)
{ {
Sta *sta = Sta::sta(); return filter_objects<sta::Edge>(property, op, pattern, edges);
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;
} }
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////

View File

@ -935,7 +935,7 @@ proc get_ports { args } {
return $ports 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_or_regexp "($filter_regexp1) *\\|\\| *($filter_regexp1)"
variable filter_and_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() : PropertyValue::PropertyValue() :
type_(type_none), type_(type_none),
unit_(nullptr) unit_(nullptr)
@ -620,6 +649,30 @@ PropertyValue::asString(const Network *network) const
return nullptr; 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 PropertyValue

View File

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

View File

@ -192,7 +192,7 @@ tclListNetworkSet1(Tcl_Obj *const source,
return set; return set;
} }
StringSet * static StringSet *
tclListSetConstChar(Tcl_Obj *const source, tclListSetConstChar(Tcl_Obj *const source,
Tcl_Interp *interp) Tcl_Interp *interp)
{ {
@ -212,7 +212,7 @@ tclListSetConstChar(Tcl_Obj *const source,
return nullptr; return nullptr;
} }
StringSeq * static StringSeq *
tclListSeqConstChar(Tcl_Obj *const source, tclListSeqConstChar(Tcl_Obj *const source,
Tcl_Interp *interp) Tcl_Interp *interp)
{ {
@ -232,7 +232,7 @@ tclListSeqConstChar(Tcl_Obj *const source,
return nullptr; return nullptr;
} }
StdStringSet * static StdStringSet *
tclListSetStdString(Tcl_Obj *const source, tclListSetStdString(Tcl_Obj *const source,
Tcl_Interp *interp) Tcl_Interp *interp)
{ {
@ -317,7 +317,7 @@ setPtrTclList(SET_TYPE *set,
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
void static void
tclArgError(Tcl_Interp *interp, tclArgError(Tcl_Interp *interp,
const char *msg, const char *msg,
const char *arg) const char *arg)
@ -330,7 +330,7 @@ tclArgError(Tcl_Interp *interp,
stringDelete(error); stringDelete(error);
} }
void static void
objectListNext(const char *list, objectListNext(const char *list,
const char *type, const char *type,
// Return values. // Return values.
@ -366,7 +366,7 @@ objectListNext(const char *list,
} }
} }
Tcl_Obj * static Tcl_Obj *
tclArcDcalcArg(ArcDcalcArg &gate, tclArcDcalcArg(ArcDcalcArg &gate,
Tcl_Interp *interp) Tcl_Interp *interp)
{ {
@ -405,7 +405,7 @@ tclArcDcalcArg(ArcDcalcArg &gate,
return list; return list;
} }
ArcDcalcArg static ArcDcalcArg
arcDcalcArgTcl(Tcl_Obj *obj, arcDcalcArgTcl(Tcl_Obj *obj,
Tcl_Interp *interp) 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 { record_sta_tests {
prima3 prima3
verilog_attribute verilog_attribute
liberty_arcs_one2one
} }
define_test_group fast [group_tests all] define_test_group fast [group_tests all]