LibertyCell::higherDrive(), slowerDrive()

This commit is contained in:
James Cherry 2019-05-25 17:08:53 -07:00
parent cfaef559e6
commit 6a194ef6ee
11 changed files with 124 additions and 92 deletions

View File

@ -626,7 +626,7 @@ add_flex_bison_dependency(SdfLex SdfParser)
include(FindSWIG) include(FindSWIG)
add_custom_command(OUTPUT ${STA_HOME}/app/StaApp_wrap.cc add_custom_command(OUTPUT ${STA_HOME}/app/StaApp_wrap.cc
COMMAND ${SWIG_EXECUTABLE} -tcl8 -c++ -namespace -prefix sta -o ${STA_HOME}/app/StaApp_wrap.cc ${STA_HOME}/app/StaApp.i COMMAND ${SWIG_EXECUTABLE} -tcl8 -c++ -namespace -prefix sta -I${STA_HOME}/tcl -I${STA_HOME}/sdf -I${STA_HOME}/dcalc -I${STA_HOME}/parasitics -I${STA_HOME}/verilog -o ${STA_HOME}/app/StaApp_wrap.cc ${STA_HOME}/app/StaApp.i
COMMAND ${STA_HOME}/etc/SwigCleanup.tcl ${STA_HOME}/app/StaApp_wrap.cc COMMAND ${STA_HOME}/etc/SwigCleanup.tcl ${STA_HOME}/app/StaApp_wrap.cc
WORKING_DIRECTORY ${STA_HOME} WORKING_DIRECTORY ${STA_HOME}
DEPENDS ${STA_SWIG_FILES} DEPENDS ${STA_SWIG_FILES}

View File

@ -16,10 +16,10 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
%include "../tcl/StaException.i" %include "StaException.i"
%include "../tcl/StaTcl.i" %include "StaTcl.i"
%include "../verilog/Verilog.i" %include "Verilog.i"
%include "../tcl/NetworkEdit.i" %include "NetworkEdit.i"
%include "../sdf/Sdf.i" %include "Sdf.i"
%include "../dcalc/DelayCalc.i" %include "DelayCalc.i"
%include "../parasitics/Parasitics.i" %include "Parasitics.i"

View File

@ -15,6 +15,7 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
#include "Machine.hh" #include "Machine.hh"
#include "UnorderedMap.hh"
#include "PortDirection.hh" #include "PortDirection.hh"
#include "Transition.hh" #include "Transition.hh"
#include "MinMax.hh" #include "MinMax.hh"
@ -28,14 +29,16 @@
namespace sta { namespace sta {
typedef Map<unsigned,LibertyCellSeq*, std::less<unsigned> > LibertyCellHashMap; typedef UnorderedMap<unsigned, LibertyCellSeq*> LibertyCellHashMap;
typedef Set<LibertyCellSeq*> LibertyCellSeqSet; typedef Set<LibertyCellSeq*> LibertyCellSeqSet;
static LibertyCellEquivMap * static LibertyCellEquivMap *
findEquivCells1(const LibertyLibrary *library); findEquivCells1(const LibertyLibrary *library);
static void static void
deleteEquivCellMap(LibertyCellEquivMap *equiv_map);
static void
sortCellEquivs(LibertyCellEquivMap *cell_equivs); sortCellEquivs(LibertyCellEquivMap *cell_equivs);
float static float
cellDriveResistance(const LibertyCell *cell); cellDriveResistance(const LibertyCell *cell);
static unsigned static unsigned
@ -55,15 +58,19 @@ static bool
equivCellSequentials(const LibertyCell *cell1, equivCellSequentials(const LibertyCell *cell1,
const LibertyCell *cell2); const LibertyCell *cell2);
LibertyCellEquivMap * void
makeEquivCellMap(const LibertyLibrary *library) findEquivCells(const LibertyLibrary *library)
{ {
// Build a map from each cell in the library to a group (CellSeq) of
// cells with equivalent functionality.
LibertyCellEquivMap *cell_equivs = findEquivCells1(library); LibertyCellEquivMap *cell_equivs = findEquivCells1(library);
// Sort by drive strength.
sortCellEquivs(cell_equivs); sortCellEquivs(cell_equivs);
return cell_equivs; deleteEquivCellMap(cell_equivs);
} }
void // Delete the LibertyCellEquivMap returned by makeEquivCellMap.
static void
deleteEquivCellMap(LibertyCellEquivMap *equiv_map) deleteEquivCellMap(LibertyCellEquivMap *equiv_map)
{ {
// Multiple cells can point to the same cell sequence, so collect // Multiple cells can point to the same cell sequence, so collect
@ -147,14 +154,21 @@ sortCellEquivs(LibertyCellEquivMap *cell_equivs)
while (equivs_iter.hasNext()) { while (equivs_iter.hasNext()) {
LibertyCellSeq *equivs = equivs_iter.next(); LibertyCellSeq *equivs = equivs_iter.next();
sort(equivs, CellDriveResistanceLess()); sort(equivs, CellDriveResistanceLess());
LibertyCell *lower = nullptr;
LibertyCellSeq::Iterator cell_iter(equivs);
while (cell_iter.hasNext()) {
LibertyCell *cell = cell_iter.next();
if (lower) {
lower->setHigherDrive(cell);
cell->setLowerDrive(lower);
}
lower = cell;
}
} }
} }
// Use the worst "drive" for all the timing arcs in the cell. // Use the worst "drive" for all the timing arcs in the cell.
// Note that this function can NOT be static for sun's compiler to static float
// be happy with using it in a sort predicate (presumably because the
// template functions are compiled outside the scope of this file).
float
cellDriveResistance(const LibertyCell *cell) cellDriveResistance(const LibertyCell *cell)
{ {
float max_drive = 0.0; float max_drive = 0.0;

View File

@ -22,14 +22,10 @@
namespace sta { namespace sta {
// Build a map from each cell in the library to a group (CellSeq) of // Find equivalent cells, sort by drive strength and
// cells with equivalent functionality, sorted by drive strength. // and set cell->higherDrive/lowerDrive.
LibertyCellEquivMap *
makeEquivCellMap(const LibertyLibrary *library);
// Delete the LibertyCellEquivMap returned by makeEquivCellMap.
void void
deleteEquivCellMap(LibertyCellEquivMap *equiv_map); findEquivCells(const LibertyLibrary *library);
// Predicate that is true when the ports, functions, sequentials and // Predicate that is true when the ports, functions, sequentials and
// timing arcs match. // timing arcs match.

View File

@ -82,7 +82,6 @@ LibertyLibrary::LibertyLibrary(const char *name,
default_wire_load_mode_(WireloadMode::unknown), default_wire_load_mode_(WireloadMode::unknown),
default_wire_load_selection_(nullptr), default_wire_load_selection_(nullptr),
default_operating_conditions_(nullptr), default_operating_conditions_(nullptr),
equiv_cell_map_(nullptr),
ocv_arc_depth_(0.0), ocv_arc_depth_(0.0),
default_ocv_derate_(nullptr) default_ocv_derate_(nullptr)
{ {
@ -123,8 +122,6 @@ LibertyLibrary::~LibertyLibrary()
operating_conditions_.deleteContents(); operating_conditions_.deleteContents();
wireloads_.deleteContents(); wireloads_.deleteContents();
wire_load_selections_.deleteContents(); wire_load_selections_.deleteContents();
if (equiv_cell_map_)
deleteEquivCellMap(equiv_cell_map_);
delete units_; delete units_;
ocv_derate_map_.deleteContents(); ocv_derate_map_.deleteContents();
@ -500,15 +497,6 @@ LibertyLibrary::setDefaultOutputPinRes(const TransRiseFall *tr,
default_output_pin_res_.setValue(tr, value); default_output_pin_res_.setValue(tr, value);
} }
LibertyCellSeq *
LibertyLibrary::findEquivCells(LibertyCell *cell)
{
if (equiv_cell_map_ == nullptr)
equiv_cell_map_ = makeEquivCellMap(this);
LibertyCellSeq *equivs = equiv_cell_map_->findKey(cell);
return equivs;
}
void void
LibertyLibrary::addWireload(Wireload *wireload) LibertyLibrary::addWireload(Wireload *wireload)
{ {
@ -748,6 +736,12 @@ LibertyLibrary::makeCornerMap(LibertyCell *cell1,
} }
} }
void
LibertyLibrary::finish()
{
findEquivCells(this);
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
float float
@ -849,7 +843,9 @@ LibertyCell::LibertyCell(LibertyLibrary *library,
ocv_derate_(nullptr), ocv_derate_(nullptr),
is_disabled_constraint_(false), is_disabled_constraint_(false),
leakage_power_(0.0), leakage_power_(0.0),
leakage_power_exists_(false) leakage_power_exists_(false),
higher_drive_(nullptr),
lower_drive_(nullptr)
{ {
} }
@ -1388,6 +1384,20 @@ LibertyCell::setCornerCell(LibertyCell *corner_cell,
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
void
LibertyCell::setHigherDrive(LibertyCell *cell)
{
higher_drive_ = cell;
}
void
LibertyCell::setLowerDrive(LibertyCell *cell)
{
lower_drive_ = cell;
}
////////////////////////////////////////////////////////////////
float float
LibertyCell::ocvArcDepth() const LibertyCell::ocvArcDepth() const
{ {

View File

@ -223,7 +223,6 @@ public:
float slewDerateFromLibrary() const; float slewDerateFromLibrary() const;
void setSlewDerateFromLibrary(float derate); void setSlewDerateFromLibrary(float derate);
LibertyCellSeq *findEquivCells(LibertyCell *cell);
Units *units() { return units_; } Units *units() { return units_; }
const Units *units() const { return units_; } const Units *units() const { return units_; }
@ -279,6 +278,7 @@ public:
bool link, bool link,
int ap_index, int ap_index,
Report *report); Report *report);
void finish();
protected: protected:
float degradeWireSlew(const LibertyCell *cell, float degradeWireSlew(const LibertyCell *cell,
@ -322,7 +322,6 @@ protected:
WireloadSelectionMap wire_load_selections_; WireloadSelectionMap wire_load_selections_;
OperatingConditionsMap operating_conditions_; OperatingConditionsMap operating_conditions_;
OperatingConditions *default_operating_conditions_; OperatingConditions *default_operating_conditions_;
LibertyCellEquivMap *equiv_cell_map_;
float ocv_arc_depth_; float ocv_arc_depth_;
OcvDerate *default_ocv_derate_; OcvDerate *default_ocv_derate_;
OcvDerateMap ocv_derate_map_; OcvDerateMap ocv_derate_map_;
@ -391,9 +390,6 @@ public:
void setScaleFactors(ScaleFactors *scale_factors); void setScaleFactors(ScaleFactors *scale_factors);
ModeDef *makeModeDef(const char *name); ModeDef *makeModeDef(const char *name);
ModeDef *findModeDef(const char *name); ModeDef *findModeDef(const char *name);
// Add scaled cell after it is complete.
void addScaledCell(OperatingConditions *op_cond,
LibertyCell *scaled_cell);
float area() const { return area_; } float area() const { return area_; }
void setArea(float area); void setArea(float area);
@ -410,15 +406,6 @@ public:
bool isClockGateOther() const; bool isClockGateOther() const;
bool isClockGate() const; bool isClockGate() const;
void setClockGateType(ClockGateType type); void setClockGateType(ClockGateType type);
virtual unsigned addTimingArcSet(TimingArcSet *set);
void addTimingArcAttrs(TimingArcAttrs *attrs);
virtual void addInternalPower(InternalPower *power);
void addInternalPowerAttrs(InternalPowerAttrs *attrs);
virtual void addLeakagePower(LeakagePower *power);
// Call after cell is finished being constructed.
virtual void finish(bool infer_latches,
Report *report,
Debug *debug);
// Internal to LibertyCellTimingArcSetIterator. // Internal to LibertyCellTimingArcSetIterator.
TimingArcSetSeq *timingArcSets(const LibertyPort *from, TimingArcSetSeq *timingArcSets(const LibertyPort *from,
const LibertyPort *to) const; const LibertyPort *to) const;
@ -427,13 +414,44 @@ public:
TimingArcSet *findTimingArcSet(TimingArcSet *key) const; TimingArcSet *findTimingArcSet(TimingArcSet *key) const;
TimingArcSet *findTimingArcSet(unsigned arc_set_index) const; TimingArcSet *findTimingArcSet(unsigned arc_set_index) const;
bool hasTimingArcs(LibertyPort *port) const; bool hasTimingArcs(LibertyPort *port) const;
InternalPowerSeq *internalPowers() { return &internal_powers_; } InternalPowerSeq *internalPowers() { return &internal_powers_; }
LeakagePowerSeq *leakagePowers() { return &leakage_powers_; } LeakagePowerSeq *leakagePowers() { return &leakage_powers_; }
void leakagePower(// Return values. void leakagePower(// Return values.
float &leakage, float &leakage,
bool &exists) const; bool &exists) const;
bool leakagePowerEx() const { return leakage_power_exists_; } bool leakagePowerEx() const { return leakage_power_exists_; }
bool hasSequentials() const; bool hasSequentials() const;
// Find the sequential with the output connected to an (internal) port.
Sequential *outputPortSequential(LibertyPort *port);
// Find bus declaration local to this cell.
BusDcl *findBusDcl(const char *name) const;
// True when TimingArcSetBuilder::makeRegLatchArcs infers register
// timing arcs.
bool hasInferedRegTimingArcs() const { return has_infered_reg_timing_arcs_; }
TestCell *testCell() const { return test_cell_; }
bool isLatchData(LibertyPort *port);
void latchEnable(TimingArcSet *arc_set,
// Return values.
LibertyPort *&enable_port,
FuncExpr *&enable_func,
TransRiseFall *&enable_tr) const;
TransRiseFall *latchCheckEnableTrans(TimingArcSet *check_set);
bool isDisabledConstraint() const { return is_disabled_constraint_; }
LibertyCell *cornerCell(int ap_index);
// AOCV
float ocvArcDepth() const;
OcvDerate *ocvDerate() const;
OcvDerate *findOcvDerate(const char *derate_name);
// Next higher/lower drive equivalent cells.
LibertyCell *higherDrive() const { return higher_drive_; }
LibertyCell *lowerDrive() const { return lower_drive_; }
// Build helpers.
void makeSequential(int size, void makeSequential(int size,
bool is_register, bool is_register,
FuncExpr *clk, FuncExpr *clk,
@ -444,40 +462,31 @@ public:
LogicValue clr_preset_out_inv, LogicValue clr_preset_out_inv,
LibertyPort *output, LibertyPort *output,
LibertyPort *output_inv); LibertyPort *output_inv);
// Find the sequential with the output connected to an (internal) port.
Sequential *outputPortSequential(LibertyPort *port);
// Find bus declaration local to this cell.
BusDcl *findBusDcl(const char *name) const;
void addBusDcl(BusDcl *bus_dcl); void addBusDcl(BusDcl *bus_dcl);
// True when TimingArcSetBuilder::makeRegLatchArcs infers register // Add scaled cell after it is complete.
// timing arcs. void addScaledCell(OperatingConditions *op_cond,
bool hasInferedRegTimingArcs() const { return has_infered_reg_timing_arcs_; } LibertyCell *scaled_cell);
void setHasInferedRegTimingArcs(bool infered); virtual unsigned addTimingArcSet(TimingArcSet *set);
TestCell *testCell() const { return test_cell_; } void addTimingArcAttrs(TimingArcAttrs *attrs);
virtual void addInternalPower(InternalPower *power);
void addInternalPowerAttrs(InternalPowerAttrs *attrs);
virtual void addLeakagePower(LeakagePower *power);
void setLeakagePower(float leakage);
void setOcvArcDepth(float depth);
void setOcvDerate(OcvDerate *derate);
void addOcvDerate(OcvDerate *derate);
void addPgPort(LibertyPgPort *pg_port);
void setTestCell(TestCell *test); void setTestCell(TestCell *test);
bool isLatchData(LibertyPort *port); void setHasInferedRegTimingArcs(bool infered);
void latchEnable(TimingArcSet *arc_set,
// Return values.
LibertyPort *&enable_port,
FuncExpr *&enable_func,
TransRiseFall *&enable_tr) const;
TransRiseFall *latchCheckEnableTrans(TimingArcSet *check_set);
bool isDisabledConstraint() const { return is_disabled_constraint_; }
void setIsDisabledConstraint(bool is_disabled); void setIsDisabledConstraint(bool is_disabled);
LibertyCell *cornerCell(int ap_index);
void setCornerCell(LibertyCell *corner_cell, void setCornerCell(LibertyCell *corner_cell,
int ap_index); int ap_index);
void setLeakagePower(float leakage); // Call after cell is finished being constructed.
virtual void finish(bool infer_latches,
// AOCV Report *report,
float ocvArcDepth() const; Debug *debug);
void setOcvArcDepth(float depth); void setHigherDrive(LibertyCell *cell);
OcvDerate *ocvDerate() const; void setLowerDrive(LibertyCell *cell);
void setOcvDerate(OcvDerate *derate);
OcvDerate *findOcvDerate(const char *derate_name);
void addOcvDerate(OcvDerate *derate);
void addPgPort(LibertyPgPort *pg_port);
protected: protected:
virtual void addPort(ConcretePort *port); virtual void addPort(ConcretePort *port);
@ -511,7 +520,6 @@ protected:
bool interface_timing_; bool interface_timing_;
ClockGateType clock_gate_type_; ClockGateType clock_gate_type_;
TimingArcSetSeq timing_arc_sets_; TimingArcSetSeq timing_arc_sets_;
// Used to find matching arc sets in equivalent cells.
TimingArcSetMap timing_arc_set_map_; TimingArcSetMap timing_arc_set_map_;
LibertyPortPairTimingArcMap port_timing_arc_set_map_; LibertyPortPairTimingArcMap port_timing_arc_set_map_;
LibertyPortTimingArcMap timing_arc_set_from_map_; LibertyPortTimingArcMap timing_arc_set_from_map_;
@ -542,6 +550,9 @@ protected:
float leakage_power_; float leakage_power_;
bool leakage_power_exists_; bool leakage_power_exists_;
LibertyPgPortMap pg_port_map_; LibertyPgPortMap pg_port_map_;
// Next higher/lower drive equivalent cells.
LibertyCell *higher_drive_;
LibertyCell *lower_drive_;
private: private:
DISALLOW_COPY_AND_ASSIGN(LibertyCell); DISALLOW_COPY_AND_ASSIGN(LibertyCell);

View File

@ -578,6 +578,7 @@ void
LibertyReader::endLibrary(LibertyGroup *group) LibertyReader::endLibrary(LibertyGroup *group)
{ {
endLibraryAttrs(group); endLibraryAttrs(group);
library_->finish();
} }
void void

View File

@ -509,6 +509,10 @@ getProperty(const LibertyCell *cell,
return PropertyValue(cell->filename()); return PropertyValue(cell->filename());
else if (stringEqual(property, "library")) else if (stringEqual(property, "library"))
return PropertyValue(cell->libertyLibrary()); return PropertyValue(cell->libertyLibrary());
else if (stringEqual(property, "higher_drive"))
return PropertyValue(cell->higherDrive());
else if (stringEqual(property, "lower_drive"))
return PropertyValue(cell->lowerDrive());
else else
throw PropertyUnknown("liberty cell", property); throw PropertyUnknown("liberty cell", property);
} }
@ -706,7 +710,7 @@ pinSlewProperty(const Pin *pin,
const MinMax *min_max, const MinMax *min_max,
Sta *sta) Sta *sta)
{ {
auto graph = sta->graph(); auto graph = sta->ensureGraph();
Vertex *vertex, *bidirect_drvr_vertex; Vertex *vertex, *bidirect_drvr_vertex;
graph->pinVertices(pin, vertex, bidirect_drvr_vertex); graph->pinVertices(pin, vertex, bidirect_drvr_vertex);
Slew slew = min_max->initValue(); Slew slew = min_max->initValue();

View File

@ -3214,7 +3214,7 @@ Sta::setArcDelay(Edge *edge,
TimingArc *arc, TimingArc *arc,
const Corner *corner, const Corner *corner,
const MinMaxAll *min_max, const MinMaxAll *min_max,
float delay) ArcDelay delay)
{ {
MinMaxIterator mm_iter(min_max); MinMaxIterator mm_iter(min_max);
while (mm_iter.hasNext()) { while (mm_iter.hasNext()) {

View File

@ -705,7 +705,7 @@ public:
TimingArc *arc, TimingArc *arc,
const Corner *corner, const Corner *corner,
const MinMaxAll *min_max, const MinMaxAll *min_max,
float delay); ArcDelay delay);
// Set annotated slew on a vertex for delay calculation. // Set annotated slew on a vertex for delay calculation.
void setAnnotatedSlew(Vertex *vertex, void setAnnotatedSlew(Vertex *vertex,
const Corner *corner, const Corner *corner,

View File

@ -2275,13 +2275,6 @@ cells_equiv_ports(LibertyCell *cell1,
return equivCellPorts(cell1, cell2); return equivCellPorts(cell1, cell2);
} }
LibertyCellSeq *
find_equiv_cells(LibertyCell *cell)
{
LibertyLibrary *library = cell->libertyLibrary();
return library->findEquivCells(cell);
}
void void
set_cmd_namespace_cmd(const char *namespc) set_cmd_namespace_cmd(const char *namespc)
{ {
@ -2652,6 +2645,7 @@ PropertyValue
pin_property(const Pin *pin, pin_property(const Pin *pin,
const char *property) const char *property)
{ {
cmdLinkedNetwork();
return getProperty(pin, property, Sta::sta()); return getProperty(pin, property, Sta::sta());
} }
@ -2659,6 +2653,7 @@ PropertyValue
instance_property(const Instance *inst, instance_property(const Instance *inst,
const char *property) const char *property)
{ {
cmdLinkedNetwork();
return getProperty(inst, property, Sta::sta()); return getProperty(inst, property, Sta::sta());
} }
@ -2666,6 +2661,7 @@ PropertyValue
net_property(const Net *net, net_property(const Net *net,
const char *property) const char *property)
{ {
cmdLinkedNetwork();
return getProperty(net, property, Sta::sta()); return getProperty(net, property, Sta::sta());
} }