liberty min_pulse_width timing group support

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2024-04-17 11:49:19 -07:00
parent 4146e623d1
commit 60d8030a94
23 changed files with 221 additions and 255 deletions

View File

@ -1334,7 +1334,6 @@ ArnoldiDelayCalc::ra_get_s(delay_work *D,
tlohi = slew_derate*delayAsFloat(s1);
smin = r*c*c_smin; // c_smin = ra_hinv((1-vhi)/vhi-log(vhi)) + log(vhi);
if (c_log*r*c >= tlohi) {
// printf("hit smin\n");
s = smin;
} else {
s = smin+0.3*tlohi;
@ -1410,7 +1409,6 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D,
if (debug_->check("arnoldi", 1)) {
double p = 1.0/(r*ctot);
double thix,tlox;
if (bad) printf("bad\n");
debugPrint(debug_, "arnoldi", 1, "at r=%s s=%s",
units_->resistanceUnit()->asString(r),
units_->timeUnit()->asString(s));

View File

@ -1413,12 +1413,14 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge,
int slew_index = dcalc_ap->checkDataSlewIndex();
const Slew &to_slew = graph_->slew(to_vertex, to_rf, slew_index);
debugPrint(debug_, "delay_calc", 3,
" %s %s -> %s %s (%s)",
" %s %s -> %s %s (%s) corner:%s/%s",
arc_set->from()->name(),
arc->fromEdge()->asString(),
arc_set->to()->name(),
arc->toEdge()->asString(),
arc_set->role()->asString());
arc_set->role()->asString(),
dcalc_ap->corner()->name(),
dcalc_ap->delayMinMax()->asString());
debugPrint(debug_, "delay_calc", 3,
" from_slew = %s to_slew = %s",
delayAsString(from_slew, this),
@ -1426,7 +1428,7 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge,
float related_out_cap = 0.0;
if (related_out_pin)
related_out_cap = loadCap(related_out_pin, to_rf,dcalc_ap,arc_delay_calc);
ArcDelay check_delay = arc_delay_calc->checkDelay(to_pin, arc, from_slew,
ArcDelay check_delay = arc_delay_calc->checkDelay(to_pin, arc, from_slew,
to_slew, related_out_cap,
dcalc_ap);
debugPrint(debug_, "delay_calc", 3,
@ -1512,30 +1514,6 @@ GraphDelayCalc::reportDelayCalc(const Edge *edge,
////////////////////////////////////////////////////////////////
void
GraphDelayCalc::minPulseWidth(const Pin *pin,
const RiseFall *hi_low,
DcalcAPIndex ap_index,
const MinMax *min_max,
// Return values.
float &min_width,
bool &exists)
{
// Sdf annotation.
graph_->widthCheckAnnotation(pin, hi_low, ap_index,
min_width, exists);
if (!exists) {
// Liberty library.
LibertyPort *port = network_->libertyPort(pin);
if (port) {
Instance *inst = network_->instance(pin);
const Pvt *pvt = inst ? sdc_->pvt(inst, min_max) : nullptr;
OperatingConditions *op_cond=sdc_->operatingConditions(min_max);
port->minPulseWidth(hi_low, op_cond, pvt, min_width, exists);
}
}
}
void
GraphDelayCalc::minPeriod(const Pin *pin,
// Return values.

View File

@ -47,7 +47,6 @@ Graph::Graph(StaState *sta,
slew_rf_count_(slew_rf_count),
have_arc_delays_(have_arc_delays),
ap_count_(ap_count),
width_check_annotations_(nullptr),
period_check_annotations_(nullptr),
reg_clk_vertices_(new VertexSet(graph_))
{
@ -62,7 +61,6 @@ Graph::~Graph()
delete reg_clk_vertices_;
deleteSlewTables();
deleteArcDelayTables();
removeWidthCheckAnnotations();
removePeriodCheckAnnotations();
}
@ -205,9 +203,9 @@ Graph::makePortInstanceEdges(const Instance *inst,
// Vertices can be missing from the graph if the pins
// are power or ground.
if (from_vertex) {
bool is_check = arc_set->role()->isTimingCheck();
if (to_bidirect_drvr_vertex &&
!is_check)
TimingRole *role = arc_set->role();
bool is_check = role->isTimingCheckBetween();
if (to_bidirect_drvr_vertex && !is_check)
makeEdge(from_vertex, to_bidirect_drvr_vertex, arc_set);
else if (to_vertex) {
makeEdge(from_vertex, to_vertex, arc_set);
@ -856,7 +854,7 @@ Graph::arcDelayAnnotated(const Edge *edge,
const TimingArc *arc,
DcalcAPIndex ap_index) const
{
if (arc_delay_annotated_.size()) {
if (!arc_delay_annotated_.empty()) {
size_t index = (edge->arcDelays() + arc->index()) * ap_count_ + ap_index;
if (index >= arc_delay_annotated_.size())
report_->critical(1080, "arc_delay_annotated array bounds exceeded");
@ -912,7 +910,6 @@ Graph::setDelayCount(DcalcAPIndex ap_count)
// Discard any existing delays.
deleteSlewTables();
deleteArcDelayTables();
removeWidthCheckAnnotations();
removePeriodCheckAnnotations();
makeSlewTables(ap_count);
makeArcDelayTables(ap_count);
@ -955,11 +952,11 @@ Graph::delayAnnotated(Edge *edge)
TimingArcSet *arc_set = edge->timingArcSet();
for (TimingArc *arc : arc_set->arcs()) {
for (DcalcAPIndex ap_index = 0; ap_index < ap_count_; ap_index++) {
if (arcDelayAnnotated(edge, arc, ap_index))
return true;
if (!arcDelayAnnotated(edge, arc, ap_index))
return false;
}
}
return false;
return true;
}
void
@ -994,58 +991,28 @@ Graph::makeVertexSlews(Vertex *vertex)
////////////////////////////////////////////////////////////////
void
Graph::widthCheckAnnotation(const Pin *pin,
const RiseFall *rf,
DcalcAPIndex ap_index,
// Return values.
float &width,
bool &exists)
Graph::minPulseWidthArc(Vertex *vertex,
// high = rise, low = fall
const RiseFall *hi_low,
// Return values.
Edge *&edge,
TimingArc *&arc)
{
exists = false;
if (width_check_annotations_) {
float *widths = width_check_annotations_->findKey(pin);
if (widths) {
int index = ap_index * RiseFall::index_count + rf->index();
width = widths[index];
if (width >= 0.0)
exists = true;
VertexOutEdgeIterator edge_iter(vertex, this);
while (edge_iter.hasNext()) {
edge = edge_iter.next();
TimingArcSet *arc_set = edge->timingArcSet();
if (arc_set->role() == TimingRole::width()) {
for (TimingArc *arc1 : arc_set->arcs()) {
if (arc1->fromEdge()->asRiseFall() == hi_low) {
arc = arc1;
return;
}
}
}
}
}
void
Graph::setWidthCheckAnnotation(const Pin *pin,
const RiseFall *rf,
DcalcAPIndex ap_index,
float width)
{
if (width_check_annotations_ == nullptr)
width_check_annotations_ = new WidthCheckAnnotations;
float *widths = width_check_annotations_->findKey(pin);
if (widths == nullptr) {
int width_count = RiseFall::index_count * ap_count_;
widths = new float[width_count];
// Use negative (illegal) width values to indicate unannotated checks.
for (int i = 0; i < width_count; i++)
widths[i] = -1;
(*width_check_annotations_)[pin] = widths;
}
int index = ap_index * RiseFall::index_count + rf->index();
widths[index] = width;
}
void
Graph::removeWidthCheckAnnotations()
{
if (width_check_annotations_) {
WidthCheckAnnotations::Iterator check_iter(width_check_annotations_);
while (check_iter.hasNext()) {
float *widths = check_iter.next();
delete [] widths;
}
delete width_check_annotations_;
width_check_annotations_ = nullptr;
}
edge = nullptr;
arc = nullptr;
}
////////////////////////////////////////////////////////////////
@ -1112,7 +1079,6 @@ Graph::removeDelaySlewAnnotations()
}
vertex->removeSlewAnnotated();
}
removeWidthCheckAnnotations();
removePeriodCheckAnnotations();
}

View File

@ -46,7 +46,6 @@ typedef ArrayTable<Required> RequiredsTable;
typedef ArrayTable<PathVertexRep> PrevPathsTable;
typedef Map<const Pin*, Vertex*> PinVertexMap;
typedef Iterator<Edge*> VertexEdgeIterator;
typedef Map<const Pin*, float*> WidthCheckAnnotations;
typedef Map<const Pin*, float*> PeriodCheckAnnotations;
typedef Vector<DelayTable*> DelayTableSeq;
typedef ObjectId EdgeId;
@ -184,18 +183,11 @@ public:
int edgeCount() { return edges_->size(); }
virtual int arcCount() { return arc_count_; }
// Sdf width check annotation.
void widthCheckAnnotation(const Pin *pin,
const RiseFall *rf,
DcalcAPIndex ap_index,
// Return values.
float &width,
bool &exists);
void setWidthCheckAnnotation(const Pin *pin,
const RiseFall *rf,
DcalcAPIndex ap_index,
float width);
void minPulseWidthArc(Vertex *vertex,
const RiseFall *hi_low,
// Return values.
Edge *&edge,
TimingArc *&arc);
// Sdf period check annotation.
void periodCheckAnnotation(const Pin *pin,
DcalcAPIndex ap_index,
@ -229,7 +221,6 @@ protected:
virtual void makePortInstanceEdges(const Instance *inst,
LibertyCell *cell,
LibertyPort *from_to_port);
void removeWidthCheckAnnotations();
void removePeriodCheckAnnotations();
void makeSlewTables(DcalcAPIndex count);
void deleteSlewTables();
@ -264,8 +255,6 @@ protected:
DelayTableSeq slew_tables_; // [ap_index][tr_index][vertex_id]
VertexId slew_count_;
DelayTableSeq arc_delays_; // [ap_index][edge_arc_index]
// Sdf width check annotations.
WidthCheckAnnotations *width_check_annotations_;
// Sdf period check annotations.
PeriodCheckAnnotations *period_check_annotations_;
// Register/latch clock vertices to search from.

View File

@ -109,17 +109,6 @@ public:
// Precedence:
// SDF annotation
// Liberty library
// (ignores set_min_pulse_width constraint)
void minPulseWidth(const Pin *pin,
const RiseFall *hi_low,
DcalcAPIndex ap_index,
const MinMax *min_max,
// Return values.
float &min_width,
bool &exists);
// Precedence:
// SDF annotation
// Liberty library
void minPeriod(const Pin *pin,
// Return values.
float &min_period,

View File

@ -728,17 +728,12 @@ public:
void minPeriod(float &min_period,
bool &exists) const;
void setMinPeriod(float min_period);
// This corresponds to the min_pulse_width_high/low port attribute.
// high = rise, low = fall
void minPulseWidth(const RiseFall *hi_low,
const OperatingConditions *op_cond,
const Pvt *pvt,
float &min_width,
bool &exists) const;
// Unscaled value.
void minPulseWidth(const RiseFall *hi_low,
float &min_width,
bool &exists) const;
void setMinPulseWidth(RiseFall *hi_low,
void setMinPulseWidth(const RiseFall *hi_low,
float min_width);
bool isClock() const;
void setIsClock(bool is_clk);

View File

@ -1068,7 +1068,7 @@ protected:
virtual void recordPathDelayInternalEndpoints(ExceptionPath *exception);
virtual void unrecordPathDelayInternalEndpoints(ExceptionPath *exception);
bool pathDelayTo(const Pin *pin);
bool hasLibertyChecks(const Pin *pin);
bool hasLibertyCheckTo(const Pin *pin);
void deleteMatchingExceptions(ExceptionPath *exception);
void findMatchingExceptions(ExceptionPath *exception,
ExceptionPathSet &matches);

View File

@ -65,6 +65,8 @@ public:
int index() const { return index_; }
bool isWire() const;
bool isTimingCheck() const { return is_timing_check_; }
// TIming check but not width or period.
bool isTimingCheckBetween() const;
bool isAsyncTimingCheck() const;
bool isNonSeqTimingCheck() const { return is_non_seq_check_; }
bool isDataCheck() const;

View File

@ -2330,28 +2330,6 @@ LibertyPort::setMinPeriod(float min_period)
min_period_exists_ = true;
}
void
LibertyPort::minPulseWidth(const RiseFall *hi_low,
const OperatingConditions *op_cond,
const Pvt *pvt,
float &min_width,
bool &exists) const
{
if (scaled_ports_) {
LibertyPort *scaled_port = (*scaled_ports_)[op_cond];
if (scaled_port) {
scaled_port->minPulseWidth(hi_low, min_width, exists);
return;
}
}
int hi_low_index = hi_low->index();
LibertyLibrary *lib = liberty_cell_->libertyLibrary();
min_width = min_pulse_width_[hi_low_index]
* lib->scaleFactor(ScaleFactorType::min_pulse_width, hi_low_index,
liberty_cell_, pvt);
exists = min_pulse_width_exists_ & (1 << hi_low_index);
}
void
LibertyPort::minPulseWidth(const RiseFall *hi_low,
float &min_width,
@ -2363,7 +2341,7 @@ LibertyPort::minPulseWidth(const RiseFall *hi_low,
}
void
LibertyPort::setMinPulseWidth(RiseFall *hi_low,
LibertyPort::setMinPulseWidth(const RiseFall *hi_low,
float min_width)
{
int hi_low_index = hi_low->index();

View File

@ -276,6 +276,8 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell,
return makeClockTreePathArcs(cell, to_port, TimingRole::clockTreePathMax(),
MinMax::max(), attrs);
case TimingType::min_pulse_width:
return makeMinPulseWidthArcs(cell, from_port, to_port, related_out,
TimingRole::width(), attrs);
case TimingType::minimum_period:
case TimingType::nochange_high_high:
case TimingType::nochange_high_low:
@ -668,6 +670,26 @@ LibertyBuilder::makeClockTreePathArcs(LibertyCell *cell,
return arc_set;
}
TimingArcSet *
LibertyBuilder::makeMinPulseWidthArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
TimingRole *role,
TimingArcAttrsPtr attrs)
{
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, related_out,
role, attrs);
for (auto to_rf : RiseFall::range()) {
TimingModel *model = attrs->model(to_rf);
if (model)
makeTimingArc(arc_set, to_rf->opposite(), to_rf, model);
}
return arc_set;
}
////////////////////////////////////////////////////////////////
TimingArcSet *
LibertyBuilder::makeTimingArcSet(LibertyCell *cell,
LibertyPort *from,

View File

@ -84,6 +84,12 @@ public:
TimingRole *role,
const MinMax *min_max,
TimingArcAttrsPtr attrs);
TimingArcSet *makeMinPulseWidthArcs(LibertyCell *cell,
LibertyPort *from_port,
LibertyPort *to_port,
LibertyPort *related_out,
TimingRole *role,
TimingArcAttrsPtr attrs);
protected:
ConcretePort *makeBusPort(const char *name,

View File

@ -1922,8 +1922,10 @@ LibertyReader::finishPortGroups()
{
for (PortGroup *port_group : cell_port_groups_) {
int line = port_group->line();
for (LibertyPort *port : *port_group->ports())
for (LibertyPort *port : *port_group->ports()) {
checkPort(port, line);
makeMinPulseWidthArcs(port, line);
}
makeTimingArcs(port_group);
makeInternalPowers(port_group);
delete port_group;
@ -1947,6 +1949,47 @@ LibertyReader::checkPort(LibertyPort *port,
port->setDirection(PortDirection::tristate());
}
// Make timing arcs for the port min_pulse_width_low/high attributes.
// This is redundant but makes sdf annotation consistent.
void
LibertyReader::makeMinPulseWidthArcs(LibertyPort *port,
int line)
{
TimingArcAttrsPtr attrs = nullptr;
for (auto hi_low : RiseFall::range()) {
float min_width;
bool exists;
port->minPulseWidth(hi_low, min_width, exists);
if (exists) {
if (attrs == nullptr) {
attrs = make_shared<TimingArcAttrs>();
attrs->setTimingType(TimingType::min_pulse_width);
}
// rise/fall_constraint model is on the trailing edge of the pulse.
const RiseFall *model_rf = hi_low->opposite();
TimingModel *check_model =
makeScalarCheckModel(min_width, ScaleFactorType::min_pulse_width, model_rf);
attrs->setModel(model_rf, check_model);
}
}
if (attrs)
builder_.makeTimingArcs(cell_, port, port, nullptr, attrs, line);
}
TimingModel *
LibertyReader::makeScalarCheckModel(float value,
ScaleFactorType scale_factor_type,
const RiseFall *rf)
{
TablePtr table = make_shared<Table0>(value);
TableTemplate *tbl_template =
library_->findTableTemplate("scalar", TableTemplateType::delay);
TableModel *table_model = new TableModel(table, tbl_template,
scale_factor_type, rf);
CheckTableModel *check_model = new CheckTableModel(cell_, table_model, nullptr);
return check_model;
}
void
LibertyReader::makeTimingArcs(PortGroup *port_group)
{
@ -3530,7 +3573,7 @@ LibertyReader::visitMinPulseWidthHigh(LibertyAttr *attr)
void
LibertyReader::visitMinPulseWidth(LibertyAttr *attr,
RiseFall *rf)
const RiseFall *rf)
{
if (cell_) {
float value;

View File

@ -235,7 +235,7 @@ public:
virtual void visitMinPulseWidthLow(LibertyAttr *attr);
virtual void visitMinPulseWidthHigh(LibertyAttr *attr);
virtual void visitMinPulseWidth(LibertyAttr *attr,
RiseFall *rf);
const RiseFall *rf);
virtual void visitPulseClock(LibertyAttr *attr);
virtual void visitClockGateClockPin(LibertyAttr *attr);
virtual void visitClockGateEnablePin(LibertyAttr *attr);
@ -479,6 +479,11 @@ public:
virtual void visitAttr9(LibertyAttr *) {}
protected:
TimingModel *makeScalarCheckModel(float value,
ScaleFactorType scale_factor_type,
const RiseFall *rf);
void makeMinPulseWidthArcs(LibertyPort *port,
int line);
void setEnergyScale();
void defineVisitors();
virtual void begin(LibertyGroup *group);

View File

@ -55,17 +55,21 @@ protected:
void writePortAttrs(const LibertyPort *port);
void writeTimingArcSet(const TimingArcSet *arc_set);
void writeTimingModels(const TimingArc *arc,
RiseFall *rf);
const RiseFall *rf);
void writeTableModel(const TableModel *model);
void writeTableModel0(const TableModel *model);
void writeTableModel1(const TableModel *model);
void writeTableModel2(const TableModel *model);
void writeTableAxis(const TableAxis *axis,
int index);
void writeTableAxis4(const TableAxis *axis,
int index);
void writeTableAxis10(const TableAxis *axis,
int index);
const char *asString(bool value);
const char *asString(const PortDirection *dir);
const char *timingTypeString(const TimingArcSet *arc_set);
bool isAutoWidthArc(const LibertyPort *port,
const TimingArcSet *arc_set);
const LibertyLibrary *library_;
const char *filename_;
@ -214,20 +218,21 @@ LibertyWriter::writeTableTemplate(const TableTemplate *tbl_template)
fprintf(stream_, " variable_3 : %s;\n",
tableVariableString(axis3->variable()));
if (axis1)
writeTableAxis(axis1, 1);
writeTableAxis4(axis1, 1);
if (axis2)
writeTableAxis(axis2, 2);
writeTableAxis4(axis2, 2);
if (axis3)
writeTableAxis(axis3, 3);
writeTableAxis4(axis3, 3);
fprintf(stream_, " }\n");
}
}
// indent 4
void
LibertyWriter::writeTableAxis(const TableAxis *axis,
int index)
LibertyWriter::writeTableAxis4(const TableAxis *axis,
int index)
{
fprintf(stream_, " index_%d (\"", index);
fprintf(stream_, " index_%d(\"", index);
const Unit *unit = tableVariableUnit(axis->variable(), library_->units());
bool first = true;
for (size_t i = 0; i < axis->size(); i++) {
@ -239,6 +244,15 @@ LibertyWriter::writeTableAxis(const TableAxis *axis,
fprintf(stream_, "\");\n");
}
// indent 10
void
LibertyWriter::writeTableAxis10(const TableAxis *axis,
int index)
{
fprintf(stream_, " ");
writeTableAxis4(axis, index);
}
void
LibertyWriter::writeBusDcls()
{
@ -356,8 +370,25 @@ LibertyWriter::writePortAttrs(const LibertyPort *port)
fprintf(stream_, " max_capacitance : %s;\n",
cap_unit_->asString(limit, 3));
for (TimingArcSet *arc_set : port->libertyCell()->timingArcSets(nullptr,port))
writeTimingArcSet(arc_set);
for (TimingArcSet *arc_set : port->libertyCell()->timingArcSets(nullptr,port)) {
if (!isAutoWidthArc(port, arc_set))
writeTimingArcSet(arc_set);
}
}
// Check if arc is added for port min_pulse_width_high/low attribute.
bool
LibertyWriter::isAutoWidthArc(const LibertyPort *port,
const TimingArcSet *arc_set)
{
if (arc_set->role() == TimingRole::width()) {
float min_width;
bool exists1, exists2;
port->minPulseWidth(RiseFall::rise(), min_width, exists1);
port->minPulseWidth(RiseFall::fall(), min_width, exists2);
return exists1 || exists2;
}
return false;
}
void
@ -386,7 +417,7 @@ LibertyWriter::writeTimingArcSet(const TimingArcSet *arc_set)
void
LibertyWriter::writeTimingModels(const TimingArc *arc,
RiseFall *rf)
const RiseFall *rf)
{
TimingModel *model = arc->model();
const GateTableModel *gate_model = dynamic_cast<GateTableModel*>(model);
@ -450,6 +481,7 @@ LibertyWriter::writeTableModel0(const TableModel *model)
void
LibertyWriter::writeTableModel1(const TableModel *model)
{
writeTableAxis10(model->axis1(), 1);
fprintf(stream_, " values(\"");
bool first_col = true;
for (size_t index1 = 0; index1 < model->axis1()->size(); index1++) {
@ -465,6 +497,8 @@ LibertyWriter::writeTableModel1(const TableModel *model)
void
LibertyWriter::writeTableModel2(const TableModel *model)
{
writeTableAxis10(model->axis1(), 1);
writeTableAxis10(model->axis2(), 2);
fprintf(stream_, " values(\"");
bool first_row = true;
for (size_t index1 = 0; index1 < model->axis1()->size(); index1++) {
@ -577,6 +611,8 @@ LibertyWriter::timingTypeString(const TimingArcSet *arc_set)
return "min_clock_tree_path";
else if (role == TimingRole::clockTreePathMax())
return "max_clock_tree_path";
else if (role == TimingRole::width())
return "min_pulse_width";
else {
report_->error(1333, "%s/%s/%s timing arc type %s not supported.",
library_->name(),

View File

@ -258,6 +258,14 @@ TimingRole::isLatchDtoQ() const
return this == latch_d_q_;
}
bool
TimingRole::isTimingCheckBetween() const
{
return is_timing_check_
&& this != width_
&& this != period_;
}
bool
TimingRole::less(const TimingRole *role1,
const TimingRole *role2)

View File

@ -3924,7 +3924,7 @@ Sdc::recordPathDelayInternalEndpoints(ExceptionPath *exception)
if (to
&& to->hasPins()) {
for (const Pin *pin : *to->pins()) {
if (!(hasLibertyChecks(pin)
if (!(hasLibertyCheckTo(pin)
|| network_->isTopLevelPort(pin))) {
path_delay_internal_endpoints_.insert(pin);
}
@ -3940,7 +3940,7 @@ Sdc::unrecordPathDelayInternalEndpoints(ExceptionPath *exception)
&& to->hasPins()
&& !path_delay_internal_endpoints_.empty()) {
for (const Pin *pin : *to->pins()) {
if (!(hasLibertyChecks(pin)
if (!(hasLibertyCheckTo(pin)
|| network_->isTopLevelPort(pin))
&& !pathDelayTo(pin))
path_delay_internal_endpoints_.erase(pin);
@ -3949,7 +3949,7 @@ Sdc::unrecordPathDelayInternalEndpoints(ExceptionPath *exception)
}
bool
Sdc::hasLibertyChecks(const Pin *pin)
Sdc::hasLibertyCheckTo(const Pin *pin)
{
const Instance *inst = network_->instance(pin);
LibertyCell *cell = network_->libertyCell(inst);
@ -3957,7 +3957,7 @@ Sdc::hasLibertyChecks(const Pin *pin)
LibertyPort *port = network_->libertyPort(pin);
if (port) {
for (TimingArcSet *arc_set : cell->timingArcSets(nullptr, port)) {
if (arc_set->role()->isTimingCheck())
if (arc_set->role()->isTimingCheckBetween())
return true;
}
}

View File

@ -68,7 +68,7 @@ protected:
void init();
void findCounts();
void findWidthPeriodCount(Pin *pin);
void findPeriodCount(Pin *pin);
void reportDelayCounts();
void reportCheckCounts();
void reportArcs();
@ -78,9 +78,9 @@ protected:
void reportArcs(Vertex *vertex,
bool report_annotated,
int &i);
void reportWidthPeriodArcs(const Pin *pin,
bool report_annotated,
int &i);
void reportPeriodArcs(const Pin *pin,
bool report_annotated,
int &i);
void reportCount(const char *title,
int index,
int &total,
@ -282,9 +282,8 @@ ReportAnnotated::reportCheckCount(TimingRole *role,
{
int index = role->index();
if (edge_count_[index] > 0) {
const char *role_name = role->asString();
string title;
stringPrint(title, "cell %s arcs", role_name);
stringPrint(title, "cell %s arcs", role->asString());
reportCount(title.c_str(), index, total, annotated_total);
}
}
@ -345,7 +344,7 @@ ReportAnnotated::findCounts()
}
}
}
findWidthPeriodCount(from_pin);
findPeriodCount(from_pin);
}
}
@ -376,7 +375,7 @@ ReportAnnotated::roleIndex(const TimingRole *role,
// Width and period checks are not edges in the graph so
// they require special handling.
void
ReportAnnotated::findWidthPeriodCount(Pin *pin)
ReportAnnotated::findPeriodCount(Pin *pin)
{
LibertyPort *port = network_->libertyPort(pin);
if (port) {
@ -400,27 +399,6 @@ ReportAnnotated::findWidthPeriodCount(Pin *pin)
}
}
}
int width_index = TimingRole::width()->index();
if (report_role_[width_index]) {
for (auto hi_low : RiseFall::range()) {
port->minPulseWidth(hi_low, value, exists);
if (exists) {
edge_count_[width_index]++;
graph_->widthCheckAnnotation(pin, hi_low, ap_index,
value, annotated);
if (annotated) {
edge_annotated_count_[width_index]++;
if (list_annotated_)
annotated_pins_.insert(pin);
}
else {
if (list_unannotated_)
unannotated_pins_.insert(pin);
}
}
}
}
}
}
@ -476,7 +454,7 @@ ReportAnnotated::reportArcs(const char *header,
reportArcs(vertex, report_annotated, i);
if (bidirect_drvr_vertex)
reportArcs(bidirect_drvr_vertex, report_annotated, i);
reportWidthPeriodArcs(pin, report_annotated, i);
reportPeriodArcs(pin, report_annotated, i);
if (max_lines_ != 0 && i > max_lines_)
break;
}
@ -521,15 +499,13 @@ ReportAnnotated::reportArcs(Vertex *vertex,
}
void
ReportAnnotated::reportWidthPeriodArcs(const Pin *pin,
bool report_annotated,
int &i)
ReportAnnotated::reportPeriodArcs(const Pin *pin,
bool report_annotated,
int &i)
{
LibertyPort *port = network_->libertyPort(pin);
if (port) {
DcalcAPIndex ap_index = 0;
float value;
bool exists, annotated;
int period_index = TimingRole::period()->index();
if (report_role_[period_index]
&& (max_lines_ == 0 || i < max_lines_)) {
@ -547,27 +523,6 @@ ReportAnnotated::reportWidthPeriodArcs(const Pin *pin,
}
}
}
int width_index = TimingRole::width()->index();
if (report_role_[width_index]
&& (max_lines_ == 0 || i < max_lines_)) {
bool report = false;
for (auto hi_low : RiseFall::range()) {
port->minPulseWidth(hi_low, value, exists);
if (exists) {
edge_count_[width_index]++;
graph_->widthCheckAnnotation(pin, hi_low, ap_index,
value, annotated);
report |= (annotated == report_annotated);
}
}
if (report) {
report_->reportLine(" %-18s %s",
"min width",
network_->pathName(pin));
i++;
}
}
}
}

View File

@ -550,22 +550,12 @@ SdfReader::timingCheckWidth(SdfPortSpec *edge,
if (port) {
Pin *pin = network_->findPin(instance_, port_name);
if (pin) {
const RiseFall *rf = edge->transition()->asRiseFall();
float **values = triple->values();
float *value_ptr = values[triple_min_index_];
if (value_ptr) {
float value = *value_ptr;
graph_->setWidthCheckAnnotation(pin, rf, arc_delay_min_index_,
value);
}
if (triple_max_index_ != null_index_) {
value_ptr = values[triple_max_index_];
if (value_ptr) {
float value = *value_ptr;
graph_->setWidthCheckAnnotation(pin, rf, arc_delay_max_index_,
value);
}
}
const RiseFall *rf = edge->transition()->asRiseFall();
Edge *edge;
TimingArc *arc;
graph_->minPulseWidthArc(graph_->pinLoadVertex(pin), rf, edge, arc);
if (edge)
setEdgeArcDelays(edge, arc, triple);
}
}
}

View File

@ -522,14 +522,12 @@ SdfWriter::writeTimingChecks(const Instance *inst,
}
for (auto hi_low : RiseFall::range()) {
float min_width, max_width;
bool exists;
graph_delay_calc_->minPulseWidth(pin, hi_low, arc_delay_min_index_,
MinMax::min(),
min_width, exists);
graph_delay_calc_->minPulseWidth(pin, hi_low, arc_delay_max_index_,
MinMax::max(),
max_width, exists);
if (exists) {
Edge *edge;
TimingArc *arc;
graph_->minPulseWidthArc(vertex, hi_low, edge, arc);
if (edge) {
min_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_min_index_));
max_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_max_index_));
ensureTimingCheckheaders(check_header, inst, inst_header);
writeWidthCheck(pin, hi_low, min_width, max_width);
}

View File

@ -87,10 +87,10 @@ BfsIterator::reportEntries(const Network *network)
while (levelLessOrEqual(level, last_level_)) {
VertexSeq &level_vertices = queue_[level];
if (!level_vertices.empty()) {
printf("Level %d\n", level);
report_->reportLine("Level %d", level);
for (auto vertex : level_vertices) {
if (vertex)
printf(" %s\n", vertex->name(network));
report_->reportLine(" %s", vertex->name(network));
}
}
incrLevel(level);

View File

@ -424,9 +424,11 @@ MinPulseWidthCheck::minWidth(const StaState *sta) const
}
// Precedence:
// set_min_pulse_width constraint
// set_min_pulse_width SDC command
// SDF annotation
// Liberty library
// port min_pulse_width_low/high
// min_pulse_width timing group
static void
minPulseWidth(const Path *path,
const StaState *sta,
@ -441,12 +443,17 @@ minPulseWidth(const Path *path,
// set_min_pulse_width command.
sdc->minPulseWidth(pin, clk, rf, min_width, exists);
if (!exists) {
GraphDelayCalc *graph_dcalc = sta->graphDelayCalc();
const MinMax *min_max = path->minMax(sta);
const PathAnalysisPt *path_ap = path->pathAnalysisPt(sta);
const DcalcAnalysisPt *dcalc_ap = path_ap->dcalcAnalysisPt();
graph_dcalc->minPulseWidth(pin, rf, dcalc_ap->index(), min_max,
min_width, exists);
Vertex *vertex = path->vertex(sta);
Graph *graph = sta->graph();
Edge *edge;
TimingArc *arc;
graph->minPulseWidthArc(vertex, rf, edge, arc);
if (edge) {
min_width = delayAsFloat(graph->arcDelay(edge, arc, dcalc_ap->index()));
exists = true;
}
}
}

View File

@ -530,11 +530,13 @@ FindRegClkPins::FindRegClkPins(StaState *sta) :
bool
FindRegClkPins::matchPin(Pin *pin)
{
// Liberty port clock attribute is not present in latches (for nlc18 anyway).
LibertyPort *port = network_->libertyPort(pin);
LibertyCell *cell = port->libertyCell();
for (TimingArcSet *arc_set : cell->timingArcSets(port, nullptr)) {
TimingRole *role = arc_set->role();
if (role->isTimingCheck())
if (role == TimingRole::regClkToQ()
|| role == TimingRole::latchEnToQ())
return true;
}
return false;

View File

@ -142,7 +142,6 @@ Sim::funcBddSim(const FuncExpr *expr,
if (port_node) {
LogicValue value = logicValue(pin);
int var_index = Cudd_NodeReadIndex(port_node);
//printf("%s %d %c\n", port->name(), var_index, logicValueString(value));
switch (value) {
case LogicValue::zero:
bdd = Cudd_bddCompose(cudd_mgr, bdd, Cudd_ReadLogicZero(cudd_mgr), var_index);