resizer support
This commit is contained in:
parent
8242035b22
commit
53df9472d7
|
|
@ -56,9 +56,6 @@ message(STATUS "Install prefix: ${CMAKE_INSTALL_PREFIX}")
|
|||
|
||||
set(STA_SOURCE
|
||||
app/StaMain.cc
|
||||
app/StaApp_wrap.cc
|
||||
app/TclInitVar.cc
|
||||
app/StaApp_wrap.cc
|
||||
|
||||
dcalc/ArcDelayCalc.cc
|
||||
dcalc/ArnoldiDelayCalc.cc
|
||||
|
|
@ -213,6 +210,11 @@ set(STA_SOURCE
|
|||
verilog/VerilogParse.cc
|
||||
)
|
||||
|
||||
set(STA_CMD_SOURCE
|
||||
app/TclInitVar.cc
|
||||
app/StaApp_wrap.cc
|
||||
)
|
||||
|
||||
set(STA_HEADERS
|
||||
app/StaMain.hh
|
||||
|
||||
|
|
@ -648,7 +650,6 @@ add_custom_command(OUTPUT ${STA_HOME}/app/TclInitVar.cc
|
|||
set(STA_INCLUDE_DIRS
|
||||
app
|
||||
dcalc
|
||||
dcalc/verilog
|
||||
graph
|
||||
liberty
|
||||
network
|
||||
|
|
@ -663,13 +664,29 @@ set(STA_INCLUDE_DIRS
|
|||
)
|
||||
|
||||
###########################################################
|
||||
# Library
|
||||
# Library without TCL commands.
|
||||
# This is used to build applications that define
|
||||
# their own SWIG and TCL commands.
|
||||
###########################################################
|
||||
|
||||
# compatibility with configure
|
||||
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${STA_HOME}/app)
|
||||
|
||||
add_library(OpenSTA ${STA_SOURCE})
|
||||
add_library(OpenSTAnoCmds ${STA_SOURCE})
|
||||
|
||||
target_include_directories(OpenSTAnoCmds PUBLIC ${STA_INCLUDE_DIRS})
|
||||
|
||||
target_compile_features(OpenSTAnoCmds
|
||||
PUBLIC cxx_auto_type
|
||||
)
|
||||
|
||||
target_compile_options(OpenSTAnoCmds PUBLIC ${STA_COMPILE_OPTIONS})
|
||||
|
||||
###########################################################
|
||||
# Library
|
||||
###########################################################
|
||||
|
||||
add_library(OpenSTA ${STA_SOURCE} ${STA_CMD_SOURCE})
|
||||
|
||||
target_include_directories(OpenSTA PUBLIC ${STA_INCLUDE_DIRS})
|
||||
|
||||
|
|
@ -677,6 +694,8 @@ target_compile_features(OpenSTA
|
|||
PUBLIC cxx_auto_type
|
||||
)
|
||||
|
||||
target_compile_options(OpenSTA PUBLIC ${STA_COMPILE_OPTIONS})
|
||||
|
||||
###########################################################
|
||||
# Executable
|
||||
###########################################################
|
||||
|
|
@ -704,9 +723,7 @@ if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
|||
target_link_libraries(sta -pthread)
|
||||
endif()
|
||||
|
||||
target_compile_options(OpenSTA PUBLIC ${STA_COMPILE_OPTIONS})
|
||||
target_compile_options(sta PUBLIC ${STA_COMPILE_OPTIONS})
|
||||
message(STATUS "Compiler options: ${STA_COMPILE_OPTIONS}")
|
||||
|
||||
################################################################
|
||||
# Install
|
||||
|
|
|
|||
|
|
@ -87,6 +87,13 @@ GraphDelayCalc::loadCap(const Pin *,
|
|||
return 0.0F;
|
||||
}
|
||||
|
||||
float
|
||||
GraphDelayCalc::loadCap(const Pin *,
|
||||
const DcalcAnalysisPt *) const
|
||||
{
|
||||
return 0.0F;
|
||||
}
|
||||
|
||||
void
|
||||
GraphDelayCalc::netCaps(const Pin *,
|
||||
const TransRiseFall *,
|
||||
|
|
|
|||
|
|
@ -79,10 +79,13 @@ public:
|
|||
// Return values.
|
||||
float &pin_cap,
|
||||
float &wire_cap) const;
|
||||
// Load pin_cap + wire_cap.
|
||||
// Load pin_cap + wire_cap including parasitic.
|
||||
virtual float loadCap(const Pin *drvr_pin,
|
||||
const TransRiseFall *to_tr,
|
||||
const DcalcAnalysisPt *dcalc_ap) const;
|
||||
// Load pin_cap + wire_cap including parasitic min/max for rise/fall.
|
||||
virtual float loadCap(const Pin *drvr_pin,
|
||||
const DcalcAnalysisPt *dcalc_ap) const;
|
||||
// Load pin_cap + wire_cap.
|
||||
virtual float loadCap(const Pin *drvr_pin,
|
||||
Parasitic *drvr_parasitic,
|
||||
|
|
|
|||
|
|
@ -1039,6 +1039,24 @@ GraphDelayCalc1::findDriverEdgeDelays(LibertyCell *drvr_cell,
|
|||
return delay_changed;
|
||||
}
|
||||
|
||||
float
|
||||
GraphDelayCalc1::loadCap(const Pin *drvr_pin,
|
||||
const DcalcAnalysisPt *dcalc_ap) const
|
||||
{
|
||||
const MinMax *min_max = dcalc_ap->constraintMinMax();
|
||||
float load_cap = 0.0;
|
||||
TransRiseFallIterator drvr_tr_iter;
|
||||
while (drvr_tr_iter.hasNext()) {
|
||||
TransRiseFall *drvr_tr = drvr_tr_iter.next();
|
||||
Parasitic *drvr_parasitic = arc_delay_calc_->findParasitic(drvr_pin, drvr_tr,
|
||||
dcalc_ap);
|
||||
float cap = loadCap(drvr_pin, nullptr, drvr_parasitic, drvr_tr, dcalc_ap);
|
||||
if (min_max->compare(cap, load_cap))
|
||||
load_cap = cap;
|
||||
}
|
||||
return load_cap;
|
||||
}
|
||||
|
||||
float
|
||||
GraphDelayCalc1::loadCap(const Pin *drvr_pin,
|
||||
const TransRiseFall *drvr_tr,
|
||||
|
|
|
|||
|
|
@ -55,6 +55,8 @@ public:
|
|||
virtual float loadCap(const Pin *drvr_pin,
|
||||
const TransRiseFall *drvr_tr,
|
||||
const DcalcAnalysisPt *dcalc_ap) const;
|
||||
virtual float loadCap(const Pin *drvr_pin,
|
||||
const DcalcAnalysisPt *dcalc_ap) const;
|
||||
virtual void loadCap(const Pin *drvr_pin,
|
||||
Parasitic *drvr_parasitic,
|
||||
const TransRiseFall *tr,
|
||||
|
|
|
|||
|
|
@ -35,8 +35,6 @@ typedef Set<LibertyCellSeq*> LibertyCellSeqSet;
|
|||
static LibertyCellEquivMap *
|
||||
findEquivCells1(const LibertyLibrary *library);
|
||||
static void
|
||||
deleteEquivCellMap(LibertyCellEquivMap *equiv_map);
|
||||
static void
|
||||
sortCellEquivs(LibertyCellEquivMap *cell_equivs);
|
||||
static float
|
||||
cellDriveResistance(const LibertyCell *cell);
|
||||
|
|
@ -58,7 +56,7 @@ static bool
|
|||
equivCellSequentials(const LibertyCell *cell1,
|
||||
const LibertyCell *cell2);
|
||||
|
||||
void
|
||||
LibertyCellEquivMap *
|
||||
findEquivCells(const LibertyLibrary *library)
|
||||
{
|
||||
// Build a map from each cell in the library to a group (CellSeq) of
|
||||
|
|
@ -66,11 +64,11 @@ findEquivCells(const LibertyLibrary *library)
|
|||
LibertyCellEquivMap *cell_equivs = findEquivCells1(library);
|
||||
// Sort by drive strength.
|
||||
sortCellEquivs(cell_equivs);
|
||||
deleteEquivCellMap(cell_equivs);
|
||||
return cell_equivs;
|
||||
}
|
||||
|
||||
// Delete the LibertyCellEquivMap returned by makeEquivCellMap.
|
||||
static void
|
||||
void
|
||||
deleteEquivCellMap(LibertyCellEquivMap *equiv_map)
|
||||
{
|
||||
// Multiple cells can point to the same cell sequence, so collect
|
||||
|
|
@ -129,12 +127,7 @@ findEquivCells1(const LibertyLibrary *library)
|
|||
}
|
||||
}
|
||||
|
||||
LibertyCellHashMap::Iterator hash_iter(cell_hash);
|
||||
while (hash_iter.hasNext()) {
|
||||
LibertyCellSeq *cells = hash_iter.next();
|
||||
delete cells;
|
||||
}
|
||||
|
||||
cell_hash.deleteContents();
|
||||
return cell_equivs;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,8 +24,11 @@ namespace sta {
|
|||
|
||||
// Find equivalent cells, sort by drive strength and
|
||||
// and set cell->higherDrive/lowerDrive.
|
||||
void
|
||||
LibertyCellEquivMap *
|
||||
findEquivCells(const LibertyLibrary *library);
|
||||
// Delete findEquivCells return value.
|
||||
void
|
||||
deleteEquivCellMap(LibertyCellEquivMap *equiv_map);
|
||||
|
||||
// Predicate that is true when the ports, functions, sequentials and
|
||||
// timing arcs match.
|
||||
|
|
|
|||
|
|
@ -83,12 +83,15 @@ LibertyLibrary::LibertyLibrary(const char *name,
|
|||
default_wire_load_selection_(nullptr),
|
||||
default_operating_conditions_(nullptr),
|
||||
ocv_arc_depth_(0.0),
|
||||
default_ocv_derate_(nullptr)
|
||||
default_ocv_derate_(nullptr),
|
||||
equiv_cell_map_(nullptr),
|
||||
buffers_(nullptr)
|
||||
{
|
||||
// Scalar templates are builtin.
|
||||
for (int i = 0; i != int(TableTemplateType::count); i++) {
|
||||
TableTemplateType type = static_cast<TableTemplateType>(i);
|
||||
TableTemplate *scalar_template = new TableTemplate("scalar", nullptr, nullptr, nullptr);
|
||||
TableTemplate *scalar_template = new TableTemplate("scalar", nullptr,
|
||||
nullptr, nullptr);
|
||||
addTableTemplate(scalar_template, type);
|
||||
}
|
||||
|
||||
|
|
@ -129,6 +132,8 @@ LibertyLibrary::~LibertyLibrary()
|
|||
const char *supply_name = name_volt.first;
|
||||
stringDelete(supply_name);
|
||||
}
|
||||
deleteEquivCellMap(equiv_cell_map_);
|
||||
delete buffers_;
|
||||
}
|
||||
|
||||
LibertyCell *
|
||||
|
|
@ -149,6 +154,22 @@ LibertyLibrary::findLibertyCellsMatching(PatternMatch *pattern,
|
|||
}
|
||||
}
|
||||
|
||||
LibertyCellSeq *
|
||||
LibertyLibrary::buffers()
|
||||
{
|
||||
if (buffers_ == nullptr) {
|
||||
buffers_ = new LibertyCellSeq;
|
||||
LibertyCellIterator cell_iter(this);
|
||||
while (cell_iter.hasNext()) {
|
||||
LibertyCell *cell = cell_iter.next();
|
||||
if (!cell->dontUse()
|
||||
&& cell->isBuffer())
|
||||
buffers_->push_back(cell);
|
||||
}
|
||||
}
|
||||
return buffers_;
|
||||
}
|
||||
|
||||
void
|
||||
LibertyLibrary::setDelayModelType(DelayModelType type)
|
||||
{
|
||||
|
|
@ -737,9 +758,17 @@ LibertyLibrary::makeCornerMap(LibertyCell *cell1,
|
|||
}
|
||||
|
||||
void
|
||||
LibertyLibrary::finish()
|
||||
LibertyLibrary::ensureEquivCells()
|
||||
{
|
||||
findEquivCells(this);
|
||||
if (equiv_cell_map_ == nullptr)
|
||||
equiv_cell_map_ = sta::findEquivCells(this);
|
||||
}
|
||||
|
||||
LibertyCellSeq *
|
||||
LibertyLibrary::findEquivCells(LibertyCell *cell)
|
||||
{
|
||||
ensureEquivCells();
|
||||
return equiv_cell_map_->findKey(cell);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
|
@ -1022,33 +1051,16 @@ LibertyCell::setClockGateType(ClockGateType type)
|
|||
|
||||
bool
|
||||
LibertyCell::isBuffer() const
|
||||
{
|
||||
LibertyPort *input, *output;
|
||||
return isBuffer(input, output);
|
||||
}
|
||||
|
||||
bool
|
||||
LibertyCell::isBuffer(// Return values.
|
||||
LibertyPort *&input,
|
||||
LibertyPort *&output) const
|
||||
{
|
||||
if (ports_.size() == 2) {
|
||||
LibertyPort *port1 = static_cast<LibertyPort*>(ports_[0]);
|
||||
LibertyPort *port2 = static_cast<LibertyPort*>(ports_[1]);
|
||||
if (port1->direction()->isInput()
|
||||
&& port2->direction()->isOutput()
|
||||
&& hasBufferFunc(port1, port2)) {
|
||||
input = port1;
|
||||
output = port2;
|
||||
return true;
|
||||
}
|
||||
else if (port2->direction()->isInput()
|
||||
&& port1->direction()->isOutput()
|
||||
&& hasBufferFunc(port2, port1)) {
|
||||
input = port2;
|
||||
output = port1;
|
||||
return true;
|
||||
}
|
||||
return (port1->direction()->isInput()
|
||||
&& port2->direction()->isOutput()
|
||||
&& hasBufferFunc(port1, port2))
|
||||
|| (port2->direction()->isInput()
|
||||
&& port1->direction()->isOutput()
|
||||
&& hasBufferFunc(port2, port1));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1063,6 +1075,24 @@ LibertyCell::hasBufferFunc(const LibertyPort *input,
|
|||
&& func->port() == input;
|
||||
}
|
||||
|
||||
void
|
||||
LibertyCell::bufferPorts(// Return values.
|
||||
LibertyPort *&input,
|
||||
LibertyPort *&output)
|
||||
{
|
||||
LibertyPort *port1 = static_cast<LibertyPort*>(ports_[0]);
|
||||
LibertyPort *port2 = static_cast<LibertyPort*>(ports_[1]);
|
||||
if (port1->direction()->isInput()
|
||||
&& port2->direction()->isOutput()) {
|
||||
input = port1;
|
||||
output = port2;
|
||||
}
|
||||
else {
|
||||
input = port2;
|
||||
output = port1;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned
|
||||
LibertyCell::addTimingArcSet(TimingArcSet *arc_set)
|
||||
{
|
||||
|
|
@ -1427,6 +1457,20 @@ LibertyCell::setCornerCell(LibertyCell *corner_cell,
|
|||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
LibertyCell *
|
||||
LibertyCell::higherDrive() const
|
||||
{
|
||||
liberty_library_->ensureEquivCells();
|
||||
return higher_drive_;
|
||||
}
|
||||
|
||||
LibertyCell *
|
||||
LibertyCell::lowerDrive() const
|
||||
{
|
||||
liberty_library_->ensureEquivCells();
|
||||
return lower_drive_;
|
||||
}
|
||||
|
||||
void
|
||||
LibertyCell::setHigherDrive(LibertyCell *cell)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -118,6 +118,10 @@ public:
|
|||
LibertyCell *findLibertyCell(const char *name) const;
|
||||
void findLibertyCellsMatching(PatternMatch *pattern,
|
||||
LibertyCellSeq *cells);
|
||||
LibertyCellSeq *findEquivCells(LibertyCell *cell);
|
||||
// Liberty cells that are buffers.
|
||||
LibertyCellSeq *buffers();
|
||||
|
||||
DelayModelType delayModelType() const { return delay_model_type_; }
|
||||
void setDelayModelType(DelayModelType type);
|
||||
void addBusDcl(BusDcl *bus_dcl);
|
||||
|
|
@ -262,6 +266,7 @@ public:
|
|||
// Make scaled cell. Call LibertyCell::addScaledCell after it is complete.
|
||||
LibertyCell *makeScaledCell(const char *name,
|
||||
const char *filename);
|
||||
|
||||
static void
|
||||
makeCornerMap(LibertyLibrary *lib,
|
||||
int ap_index,
|
||||
|
|
@ -278,7 +283,6 @@ public:
|
|||
bool link,
|
||||
int ap_index,
|
||||
Report *report);
|
||||
void finish();
|
||||
|
||||
protected:
|
||||
float degradeWireSlew(const LibertyCell *cell,
|
||||
|
|
@ -286,6 +290,7 @@ protected:
|
|||
const TableModel *model,
|
||||
float in_slew,
|
||||
float wire_delay) const;
|
||||
void ensureEquivCells();
|
||||
|
||||
Units *units_;
|
||||
DelayModelType delay_model_type_;
|
||||
|
|
@ -326,6 +331,8 @@ protected:
|
|||
OcvDerate *default_ocv_derate_;
|
||||
OcvDerateMap ocv_derate_map_;
|
||||
SupplyVoltageMap supply_voltage_map_;
|
||||
LibertyCellEquivMap *equiv_cell_map_;
|
||||
LibertyCellSeq *buffers_;
|
||||
|
||||
// Set if any library has rise/fall capacitances.
|
||||
static bool found_rise_fall_caps_;
|
||||
|
|
@ -337,6 +344,7 @@ protected:
|
|||
private:
|
||||
DISALLOW_COPY_AND_ASSIGN(LibertyLibrary);
|
||||
|
||||
friend class LibertyCell;
|
||||
friend class LibertyCellIterator;
|
||||
friend class TableTemplateIterator;
|
||||
friend class OperatingConditionsIterator;
|
||||
|
|
@ -448,8 +456,8 @@ public:
|
|||
OcvDerate *findOcvDerate(const char *derate_name);
|
||||
|
||||
// Next higher/lower drive equivalent cells.
|
||||
LibertyCell *higherDrive() const { return higher_drive_; }
|
||||
LibertyCell *lowerDrive() const { return lower_drive_; }
|
||||
LibertyCell *higherDrive() const;
|
||||
LibertyCell *lowerDrive() const;
|
||||
|
||||
// Build helpers.
|
||||
void makeSequential(int size,
|
||||
|
|
@ -488,9 +496,10 @@ public:
|
|||
void setHigherDrive(LibertyCell *cell);
|
||||
void setLowerDrive(LibertyCell *cell);
|
||||
bool isBuffer() const;
|
||||
bool isBuffer(// Return values.
|
||||
LibertyPort *&input,
|
||||
LibertyPort *&output) const;
|
||||
// Only valid when isBuffer() returns true.
|
||||
void bufferPorts(// Return values.
|
||||
LibertyPort *&input,
|
||||
LibertyPort *&output);
|
||||
|
||||
protected:
|
||||
virtual void addPort(ConcretePort *port);
|
||||
|
|
|
|||
|
|
@ -578,7 +578,6 @@ void
|
|||
LibertyReader::endLibrary(LibertyGroup *group)
|
||||
{
|
||||
endLibraryAttrs(group);
|
||||
library_->finish();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -500,7 +500,7 @@ Power::power(const Instance *inst,
|
|||
const Pin *to_pin = pin_iter->next();
|
||||
const LibertyPort *to_port = network_->libertyPort(to_pin);
|
||||
float load_cap = to_port->direction()->isAnyOutput()
|
||||
? graph_delay_calc_->loadCap(to_pin, TransRiseFall::rise(), dcalc_ap)
|
||||
? graph_delay_calc_->loadCap(to_pin, dcalc_ap)
|
||||
: 0.0;
|
||||
PwrActivity activity = findClkedActivity(to_pin, inst_clk);
|
||||
if (to_port->direction()->isAnyOutput())
|
||||
|
|
|
|||
|
|
@ -1907,6 +1907,14 @@ proc get_full_name { object } {
|
|||
return [get_object_property $object "full_name"]
|
||||
}
|
||||
|
||||
proc sort_by_name { objects } {
|
||||
return [lsort -command name_cmp $objects]
|
||||
}
|
||||
|
||||
proc name_cmp { obj1 obj2 } {
|
||||
return [string compare [get_name $obj1] [get_name $obj2]]
|
||||
}
|
||||
|
||||
proc sort_by_full_name { objects } {
|
||||
return [lsort -command full_name_cmp $objects]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -225,8 +225,8 @@ proc replace_cell { instances lib_cell } {
|
|||
set insts [get_instances_error "instances" $instances]
|
||||
foreach inst $insts {
|
||||
set inst_cell [$inst liberty_cell]
|
||||
if { $inst_cell != "NULL" \
|
||||
&& ![cells_equiv_ports $inst_cell $cell] } {
|
||||
if { $inst_cell == "NULL" \
|
||||
|| ![equiv_cell_ports $inst_cell $cell] } {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -956,7 +956,7 @@ proc_redirect report_clock_properties {
|
|||
define_sta_cmd_args "report_object_full_names" {[-verbose] objects}
|
||||
|
||||
proc report_object_full_names { args } {
|
||||
parse_key_args "report_object_names" args keys {} flags {-verbose}
|
||||
parse_key_args "report_object_full_names" args keys {} flags {-verbose}
|
||||
|
||||
set objects [lindex $args 0]
|
||||
if { [info exists flags(-verbose)] } {
|
||||
|
|
@ -986,7 +986,7 @@ proc report_object_names { args } {
|
|||
if { [info exists flags(-verbose)] } {
|
||||
puts -nonewline "{"
|
||||
set first 1
|
||||
foreach obj [sort_by_full_name $objects] {
|
||||
foreach obj [sort_by_name $objects] {
|
||||
if { !$first } {
|
||||
puts -nonewline ", "
|
||||
}
|
||||
|
|
@ -995,7 +995,7 @@ proc report_object_names { args } {
|
|||
}
|
||||
puts "}"
|
||||
} else {
|
||||
foreach obj [sort_by_full_name $objects] {
|
||||
foreach obj [sort_by_name $objects] {
|
||||
puts [get_name $obj]
|
||||
}
|
||||
}
|
||||
|
|
|
|||
15
tcl/StaTcl.i
15
tcl/StaTcl.i
|
|
@ -2273,8 +2273,21 @@ find_cells_matching(const char *pattern,
|
|||
return cells;
|
||||
}
|
||||
|
||||
LibertyCellSeq *
|
||||
find_library_buffers(LibertyLibrary *library)
|
||||
{
|
||||
return library->buffers();
|
||||
}
|
||||
|
||||
LibertyCellSeq *
|
||||
equiv_cells(LibertyCell *cell)
|
||||
{
|
||||
LibertyLibrary *library = cell->libertyLibrary();
|
||||
return library->findEquivCells(cell);
|
||||
}
|
||||
|
||||
bool
|
||||
cells_equiv_ports(LibertyCell *cell1,
|
||||
equiv_cell_ports(LibertyCell *cell1,
|
||||
LibertyCell *cell2)
|
||||
{
|
||||
return equivCellPorts(cell1, cell2);
|
||||
|
|
|
|||
Loading…
Reference in New Issue