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)
|
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()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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_);
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
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] {
|
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]]
|
||||||
|
|
|
||||||
|
|
@ -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_;
|
||||||
|
|
|
||||||
|
|
@ -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_; }
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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()) {
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
103
sdc/Sdc.i
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////
|
||||||
|
|
|
||||||
|
|
@ -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)"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,7 @@ Sim::funcBddSim(const FuncExpr *expr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
delete pin_iter;
|
||||||
return bdd;
|
return bdd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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 {
|
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]
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue