LibertyCell::higherDrive(), slowerDrive()
This commit is contained in:
parent
cfaef559e6
commit
6a194ef6ee
|
|
@ -626,7 +626,7 @@ add_flex_bison_dependency(SdfLex SdfParser)
|
|||
include(FindSWIG)
|
||||
|
||||
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
|
||||
WORKING_DIRECTORY ${STA_HOME}
|
||||
DEPENDS ${STA_SWIG_FILES}
|
||||
|
|
|
|||
14
app/StaApp.i
14
app/StaApp.i
|
|
@ -16,10 +16,10 @@
|
|||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
%include "../tcl/StaException.i"
|
||||
%include "../tcl/StaTcl.i"
|
||||
%include "../verilog/Verilog.i"
|
||||
%include "../tcl/NetworkEdit.i"
|
||||
%include "../sdf/Sdf.i"
|
||||
%include "../dcalc/DelayCalc.i"
|
||||
%include "../parasitics/Parasitics.i"
|
||||
%include "StaException.i"
|
||||
%include "StaTcl.i"
|
||||
%include "Verilog.i"
|
||||
%include "NetworkEdit.i"
|
||||
%include "Sdf.i"
|
||||
%include "DelayCalc.i"
|
||||
%include "Parasitics.i"
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@
|
|||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "Machine.hh"
|
||||
#include "UnorderedMap.hh"
|
||||
#include "PortDirection.hh"
|
||||
#include "Transition.hh"
|
||||
#include "MinMax.hh"
|
||||
|
|
@ -28,14 +29,16 @@
|
|||
|
||||
namespace sta {
|
||||
|
||||
typedef Map<unsigned,LibertyCellSeq*, std::less<unsigned> > LibertyCellHashMap;
|
||||
typedef UnorderedMap<unsigned, LibertyCellSeq*> LibertyCellHashMap;
|
||||
typedef Set<LibertyCellSeq*> LibertyCellSeqSet;
|
||||
|
||||
static LibertyCellEquivMap *
|
||||
findEquivCells1(const LibertyLibrary *library);
|
||||
static void
|
||||
deleteEquivCellMap(LibertyCellEquivMap *equiv_map);
|
||||
static void
|
||||
sortCellEquivs(LibertyCellEquivMap *cell_equivs);
|
||||
float
|
||||
static float
|
||||
cellDriveResistance(const LibertyCell *cell);
|
||||
|
||||
static unsigned
|
||||
|
|
@ -55,15 +58,19 @@ static bool
|
|||
equivCellSequentials(const LibertyCell *cell1,
|
||||
const LibertyCell *cell2);
|
||||
|
||||
LibertyCellEquivMap *
|
||||
makeEquivCellMap(const LibertyLibrary *library)
|
||||
void
|
||||
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);
|
||||
// Sort by drive strength.
|
||||
sortCellEquivs(cell_equivs);
|
||||
return cell_equivs;
|
||||
deleteEquivCellMap(cell_equivs);
|
||||
}
|
||||
|
||||
void
|
||||
// Delete the LibertyCellEquivMap returned by makeEquivCellMap.
|
||||
static void
|
||||
deleteEquivCellMap(LibertyCellEquivMap *equiv_map)
|
||||
{
|
||||
// Multiple cells can point to the same cell sequence, so collect
|
||||
|
|
@ -147,14 +154,21 @@ sortCellEquivs(LibertyCellEquivMap *cell_equivs)
|
|||
while (equivs_iter.hasNext()) {
|
||||
LibertyCellSeq *equivs = equivs_iter.next();
|
||||
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.
|
||||
// Note that this function can NOT be static for sun's compiler to
|
||||
// be happy with using it in a sort predicate (presumably because the
|
||||
// template functions are compiled outside the scope of this file).
|
||||
float
|
||||
static float
|
||||
cellDriveResistance(const LibertyCell *cell)
|
||||
{
|
||||
float max_drive = 0.0;
|
||||
|
|
|
|||
|
|
@ -22,14 +22,10 @@
|
|||
|
||||
namespace sta {
|
||||
|
||||
// Build a map from each cell in the library to a group (CellSeq) of
|
||||
// cells with equivalent functionality, sorted by drive strength.
|
||||
LibertyCellEquivMap *
|
||||
makeEquivCellMap(const LibertyLibrary *library);
|
||||
|
||||
// Delete the LibertyCellEquivMap returned by makeEquivCellMap.
|
||||
// Find equivalent cells, sort by drive strength and
|
||||
// and set cell->higherDrive/lowerDrive.
|
||||
void
|
||||
deleteEquivCellMap(LibertyCellEquivMap *equiv_map);
|
||||
findEquivCells(const LibertyLibrary *library);
|
||||
|
||||
// Predicate that is true when the ports, functions, sequentials and
|
||||
// timing arcs match.
|
||||
|
|
|
|||
|
|
@ -82,7 +82,6 @@ LibertyLibrary::LibertyLibrary(const char *name,
|
|||
default_wire_load_mode_(WireloadMode::unknown),
|
||||
default_wire_load_selection_(nullptr),
|
||||
default_operating_conditions_(nullptr),
|
||||
equiv_cell_map_(nullptr),
|
||||
ocv_arc_depth_(0.0),
|
||||
default_ocv_derate_(nullptr)
|
||||
{
|
||||
|
|
@ -123,8 +122,6 @@ LibertyLibrary::~LibertyLibrary()
|
|||
operating_conditions_.deleteContents();
|
||||
wireloads_.deleteContents();
|
||||
wire_load_selections_.deleteContents();
|
||||
if (equiv_cell_map_)
|
||||
deleteEquivCellMap(equiv_cell_map_);
|
||||
delete units_;
|
||||
ocv_derate_map_.deleteContents();
|
||||
|
||||
|
|
@ -500,15 +497,6 @@ LibertyLibrary::setDefaultOutputPinRes(const TransRiseFall *tr,
|
|||
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
|
||||
LibertyLibrary::addWireload(Wireload *wireload)
|
||||
{
|
||||
|
|
@ -748,6 +736,12 @@ LibertyLibrary::makeCornerMap(LibertyCell *cell1,
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
LibertyLibrary::finish()
|
||||
{
|
||||
findEquivCells(this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
float
|
||||
|
|
@ -849,7 +843,9 @@ LibertyCell::LibertyCell(LibertyLibrary *library,
|
|||
ocv_derate_(nullptr),
|
||||
is_disabled_constraint_(false),
|
||||
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
|
||||
LibertyCell::ocvArcDepth() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -223,7 +223,6 @@ public:
|
|||
float slewDerateFromLibrary() const;
|
||||
void setSlewDerateFromLibrary(float derate);
|
||||
|
||||
LibertyCellSeq *findEquivCells(LibertyCell *cell);
|
||||
Units *units() { return units_; }
|
||||
const Units *units() const { return units_; }
|
||||
|
||||
|
|
@ -279,6 +278,7 @@ public:
|
|||
bool link,
|
||||
int ap_index,
|
||||
Report *report);
|
||||
void finish();
|
||||
|
||||
protected:
|
||||
float degradeWireSlew(const LibertyCell *cell,
|
||||
|
|
@ -322,7 +322,6 @@ protected:
|
|||
WireloadSelectionMap wire_load_selections_;
|
||||
OperatingConditionsMap operating_conditions_;
|
||||
OperatingConditions *default_operating_conditions_;
|
||||
LibertyCellEquivMap *equiv_cell_map_;
|
||||
float ocv_arc_depth_;
|
||||
OcvDerate *default_ocv_derate_;
|
||||
OcvDerateMap ocv_derate_map_;
|
||||
|
|
@ -391,9 +390,6 @@ public:
|
|||
void setScaleFactors(ScaleFactors *scale_factors);
|
||||
ModeDef *makeModeDef(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_; }
|
||||
void setArea(float area);
|
||||
|
|
@ -410,15 +406,6 @@ public:
|
|||
bool isClockGateOther() const;
|
||||
bool isClockGate() const;
|
||||
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.
|
||||
TimingArcSetSeq *timingArcSets(const LibertyPort *from,
|
||||
const LibertyPort *to) const;
|
||||
|
|
@ -427,13 +414,44 @@ public:
|
|||
TimingArcSet *findTimingArcSet(TimingArcSet *key) const;
|
||||
TimingArcSet *findTimingArcSet(unsigned arc_set_index) const;
|
||||
bool hasTimingArcs(LibertyPort *port) const;
|
||||
|
||||
InternalPowerSeq *internalPowers() { return &internal_powers_; }
|
||||
LeakagePowerSeq *leakagePowers() { return &leakage_powers_; }
|
||||
void leakagePower(// Return values.
|
||||
float &leakage,
|
||||
bool &exists) const;
|
||||
bool leakagePowerEx() const { return leakage_power_exists_; }
|
||||
|
||||
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,
|
||||
bool is_register,
|
||||
FuncExpr *clk,
|
||||
|
|
@ -444,40 +462,31 @@ public:
|
|||
LogicValue clr_preset_out_inv,
|
||||
LibertyPort *output,
|
||||
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);
|
||||
// True when TimingArcSetBuilder::makeRegLatchArcs infers register
|
||||
// timing arcs.
|
||||
bool hasInferedRegTimingArcs() const { return has_infered_reg_timing_arcs_; }
|
||||
void setHasInferedRegTimingArcs(bool infered);
|
||||
TestCell *testCell() const { return test_cell_; }
|
||||
// Add scaled cell after it is complete.
|
||||
void addScaledCell(OperatingConditions *op_cond,
|
||||
LibertyCell *scaled_cell);
|
||||
virtual unsigned addTimingArcSet(TimingArcSet *set);
|
||||
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);
|
||||
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_; }
|
||||
void setHasInferedRegTimingArcs(bool infered);
|
||||
void setIsDisabledConstraint(bool is_disabled);
|
||||
LibertyCell *cornerCell(int ap_index);
|
||||
void setCornerCell(LibertyCell *corner_cell,
|
||||
int ap_index);
|
||||
void setLeakagePower(float leakage);
|
||||
|
||||
// AOCV
|
||||
float ocvArcDepth() const;
|
||||
void setOcvArcDepth(float depth);
|
||||
OcvDerate *ocvDerate() const;
|
||||
void setOcvDerate(OcvDerate *derate);
|
||||
OcvDerate *findOcvDerate(const char *derate_name);
|
||||
void addOcvDerate(OcvDerate *derate);
|
||||
|
||||
void addPgPort(LibertyPgPort *pg_port);
|
||||
// Call after cell is finished being constructed.
|
||||
virtual void finish(bool infer_latches,
|
||||
Report *report,
|
||||
Debug *debug);
|
||||
void setHigherDrive(LibertyCell *cell);
|
||||
void setLowerDrive(LibertyCell *cell);
|
||||
|
||||
protected:
|
||||
virtual void addPort(ConcretePort *port);
|
||||
|
|
@ -511,7 +520,6 @@ protected:
|
|||
bool interface_timing_;
|
||||
ClockGateType clock_gate_type_;
|
||||
TimingArcSetSeq timing_arc_sets_;
|
||||
// Used to find matching arc sets in equivalent cells.
|
||||
TimingArcSetMap timing_arc_set_map_;
|
||||
LibertyPortPairTimingArcMap port_timing_arc_set_map_;
|
||||
LibertyPortTimingArcMap timing_arc_set_from_map_;
|
||||
|
|
@ -542,6 +550,9 @@ protected:
|
|||
float leakage_power_;
|
||||
bool leakage_power_exists_;
|
||||
LibertyPgPortMap pg_port_map_;
|
||||
// Next higher/lower drive equivalent cells.
|
||||
LibertyCell *higher_drive_;
|
||||
LibertyCell *lower_drive_;
|
||||
|
||||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(LibertyCell);
|
||||
|
|
|
|||
|
|
@ -578,6 +578,7 @@ void
|
|||
LibertyReader::endLibrary(LibertyGroup *group)
|
||||
{
|
||||
endLibraryAttrs(group);
|
||||
library_->finish();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -509,6 +509,10 @@ getProperty(const LibertyCell *cell,
|
|||
return PropertyValue(cell->filename());
|
||||
else if (stringEqual(property, "library"))
|
||||
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
|
||||
throw PropertyUnknown("liberty cell", property);
|
||||
}
|
||||
|
|
@ -706,7 +710,7 @@ pinSlewProperty(const Pin *pin,
|
|||
const MinMax *min_max,
|
||||
Sta *sta)
|
||||
{
|
||||
auto graph = sta->graph();
|
||||
auto graph = sta->ensureGraph();
|
||||
Vertex *vertex, *bidirect_drvr_vertex;
|
||||
graph->pinVertices(pin, vertex, bidirect_drvr_vertex);
|
||||
Slew slew = min_max->initValue();
|
||||
|
|
|
|||
|
|
@ -3214,7 +3214,7 @@ Sta::setArcDelay(Edge *edge,
|
|||
TimingArc *arc,
|
||||
const Corner *corner,
|
||||
const MinMaxAll *min_max,
|
||||
float delay)
|
||||
ArcDelay delay)
|
||||
{
|
||||
MinMaxIterator mm_iter(min_max);
|
||||
while (mm_iter.hasNext()) {
|
||||
|
|
|
|||
|
|
@ -705,7 +705,7 @@ public:
|
|||
TimingArc *arc,
|
||||
const Corner *corner,
|
||||
const MinMaxAll *min_max,
|
||||
float delay);
|
||||
ArcDelay delay);
|
||||
// Set annotated slew on a vertex for delay calculation.
|
||||
void setAnnotatedSlew(Vertex *vertex,
|
||||
const Corner *corner,
|
||||
|
|
|
|||
10
tcl/StaTcl.i
10
tcl/StaTcl.i
|
|
@ -2275,13 +2275,6 @@ cells_equiv_ports(LibertyCell *cell1,
|
|||
return equivCellPorts(cell1, cell2);
|
||||
}
|
||||
|
||||
LibertyCellSeq *
|
||||
find_equiv_cells(LibertyCell *cell)
|
||||
{
|
||||
LibertyLibrary *library = cell->libertyLibrary();
|
||||
return library->findEquivCells(cell);
|
||||
}
|
||||
|
||||
void
|
||||
set_cmd_namespace_cmd(const char *namespc)
|
||||
{
|
||||
|
|
@ -2652,6 +2645,7 @@ PropertyValue
|
|||
pin_property(const Pin *pin,
|
||||
const char *property)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
return getProperty(pin, property, Sta::sta());
|
||||
}
|
||||
|
||||
|
|
@ -2659,6 +2653,7 @@ PropertyValue
|
|||
instance_property(const Instance *inst,
|
||||
const char *property)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
return getProperty(inst, property, Sta::sta());
|
||||
}
|
||||
|
||||
|
|
@ -2666,6 +2661,7 @@ PropertyValue
|
|||
net_property(const Net *net,
|
||||
const char *property)
|
||||
{
|
||||
cmdLinkedNetwork();
|
||||
return getProperty(net, property, Sta::sta());
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue