set_clock_sense -> set_sense, LibertyPort::driveResistance
This commit is contained in:
parent
b9a7b349eb
commit
12494398e9
BIN
doc/OpenSTA.odt
BIN
doc/OpenSTA.odt
Binary file not shown.
|
|
@ -43,13 +43,25 @@ hashPort(const LibertyPort *port);
|
|||
static unsigned
|
||||
hashString(const char *str);
|
||||
|
||||
class CellDriveResistanceLess
|
||||
static float
|
||||
cellDriveResistance(const LibertyCell *cell)
|
||||
{
|
||||
LibertyCellPortBitIterator port_iter(cell);
|
||||
while (port_iter.hasNext()) {
|
||||
auto port = port_iter.next();
|
||||
if (port->direction()->isOutput())
|
||||
return port->driveResistance();
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
class CellDriveResistanceGreater
|
||||
{
|
||||
public:
|
||||
bool operator()(const LibertyCell *cell1,
|
||||
const LibertyCell *cell2) const
|
||||
{
|
||||
return cell1->driveResistance() > cell2->driveResistance();
|
||||
return cellDriveResistance(cell1) > cellDriveResistance(cell2);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -62,7 +74,7 @@ EquivCells::EquivCells(LibertyLibrarySeq *equiv_libs,
|
|||
// Sort the equiv sets by drive resistance.
|
||||
for (auto cell : unique_equiv_cells_) {
|
||||
auto equivs = equiv_cells_.findKey(cell);
|
||||
sort(equivs, CellDriveResistanceLess());
|
||||
sort(equivs, CellDriveResistanceGreater());
|
||||
}
|
||||
if (map_libs) {
|
||||
for (auto lib : *map_libs)
|
||||
|
|
|
|||
|
|
@ -1440,42 +1440,6 @@ LibertyCell::setCornerCell(LibertyCell *corner_cell,
|
|||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// Use the min/max "drive" for all the timing arcs in the cell.
|
||||
float
|
||||
LibertyCell::driveResistance(const TransRiseFall *tr,
|
||||
const MinMax *min_max) const
|
||||
{
|
||||
float max_drive = min_max->initValue();
|
||||
LibertyCellTimingArcSetIterator set_iter(this);
|
||||
while (set_iter.hasNext()) {
|
||||
TimingArcSet *set = set_iter.next();
|
||||
if (!set->role()->isTimingCheck()) {
|
||||
TimingArcSetArcIterator arc_iter(set);
|
||||
while (arc_iter.hasNext()) {
|
||||
TimingArc *arc = arc_iter.next();
|
||||
if (tr == nullptr
|
||||
|| arc->toTrans()->asRiseFall() == tr) {
|
||||
GateTimingModel *model = dynamic_cast<GateTimingModel*>(arc->model());
|
||||
if (model) {
|
||||
float drive = model->driveResistance(this, nullptr);
|
||||
if (min_max->compare(drive, max_drive))
|
||||
max_drive = drive;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return max_drive;
|
||||
}
|
||||
|
||||
float
|
||||
LibertyCell::driveResistance() const
|
||||
{
|
||||
return driveResistance(nullptr, MinMax::max());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
float
|
||||
LibertyCell::ocvArcDepth() const
|
||||
{
|
||||
|
|
@ -1953,6 +1917,47 @@ LibertyPort::capacitanceIsOneValue() const
|
|||
return capacitance_.isOneValue();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// Use the min/max "drive" for all the timing arcs in the cell.
|
||||
float
|
||||
LibertyPort::driveResistance(const TransRiseFall *tr,
|
||||
const MinMax *min_max) const
|
||||
{
|
||||
float max_drive = min_max->initValue();
|
||||
bool found_drive = false;
|
||||
LibertyCellTimingArcSetIterator set_iter(liberty_cell_, nullptr, this);
|
||||
while (set_iter.hasNext()) {
|
||||
TimingArcSet *set = set_iter.next();
|
||||
if (!set->role()->isTimingCheck()) {
|
||||
TimingArcSetArcIterator arc_iter(set);
|
||||
while (arc_iter.hasNext()) {
|
||||
TimingArc *arc = arc_iter.next();
|
||||
if (tr == nullptr
|
||||
|| arc->toTrans()->asRiseFall() == tr) {
|
||||
GateTimingModel *model = dynamic_cast<GateTimingModel*>(arc->model());
|
||||
if (model) {
|
||||
float drive = model->driveResistance(liberty_cell_, nullptr);
|
||||
if (min_max->compare(drive, max_drive))
|
||||
max_drive = drive;
|
||||
found_drive = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found_drive)
|
||||
return max_drive;
|
||||
else
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
float
|
||||
LibertyPort::driveResistance() const
|
||||
{
|
||||
return driveResistance(nullptr, MinMax::max());
|
||||
}
|
||||
|
||||
void
|
||||
LibertyPort::setFunction(FuncExpr *func)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -411,7 +411,7 @@ public:
|
|||
bool isClockGateOther() const;
|
||||
bool isClockGate() const;
|
||||
void setClockGateType(ClockGateType type);
|
||||
// Internal to LibertyCellTimingArcSetIterator.
|
||||
// from or to may be nullptr to wildcard.
|
||||
TimingArcSetSeq *timingArcSets(const LibertyPort *from,
|
||||
const LibertyPort *to) const;
|
||||
size_t timingArcSetCount() const;
|
||||
|
|
@ -490,10 +490,6 @@ public:
|
|||
virtual void finish(bool infer_latches,
|
||||
Report *report,
|
||||
Debug *debug);
|
||||
float driveResistance(const TransRiseFall *tr,
|
||||
const MinMax *min_max) const;
|
||||
// Max of rise/fall.
|
||||
float driveResistance() const;
|
||||
bool isBuffer() const;
|
||||
// Only valid when isBuffer() returns true.
|
||||
void bufferPorts(// Return values.
|
||||
|
|
@ -607,6 +603,7 @@ class LibertyCellTimingArcSetIterator : public TimingArcSetSeq::ConstIterator
|
|||
{
|
||||
public:
|
||||
LibertyCellTimingArcSetIterator(const LibertyCell *cell);
|
||||
// from or to may be nullptr to wildcard.
|
||||
LibertyCellTimingArcSetIterator(const LibertyCell *cell,
|
||||
const LibertyPort *from,
|
||||
const LibertyPort *to);
|
||||
|
|
@ -659,6 +656,10 @@ public:
|
|||
void setCapacitance(const TransRiseFall *tr,
|
||||
const MinMax *min_max,
|
||||
float cap);
|
||||
float driveResistance(const TransRiseFall *tr,
|
||||
const MinMax *min_max) const;
|
||||
// Max of rise/fall.
|
||||
float driveResistance() const;
|
||||
FuncExpr *function() const { return function_; }
|
||||
void setFunction(FuncExpr *func);
|
||||
FuncExpr *&functionRef() { return function_; }
|
||||
|
|
|
|||
|
|
@ -918,7 +918,7 @@ WriteSdc::writeClockSense(PinClockPair &pin_clk,
|
|||
flag = "-negative";
|
||||
else if (sense == ClockSense::stop)
|
||||
flag = "-stop_propagation";
|
||||
fprintf(stream_, "set_clock_sense %s ", flag);
|
||||
fprintf(stream_, "set_sense -type clock %s ", flag);
|
||||
const Clock *clk = pin_clk.second;
|
||||
if (clk) {
|
||||
fprintf(stream_, "-clock ");
|
||||
|
|
|
|||
|
|
@ -527,18 +527,6 @@ getProperty(const LibertyCell *cell,
|
|||
return PropertyValue(cell->filename());
|
||||
else if (stringEqual(property, "library"))
|
||||
return PropertyValue(cell->libertyLibrary());
|
||||
else if (stringEqual(property, "drive_resistance_rise_min"))
|
||||
return PropertyValue(cell->driveResistance(TransRiseFall::rise(),
|
||||
MinMax::min()));
|
||||
else if (stringEqual(property, "drive_resistance_rise_max"))
|
||||
return PropertyValue(cell->driveResistance(TransRiseFall::rise(),
|
||||
MinMax::max()));
|
||||
else if (stringEqual(property, "drive_resistance_fall_min"))
|
||||
return PropertyValue(cell->driveResistance(TransRiseFall::fall(),
|
||||
MinMax::min()));
|
||||
else if (stringEqual(property, "drive_resistance_fall_max"))
|
||||
return PropertyValue(cell->driveResistance(TransRiseFall::fall(),
|
||||
MinMax::max()));
|
||||
else if (stringEqual(property, "is_buffer"))
|
||||
return PropertyValue(cell->isBuffer());
|
||||
else if (stringEqual(property, "dont_use"))
|
||||
|
|
@ -656,6 +644,18 @@ getProperty(const LibertyPort *port,
|
|||
float cap = port->capacitance(TransRiseFall::rise(), MinMax::max());
|
||||
return PropertyValue(sta->units()->capacitanceUnit()->asString(cap, 6));
|
||||
}
|
||||
else if (stringEqual(property, "drive_resistance_rise_min"))
|
||||
return PropertyValue(port->driveResistance(TransRiseFall::rise(),
|
||||
MinMax::min()));
|
||||
else if (stringEqual(property, "drive_resistance_rise_max"))
|
||||
return PropertyValue(port->driveResistance(TransRiseFall::rise(),
|
||||
MinMax::max()));
|
||||
else if (stringEqual(property, "drive_resistance_fall_min"))
|
||||
return PropertyValue(port->driveResistance(TransRiseFall::fall(),
|
||||
MinMax::min()));
|
||||
else if (stringEqual(property, "drive_resistance_fall_max"))
|
||||
return PropertyValue(port->driveResistance(TransRiseFall::fall(),
|
||||
MinMax::max()));
|
||||
else
|
||||
throw PropertyUnknown("liberty port", property);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -192,16 +192,6 @@ SearchThru::searchThru(Edge *edge)
|
|||
&& loopEnabled(edge, sdc, graph, search);
|
||||
}
|
||||
|
||||
class ClkArrivalSearchPred : public EvalPred
|
||||
{
|
||||
public:
|
||||
ClkArrivalSearchPred(const StaState *sta);
|
||||
virtual bool searchThru(Edge *edge);
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(ClkArrivalSearchPred);
|
||||
};
|
||||
|
||||
ClkArrivalSearchPred::ClkArrivalSearchPred(const StaState *sta) :
|
||||
EvalPred(sta)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -346,6 +346,7 @@ public:
|
|||
VisitPathEnds *visitPathEnds() { return visit_path_ends_; }
|
||||
GatedClk *gatedClk() { return gated_clk_; }
|
||||
Genclks *genclks() { return genclks_; }
|
||||
void findClkVertexPins(PinSet &clk_pins);
|
||||
|
||||
protected:
|
||||
void init(StaState *sta);
|
||||
|
|
@ -376,7 +377,6 @@ protected:
|
|||
const PathAnalysisPt *path_ap,
|
||||
Arrival insertion,
|
||||
TagGroupBldr *tag_bldr);
|
||||
void findClkVertexPins(PinSet &clk_pins);
|
||||
Tag *clkDataTag(const Pin *pin,
|
||||
Clock *clk,
|
||||
const TransRiseFall *tr,
|
||||
|
|
@ -624,6 +624,16 @@ protected:
|
|||
bool search_thru_latches_;
|
||||
};
|
||||
|
||||
class ClkArrivalSearchPred : public EvalPred
|
||||
{
|
||||
public:
|
||||
ClkArrivalSearchPred(const StaState *sta);
|
||||
virtual bool searchThru(Edge *edge);
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(ClkArrivalSearchPred);
|
||||
};
|
||||
|
||||
// Class for visiting fanin/fanout paths of a vertex.
|
||||
// This used by forward/backward search to find arrival/required path times.
|
||||
class PathVisitor : public VertexVisitor
|
||||
|
|
|
|||
34
tcl/Sdc.tcl
34
tcl/Sdc.tcl
|
|
@ -1434,15 +1434,41 @@ proc set_clock_latency { args } {
|
|||
|
||||
################################################################
|
||||
|
||||
define_cmd_args "set_sense" \
|
||||
{[-type clock|data] [-positive] [-negative] [-pulse pulse_type]\
|
||||
[-stop_propagation] [-clocks clocks] pins}
|
||||
|
||||
proc set_sense { args } {
|
||||
parse_key_args "set_clock_sense" args keys {-type} flags {} 0
|
||||
|
||||
set type "clock"
|
||||
if { [info exists keys(-type)] } {
|
||||
set type $keys(-type)
|
||||
if { $type == "data" } {
|
||||
sdc_warn "set_sense -type data not supported."
|
||||
} elseif { $type == "clock" } {
|
||||
set_clock_sense_cmd1 "set_sense" $args
|
||||
} else {
|
||||
sdc_error "set_sense -type clock|data"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# deprecated in SDC 2.1
|
||||
define_cmd_args "set_clock_sense" \
|
||||
{[-positive] [-negative] [-pulse pulse_type] [-stop_propagation] \
|
||||
[-clock clocks] pins}
|
||||
|
||||
proc set_clock_sense { args } {
|
||||
sdc_warn "set_clock_sense is deprecated as of SDC 2.1. Use set_sense -type clock."
|
||||
set_clock_sense_cmd1 "set_clock_sense" $args
|
||||
}
|
||||
|
||||
proc set_clock_sense_cmd1 { cmd cmd_args } {
|
||||
# SDC uses -clock, OT, OC use -clocks
|
||||
parse_key_args "set_clock_sense" args keys {-clock -clocks -pulse} \
|
||||
flags {-positive -negative -stop_propagation}
|
||||
check_argc_eq1 "set_clock_sense" $args
|
||||
parse_key_args $cmd cmd_args keys {-clock -clocks -pulse} \
|
||||
flags {-positive -negative -stop_propagation} 0
|
||||
check_argc_eq1 "set_clock_sense" $cmd_args
|
||||
|
||||
set pulse [info exists keys(-pulse)]
|
||||
if { $pulse } {
|
||||
|
|
@ -1458,7 +1484,7 @@ proc set_clock_sense { args } {
|
|||
sta_warn "-positive, -negative, -stop_propagation and -pulse are mutually exclusive."
|
||||
}
|
||||
|
||||
set pins [get_port_pins_error "pins" [lindex $args 0]]
|
||||
set pins [get_port_pins_error "pins" [lindex $cmd_args 0]]
|
||||
set clks {}
|
||||
if {[info exists keys(-clock)]} {
|
||||
set clks [get_clocks_warn "clock" $keys(-clock)]
|
||||
|
|
|
|||
Loading…
Reference in New Issue