liberty min_pulse_width timing group support
Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
parent
4146e623d1
commit
60d8030a94
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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(),
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue