Merge remote-tracking branch 'parallax/master'
Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
This commit is contained in:
commit
2a8accc2ea
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
|
|
@ -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_);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
BIN
doc/OpenSTA.odt
BIN
doc/OpenSTA.odt
Binary file not shown.
BIN
doc/OpenSTA.pdf
BIN
doc/OpenSTA.pdf
Binary file not shown.
|
|
@ -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]]
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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_; }
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
|
||||
namespace sta {
|
||||
|
||||
using std::abs;
|
||||
using std::min;
|
||||
using std::to_string;
|
||||
|
||||
|
|
|
|||
103
sdc/Sdc.i
103
sdc/Sdc.i
|
|
@ -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);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -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)"
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -148,6 +148,7 @@ Sim::funcBddSim(const FuncExpr *expr,
|
|||
}
|
||||
}
|
||||
}
|
||||
delete pin_iter;
|
||||
return bdd;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -124,6 +124,7 @@ record_example_tests {
|
|||
record_sta_tests {
|
||||
prima3
|
||||
verilog_attribute
|
||||
liberty_arcs_one2one
|
||||
}
|
||||
|
||||
define_test_group fast [group_tests all]
|
||||
|
|
|
|||
Loading…
Reference in New Issue