diff --git a/CMakeLists.txt b/CMakeLists.txt index 26e05729..4540de0b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ project(STA VERSION 2.6.0 ) option(CUDD_DIR "CUDD BDD package directory") -option(USE_TCL_READLINE "Use TCL readliine package" ON) +option(USE_TCL_READLINE "Use TCL readline package" ON) option(USE_SANITIZE "Compile with santize address enabled") # Turn on to debug compiler args. diff --git a/app/Main.cc b/app/Main.cc index 1a15e6c9..596eb222 100644 --- a/app/Main.cc +++ b/app/Main.cc @@ -40,6 +40,7 @@ using sta::evalTclInit; using sta::sourceTclFile; using sta::parseThreadsArg; using sta::tcl_inits; +using sta::is_regular_file; // Swig uses C linkage for init functions. extern "C" { @@ -133,7 +134,7 @@ staTclAppInit(int argc, string init_path = home; init_path += "/"; init_path += init_filename; - if (std::filesystem::is_regular_file(init_path.c_str())) + if (is_regular_file(init_path.c_str())) sourceTclFile(init_path.c_str(), true, true, interp); } } diff --git a/include/sta/Liberty.hh b/include/sta/Liberty.hh index 0da0a530..a18cceec 100644 --- a/include/sta/Liberty.hh +++ b/include/sta/Liberty.hh @@ -462,10 +462,12 @@ public: bool &exists) const; bool leakagePowerExists() const { return leakage_power_exists_; } - const SequentialSeq &sequentials() const { return sequentials_; } + // Register, Latch or Statetable. bool hasSequentials() const; + const SequentialSeq &sequentials() const { return sequentials_; } // Find the sequential with the output connected to an (internal) port. Sequential *outputPortSequential(LibertyPort *port); + const Statetable *statetable() const { return statetable_; } // Find bus declaration local to this cell. BusDcl *findBusDcl(const char *name) const; @@ -502,6 +504,9 @@ public: LogicValue clr_preset_out_inv, LibertyPort *output, LibertyPort *output_inv); + void makeStatetable(LibertyPortSeq &input_ports, + LibertyPortSeq &internal_ports, + StatetableRows &table); void addBusDcl(BusDcl *bus_dcl); // Add scaled cell after it is complete. void addScaledCell(OperatingConditions *op_cond, @@ -600,6 +605,7 @@ protected: LeakagePowerSeq leakage_powers_; SequentialSeq sequentials_; PortToSequentialMap port_to_seq_map_; + Statetable *statetable_; BusDclMap bus_dcls_; ModeDefMap mode_defs_; ScaleFactors *scale_factors_; diff --git a/include/sta/LibertyClass.hh b/include/sta/LibertyClass.hh index 850e12e0..8217e031 100644 --- a/include/sta/LibertyClass.hh +++ b/include/sta/LibertyClass.hh @@ -24,6 +24,8 @@ namespace sta { +using std::vector; + class Units; class Unit; class LibertyLibrary; @@ -58,6 +60,8 @@ class Transition; class RiseFall; class RiseFallBoth; class ReceiverModel; +class Statetable; +class StatetableRow; typedef Vector LibertyLibrarySeq; typedef Vector LibertyCellSeq; @@ -71,6 +75,7 @@ typedef std::shared_ptr TablePtr; typedef std::shared_ptr TimingArcAttrsPtr; typedef std::shared_ptr TableAxisPtr; typedef std::shared_ptr ReceiverModelPtr; +typedef vector StatetableRows; enum class ScaleFactorType : unsigned { pin_cap, diff --git a/include/sta/PathEnd.hh b/include/sta/PathEnd.hh index 8c27be9a..6bca1f97 100644 --- a/include/sta/PathEnd.hh +++ b/include/sta/PathEnd.hh @@ -144,6 +144,7 @@ public: virtual const PathVertex *dataClkPath() const { return nullptr; } virtual int setupDefaultCycles() const { return 1; } virtual Delay clkSkew(const StaState *sta); + virtual bool ignoreClkLatency(const StaState * /* sta */) const { return false; } static bool less(const PathEnd *path_end1, const PathEnd *path_end2, @@ -206,6 +207,9 @@ protected: PathDelay *path_delay, Arrival src_clk_arrival, const StaState *sta); + static bool ignoreClkLatency(const PathRef &path, + PathDelay *path_delay, + const StaState *sta); PathRef path_; }; @@ -384,6 +388,7 @@ public: Crpr &crpr_diff, Delay &max_borrow, bool &borrow_limit_exists) const; + virtual bool ignoreClkLatency(const StaState *sta) const; protected: PathEndLatchCheck(Path *path, @@ -569,6 +574,7 @@ public: virtual int exceptPathCmp(const PathEnd *path_end, const StaState *sta) const; bool hasOutputDelay() const { return output_delay_ != nullptr; } + virtual bool ignoreClkLatency(const StaState *sta) const; protected: PathEndPathDelay(PathDelay *path_delay, diff --git a/include/sta/Search.hh b/include/sta/Search.hh index 8705a382..37d65dfc 100644 --- a/include/sta/Search.hh +++ b/include/sta/Search.hh @@ -155,18 +155,6 @@ public: Arrival pathClkPathArrival(const Path *path) const; PathGroup *pathGroup(const PathEnd *path_end) const; - void updatePathGroups(int group_count, - int endpoint_count, - bool unique_pins, - float min_slack, - float max_slack, - PathGroupNameSet *group_names, - bool setup, - bool hold, - bool recovery, - bool removal, - bool clk_gating_setup, - bool clk_gating_hold); void deletePathGroups(); virtual ExceptionPath *exceptionTo(ExceptionPathType type, const Path *path, @@ -523,18 +511,18 @@ protected: void tnsDecr(Vertex *vertex, PathAPIndex path_ap_index); void tnsNotifyBefore(Vertex *vertex); - PathGroups *makePathGroups(int group_count, - int endpoint_count, - bool unique_pins, - float min_slack, - float max_slack, - PathGroupNameSet *group_names, - bool setup, - bool hold, - bool recovery, - bool removal, - bool clk_gating_setup, - bool clk_gating_hold); + void makePathGroups(int group_count, + int endpoint_count, + bool unique_pins, + float min_slack, + float max_slack, + PathGroupNameSet *group_names, + bool setup, + bool hold, + bool recovery, + bool removal, + bool clk_gating_setup, + bool clk_gating_hold); bool matchesFilterTo(Path *path, const ClockEdge *to_clk_edge) const; PathRef pathClkPathArrival1(const Path *path) const; diff --git a/include/sta/Sequential.hh b/include/sta/Sequential.hh index 6f10b2cd..7d431f0e 100644 --- a/include/sta/Sequential.hh +++ b/include/sta/Sequential.hh @@ -16,11 +16,42 @@ #pragma once +#include + #include "LibertyClass.hh" #include "NetworkClass.hh" namespace sta { +enum class StateInputValue { + low, + high, + dont_care, + low_high, + high_low, + rise, + fall, + not_rise, + not_fall +}; + +enum class StateInternalValue { + low, + high, + unspecified, + low_high, + high_low, + unknown, + hold +}; + +class StatetableRow; + +using std::vector; + +typedef vector StateInputValues; +typedef vector StateInternalValues; + // Register/Latch class Sequential { @@ -63,8 +94,41 @@ protected: LibertyPort *output_; LibertyPort *output_inv_; -private: friend class LibertyCell; }; +class Statetable +{ +public: + const LibertyPortSeq &inputPorts() const { return input_ports_; } + const LibertyPortSeq &internalPorts() const { return internal_ports_; } + const StatetableRows &table() const { return table_; } + +protected: + Statetable(LibertyPortSeq &input_ports, + LibertyPortSeq &internal_ports, + StatetableRows &table); + LibertyPortSeq input_ports_; + LibertyPortSeq internal_ports_; + StatetableRows table_; + + friend class LibertyCell; +}; + +class StatetableRow +{ +public: + StatetableRow(StateInputValues &input_values, + StateInternalValues ¤t_values, + StateInternalValues &next_values); + const StateInputValues &inputValues() const { return input_values_; } + const StateInternalValues ¤tValues() const { return current_values_; } + const StateInternalValues &nextValues() const { return next_values_; } + +private: + StateInputValues input_values_; + StateInternalValues current_values_; + StateInternalValues next_values_; +}; + } // namespace diff --git a/liberty/EquivCells.cc b/liberty/EquivCells.cc index 84543d97..5e43cb98 100644 --- a/liberty/EquivCells.cc +++ b/liberty/EquivCells.cc @@ -38,6 +38,24 @@ hashCellPorts(const LibertyCell *cell); static unsigned hashCellSequentials(const LibertyCell *cell); static unsigned +hashSequential(const Sequential *seq); +bool +equivCellStatetables(const LibertyCell *cell1, + const LibertyCell *cell2); +static bool +equivCellPortSeq(const LibertyPortSeq &ports1, + const LibertyPortSeq &ports2); +static bool +equivStatetableRows(const StatetableRows &table1, + const StatetableRows &table2); +static bool +equivStatetableRow(const StatetableRow &row1, + const StatetableRow &row2); +static unsigned +hashStatetable(const Statetable *statetable); +static unsigned +hashStatetableRow(const StatetableRow &row); +static unsigned hashFuncExpr(const FuncExpr *expr); static unsigned hashPort(const LibertyPort *port); @@ -221,16 +239,61 @@ static unsigned hashCellSequentials(const LibertyCell *cell) { unsigned hash = 0; - for (Sequential *seq : cell->sequentials()) { - hash += hashFuncExpr(seq->clock()) * 3; - hash += hashFuncExpr(seq->data()) * 5; - hash += hashPort(seq->output()) * 7; - hash += hashPort(seq->outputInv()) * 9; - hash += hashFuncExpr(seq->clear()) * 11; - hash += hashFuncExpr(seq->preset()) * 13; - hash += int(seq->clearPresetOutput()) * 17; - hash += int(seq->clearPresetOutputInv()) * 19; - } + for (const Sequential *seq : cell->sequentials()) + hash += hashSequential(seq); + const Statetable *statetable = cell->statetable(); + if (statetable) + hash += hashStatetable(statetable); + return hash; +} + +static unsigned +hashSequential(const Sequential *seq) +{ + unsigned hash = 0; + hash += seq->isRegister() * 3; + hash += hashFuncExpr(seq->clock()) * 5; + hash += hashFuncExpr(seq->data()) * 7; + hash += hashPort(seq->output()) * 9; + hash += hashPort(seq->outputInv()) * 11; + hash += hashFuncExpr(seq->clear()) * 13; + hash += hashFuncExpr(seq->preset()) * 17; + hash += int(seq->clearPresetOutput()) * 19; + hash += int(seq->clearPresetOutputInv()) * 23; + return hash; +} + +static unsigned +hashStatetable(const Statetable *statetable) +{ + unsigned hash = 0; + unsigned hash_ports = 0; + for (LibertyPort *input_port : statetable->inputPorts()) + hash_ports += hashPort(input_port); + hash += hash_ports * 3; + + hash_ports = 0; + for (LibertyPort *internal_port : statetable->internalPorts()) + hash_ports += hashPort(internal_port); + hash += hash_ports * 5; + + unsigned hash_rows = 0; + for (const StatetableRow &row : statetable->table()) + hash_rows += hashStatetableRow(row); + hash += hash_rows * 7; + return hash; +} + +static unsigned +hashStatetableRow(const StatetableRow &row) +{ + unsigned hash = 0; + for (StateInputValue input_value : row.inputValues()) + hash += static_cast(input_value) * 9; + for (StateInternalValue current_value : row.currentValues()) + hash += static_cast(current_value) * 11; + for (StateInternalValue next_value : row.nextValues()) + hash += static_cast(next_value) * 13; return hash; } @@ -261,6 +324,7 @@ equivCells(const LibertyCell *cell1, return equivCellPortsAndFuncs(cell1, cell2) && equivCellPgPorts(cell1, cell2) && equivCellSequentials(cell1, cell2) + && equivCellStatetables(cell1, cell2) && equivCellTimingArcSets(cell1, cell2); } @@ -349,6 +413,102 @@ equivCellSequentials(const LibertyCell *cell1, return seq_itr1 == seqs1.end() && seq_itr2 == seqs2.end(); } +bool +equivCellStatetables(const LibertyCell *cell1, + const LibertyCell *cell2) + +{ + const Statetable *statetable1 = cell1->statetable(); + const Statetable *statetable2 = cell2->statetable(); + return (statetable1 == nullptr && statetable2 == nullptr) + || (statetable1 && statetable2 + && equivCellPortSeq(statetable1->inputPorts(), statetable2->inputPorts()) + && equivCellPortSeq(statetable1->internalPorts(), statetable2->internalPorts()) + && equivStatetableRows(statetable1->table(), statetable2->table())); +} + +static bool +equivCellPortSeq(const LibertyPortSeq &ports1, + const LibertyPortSeq &ports2) +{ + if (ports1.size() != ports2.size()) + return false; + + auto port_itr1 = ports1.begin(); + auto port_itr2 = ports2.begin(); + for (; + port_itr1 != ports1.end() && port_itr2 != ports2.end(); + port_itr1++, port_itr2++) { + const LibertyPort *port1 = *port_itr1; + const LibertyPort *port2 = *port_itr2; + if (!LibertyPort::equiv(port1, port2)) + return false; + } + return true; +} + +static bool +equivStatetableRows(const StatetableRows &table1, + const StatetableRows &table2) +{ + if (table1.size() != table2.size()) + return false; + + auto row_itr1 = table1.begin(); + auto row_itr2 = table2.begin(); + for (; + row_itr1 != table1.end() && row_itr2 != table2.end(); + row_itr1++, row_itr2++) { + const StatetableRow &row1 = *row_itr1; + const StatetableRow &row2 = *row_itr2; + if (!equivStatetableRow(row1, row2)) + return false; + } + return true; +} + +static bool +equivStatetableRow(const StatetableRow &row1, + const StatetableRow &row2) +{ + const StateInputValues &input_values1 = row1.inputValues(); + const StateInputValues &input_values2 = row2.inputValues(); + if (input_values1.size() != input_values2.size()) + return false; + for (auto input_itr1 = input_values1.begin(), + input_itr2 = input_values2.begin(); + input_itr1 != input_values1.end() && input_itr2 != input_values2.end(); + input_itr1++, input_itr2++) { + if (*input_itr1 != *input_itr2) + return false; + } + + const StateInternalValues ¤t_values1 = row1.currentValues(); + const StateInternalValues ¤t_values2 = row2.currentValues(); + if (current_values1.size() != current_values2.size()) + return false; + for (auto current_itr1 = current_values1.begin(), + current_itr2 = current_values2.begin(); + current_itr1 != current_values1.end() && current_itr2 != current_values2.end(); + current_itr1++, current_itr2++) { + if (*current_itr1 != *current_itr2) + return false; + } + + const StateInternalValues &next_values1 = row1.nextValues(); + const StateInternalValues &next_values2 = row2.nextValues(); + if (next_values1.size() != next_values2.size()) + return false; + for (auto next_itr1 = next_values1.begin(), + next_itr2 = next_values2.begin(); + next_itr1 != next_values1.end() && next_itr2 != next_values2.end(); + next_itr1++, next_itr2++) { + if (*next_itr1 != *next_itr2) + return false; + } + return true; +} + bool equivCellTimingArcSets(const LibertyCell *cell1, const LibertyCell *cell2) diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index 96b24213..96b2a33d 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -930,6 +930,7 @@ LibertyCell::LibertyCell(LibertyLibrary *library, interface_timing_(false), clock_gate_type_(ClockGateType::none), has_infered_reg_timing_arcs_(false), + statetable_(nullptr), scale_factors_(nullptr), test_cell_(nullptr), ocv_arc_depth_(0.0), @@ -958,6 +959,7 @@ LibertyCell::~LibertyCell() leakage_powers_.deleteContents(); sequentials_.deleteContents(); + delete statetable_; bus_dcls_.deleteContents(); scaled_cells_.deleteContents(); @@ -1511,7 +1513,16 @@ LibertyCell::outputPortSequential(LibertyPort *port) bool LibertyCell::hasSequentials() const { - return !sequentials_.empty(); + return !sequentials_.empty() + || statetable_ != nullptr; +} + +void +LibertyCell::makeStatetable(LibertyPortSeq &input_ports, + LibertyPortSeq &internal_ports, + StatetableRows &table) +{ + statetable_ = new Statetable(input_ports, internal_ports, table); } void diff --git a/liberty/LibertyReader.cc b/liberty/LibertyReader.cc index 5f499842..d8064180 100644 --- a/liberty/LibertyReader.cc +++ b/liberty/LibertyReader.cc @@ -19,6 +19,7 @@ #include #include +#include "EnumNameMap.hh" #include "Report.hh" #include "Debug.hh" #include "TokenParser.hh" @@ -45,6 +46,7 @@ extern int LibertyParse_debug; namespace sta { using std::make_shared; +using std::string; static void scaleFloats(FloatSeq *floats, @@ -121,6 +123,7 @@ LibertyReader::readLibertyFile(const char *filename, in_bus_ = false; in_bundle_ = false; sequential_ = nullptr; + statetable_ = nullptr; timing_ = nullptr; internal_power_ = nullptr; leakage_power_ = nullptr; @@ -375,6 +378,11 @@ LibertyReader::defineVisitors() defineAttrVisitor("clear_preset_var1", &LibertyReader::visitClrPresetVar1); defineAttrVisitor("clear_preset_var2", &LibertyReader::visitClrPresetVar2); + // Statetable + defineGroupVisitor("statetable", &LibertyReader::beginStatetable, + &LibertyReader::endStatetable); + defineAttrVisitor("table", &LibertyReader::visitTable); + defineGroupVisitor("timing", &LibertyReader::beginTiming, &LibertyReader::endTiming); defineAttrVisitor("related_pin", &LibertyReader::visitRelatedPin); @@ -1904,6 +1912,7 @@ LibertyReader::endCell(LibertyGroup *group) // Sequentials and leakage powers reference expressions outside of port definitions // so they do not require LibertyFunc's. makeCellSequentials(); + makeStatetable(); // Parse functions defined inside of port groups that reference other ports // and replace the references with the parsed expressions. parseCellFuncs(); @@ -2126,6 +2135,37 @@ LibertyReader::checkLatchEnableSense(FuncExpr *enable_func, } } +//////////////////////////////////////////////////////////////// + +void +LibertyReader::makeStatetable() +{ + if (statetable_) { + LibertyPortSeq input_ports; + for (const string &input : statetable_->inputPorts()) { + LibertyPort *port = cell_->findLibertyPort(input.c_str()); + if (port) + input_ports.push_back(port); + else + libWarn(0000, statetable_->line(), "statetable input port %s not found.", + input.c_str()); + } + LibertyPortSeq internal_ports; + for (const string &internal : statetable_->internalPorts()) { + LibertyPort *port = cell_->findLibertyPort(internal.c_str()); + if (port) + internal_ports.push_back(port); + else + libWarn(0000, statetable_->line(), "statetable internal port %s not found.", + internal.c_str()); + } + cell_->makeStatetable(input_ports, internal_ports, statetable_->table()); + statetable_ = nullptr; + } +} + +//////////////////////////////////////////////////////////////// + void LibertyReader::makeLeakagePowers() { @@ -3928,6 +3968,134 @@ LibertyReader::visitClrPresetVar2(LibertyAttr *attr) //////////////////////////////////////////////////////////////// +void +LibertyReader::beginStatetable(LibertyGroup *group) +{ + if (cell_) { + const char *input_ports_arg = group->firstName(); + StdStringSeq input_ports; + if (input_ports_arg) + input_ports = parseTokenList(input_ports_arg, ' '); + + const char *internal_ports_arg = group->secondName(); + StdStringSeq internal_ports; + if (internal_ports_arg) + internal_ports = parseTokenList(internal_ports_arg, ' '); + statetable_ = new StatetableGroup(input_ports, internal_ports, group->line()); + } +} + +void +LibertyReader::visitTable(LibertyAttr *attr) +{ + if (statetable_) { + const char *table_str = getAttrString(attr); + StdStringSeq table_rows = parseTokenList(table_str, ','); + size_t input_count = statetable_->inputPorts().size(); + size_t internal_count = statetable_->internalPorts().size(); + for (string row : table_rows) { + StdStringSeq row_groups = parseTokenList(row.c_str(), ':'); + if (row_groups.size() != 3) { + libWarn(0000, attr, "table row must have 3 groups separated by ':'."); + break; + } + StdStringSeq inputs = parseTokenList(row_groups[0].c_str(), ' '); + if (inputs.size() != input_count) { + libWarn(0000, attr, "table row has %zu input values but %zu are required.", + inputs.size(), + input_count); + break; + } + StdStringSeq currents = parseTokenList(row_groups[1].c_str(), ' '); + if (currents.size() != internal_count) { + libWarn(0000, attr, "table row has %zu current values but %zu are required.", + currents.size(), + internal_count); + break; + } + StdStringSeq nexts = parseTokenList(row_groups[2].c_str(), ' '); + if (nexts.size() != internal_count) { + libWarn(0000, attr, "table row has %zu next values but %zu are required.", + nexts.size(), + internal_count); + break; + } + + StateInputValues input_values = parseStateInputValues(inputs, attr); + StateInternalValues current_values=parseStateInternalValues(currents,attr); + StateInternalValues next_values = parseStateInternalValues(nexts, attr); + statetable_->addRow(input_values, current_values, next_values); + } + } +} + +static EnumNameMap state_input_value_name_map = + {{StateInputValue::low, "L"}, + {StateInputValue::high, "H"}, + {StateInputValue::dont_care, "-"}, + {StateInputValue::low_high, "L/H"}, + {StateInputValue::high_low, "H/L"}, + {StateInputValue::rise, "R"}, + {StateInputValue::fall, "F"}, + {StateInputValue::not_rise, "~R"}, + {StateInputValue::not_fall, "~F"} + }; + +static EnumNameMap state_internal_value_name_map = + {{StateInternalValue::low, "L"}, + {StateInternalValue::high, "H"}, + {StateInternalValue::unspecified, "-"}, + {StateInternalValue::low_high, "L/H"}, + {StateInternalValue::high_low, "H/L"}, + {StateInternalValue::unknown, "X"}, + {StateInternalValue::hold, "N"} + }; + +StateInputValues +LibertyReader::parseStateInputValues(StdStringSeq &inputs, + LibertyAttr *attr) +{ + StateInputValues input_values; + for (string input : inputs) { + bool exists; + StateInputValue value; + state_input_value_name_map.find(input.c_str(), value, exists); + if (!exists) { + libWarn(0000, attr, "table input value '%s' not recognized.", + input.c_str()); + value = StateInputValue::dont_care; + } + input_values.push_back(value); + } + return input_values; +} + +StateInternalValues +LibertyReader::parseStateInternalValues(StdStringSeq &states, + LibertyAttr *attr) +{ + StateInternalValues state_values; + for (string state : states) { + bool exists; + StateInternalValue value; + state_internal_value_name_map.find(state.c_str(), value, exists); + if (!exists) { + libWarn(0000, attr, "table internal value '%s' not recognized.", + state.c_str()); + value = StateInternalValue::unknown; + } + state_values.push_back(value); + } + return state_values; +} + +void +LibertyReader::endStatetable(LibertyGroup *) +{ +} + +//////////////////////////////////////////////////////////////// + void LibertyReader::beginTiming(LibertyGroup *group) { @@ -3996,6 +4164,24 @@ LibertyReader::parseNameList(const char *name_list) return names; } +StdStringSeq +LibertyReader::parseTokenList(const char *token_str, + const char separator) +{ + StdStringSeq tokens; + // Parse space separated list of names. + char separators[2] = {separator, '\0'}; + TokenParser parser(token_str, separators); + while (parser.hasNext()) { + char *token = parser.next(); + // Skip extra spaces. + if (token[0] != '\0') { + tokens.push_back(token); + } + } + return tokens; +} + void LibertyReader::visitRelatedBusPins(LibertyAttr *attr) { @@ -5471,6 +5657,25 @@ SequentialGroup::setClrPresetVar2(LogicValue var) //////////////////////////////////////////////////////////////// +StatetableGroup::StatetableGroup(StdStringSeq &input_ports, + StdStringSeq &internal_ports, + int line) : + input_ports_(input_ports), + internal_ports_(internal_ports), + line_(line) +{ +} + +void +StatetableGroup::addRow(StateInputValues &input_values, + StateInternalValues ¤t_values, + StateInternalValues &next_values) +{ + table_.emplace_back(input_values, current_values, next_values); +} + +//////////////////////////////////////////////////////////////// + RelatedPortGroup::RelatedPortGroup(int line) : related_port_names_(nullptr), line_(line) diff --git a/liberty/LibertyReaderPvt.hh b/liberty/LibertyReaderPvt.hh index 5fc608a6..9a812f3c 100644 --- a/liberty/LibertyReaderPvt.hh +++ b/liberty/LibertyReaderPvt.hh @@ -17,6 +17,7 @@ #pragma once #include +#include #include "Vector.hh" #include "Map.hh" @@ -27,6 +28,7 @@ #include "InternalPower.hh" #include "LeakagePower.hh" #include "Liberty.hh" +#include "Sequential.hh" #include "LibertyParser.hh" #include "LibertyReader.hh" #include "NetworkClass.hh" @@ -38,6 +40,7 @@ class LibertyReader; class LibertyFunc; class PortGroup; class SequentialGroup; +class StatetableGroup; class RelatedPortGroup; class TimingGroup; class InternalPowerGroup; @@ -47,6 +50,8 @@ class TimingArcBuilder; class LibertyAttr; class OutputWaveform; +using std::vector; + typedef void (LibertyReader::*LibraryAttrVisitor)(LibertyAttr *attr); typedef void (LibertyReader::*LibraryGroupVisitor)(LibertyGroup *group); typedef Map LibraryAttrMap; @@ -59,6 +64,7 @@ typedef Vector InternalPowerGroupSeq; typedef Vector LeakagePowerGroupSeq; typedef void (LibertyPort::*LibertyPortBoolSetter)(bool value); typedef Vector OutputWaveformSeq; +typedef vector StdStringSeq; class LibertyReader : public LibertyGroupVisitor { @@ -164,6 +170,7 @@ public: virtual void makeInternalPowers(PortGroup *port_group); virtual void makeCellSequentials(); virtual void makeCellSequential(SequentialGroup *seq); + virtual void makeStatetable(); virtual void makeLeakagePowers(); virtual void parseCellFuncs(); virtual void makeLibertyFunc(const char *expr, @@ -302,6 +309,10 @@ public: virtual void visitClrPresetVar1(LibertyAttr *attr); virtual void visitClrPresetVar2(LibertyAttr *attr); + virtual void beginStatetable(LibertyGroup *group); + virtual void endStatetable(LibertyGroup *group); + virtual void visitTable(LibertyAttr *attr); + virtual void beginTiming(LibertyGroup *group); virtual void endTiming(LibertyGroup *group); virtual void visitRelatedPin(LibertyAttr *attr); @@ -502,12 +513,19 @@ protected: void makeTableAxis(int index); StringSeq *parseNameList(const char *name_list); + StdStringSeq parseTokenList(const char *token_str, + const char separator); LibertyPort *findPort(const char *port_name); LibertyPort *findPort(LibertyCell *cell, const char *port_name); float defaultCap(LibertyPort *port); virtual void visitVariable(LibertyVariable *var); void visitPorts(std::function func); + StateInputValues parseStateInputValues(StdStringSeq &inputs, + LibertyAttr *attr); + StateInternalValues parseStateInternalValues(StdStringSeq &states, + LibertyAttr *attr); + const char *getAttrString(LibertyAttr *attr); void getAttrInt(LibertyAttr *attr, // Return values. @@ -610,6 +628,7 @@ protected: bool type_bit_to_exists_; SequentialGroup *sequential_; SequentialGroupSeq cell_sequentials_; + StatetableGroup *statetable_; TimingGroup *timing_; InternalPowerGroup *internal_power_; LeakagePowerGroup *leakage_power_; @@ -703,6 +722,24 @@ private: int line_; }; +// Liberty group with related_pins group attribute. +class RelatedPortGroup +{ +public: + explicit RelatedPortGroup(int line); + virtual ~RelatedPortGroup(); + int line() const { return line_; } + StringSeq *relatedPortNames() const { return related_port_names_; } + void setRelatedPortNames(StringSeq *names); + bool isOneToOne() const { return is_one_to_one_; } + void setIsOneToOne(bool one); + +protected: + StringSeq *related_port_names_; + bool is_one_to_one_; + int line_; +}; + class SequentialGroup { public: @@ -747,21 +784,24 @@ protected: int line_; }; -// Liberty group with related_pins group attribute. -class RelatedPortGroup +class StatetableGroup { public: - explicit RelatedPortGroup(int line); - virtual ~RelatedPortGroup(); + StatetableGroup(StdStringSeq &input_ports, + StdStringSeq &internal_ports, + int line); + const StdStringSeq &inputPorts() const { return input_ports_; } + const StdStringSeq &internalPorts() const { return internal_ports_; } + void addRow(StateInputValues &input_values, + StateInternalValues ¤t_values, + StateInternalValues &next_values); + StatetableRows &table() { return table_; } int line() const { return line_; } - StringSeq *relatedPortNames() const { return related_port_names_; } - void setRelatedPortNames(StringSeq *names); - bool isOneToOne() const { return is_one_to_one_; } - void setIsOneToOne(bool one); -protected: - StringSeq *related_port_names_; - bool is_one_to_one_; +private: + StdStringSeq input_ports_; + StdStringSeq internal_ports_; + StatetableRows table_; int line_; }; diff --git a/liberty/Sequential.cc b/liberty/Sequential.cc index 3348789f..970798de 100644 --- a/liberty/Sequential.cc +++ b/liberty/Sequential.cc @@ -53,4 +53,24 @@ Sequential::~Sequential() preset_->deleteSubexprs(); } +//////////////////////////////////////////////////////////////// + +Statetable::Statetable(LibertyPortSeq &input_ports, + LibertyPortSeq &internal_ports, + StatetableRows &table) : + input_ports_(input_ports), + internal_ports_(internal_ports), + table_(table) +{ +} + +StatetableRow::StatetableRow(StateInputValues &input_values, + StateInternalValues ¤t_values, + StateInternalValues &next_values) : + input_values_(input_values), + current_values_(current_values), + next_values_(next_values) +{ +} + } // namespace diff --git a/power/Power.cc b/power/Power.cc index 93f4cd59..7cb6628c 100644 --- a/power/Power.cc +++ b/power/Power.cc @@ -244,10 +244,10 @@ Power::power(const Corner *corner, macro.incr(inst_power); else if (cell->isPad()) pad.incr(inst_power); - else if (cell->hasSequentials()) - sequential.incr(inst_power); else if (inClockNetwork(inst)) clock.incr(inst_power); + else if (cell->hasSequentials()) + sequential.incr(inst_power); else combinational.incr(inst_power); total.incr(inst_power); diff --git a/sdc/Sdc.cc b/sdc/Sdc.cc index 7925f048..ee14c6c1 100644 --- a/sdc/Sdc.cc +++ b/sdc/Sdc.cc @@ -4371,7 +4371,8 @@ Sdc::findMatchingExceptionsFirstThru(ExceptionPath *exception, findMatchingExceptionsInsts(exception, thru->instances(), first_thru_inst_exceptions_, matches); - if (!first_thru_net_exceptions_.empty()) { + if (!first_thru_net_exceptions_.empty() + && thru->nets()) { for (const Net *net : *thru->nets()) { // Potential matches includes exceptions that match net that are not // the first exception point. diff --git a/search/Bfs.cc b/search/Bfs.cc index f5d8a429..cdb6d3a7 100644 --- a/search/Bfs.cc +++ b/search/Bfs.cc @@ -308,7 +308,7 @@ BfsIterator::remove(Vertex *vertex) Level level = vertex->level(); if (vertex->bfsInQueue(bfs_index_) && static_cast(queue_.size()) > level) { - for (Vertex *v : queue_[level]) { + for (Vertex *&v : queue_[level]) { if (v == vertex) { v = nullptr; vertex->setBfsInQueue(bfs_index_, false); diff --git a/search/PathEnd.cc b/search/PathEnd.cc index 9f8503d2..a60b1f45 100644 --- a/search/PathEnd.cc +++ b/search/PathEnd.cc @@ -1070,7 +1070,7 @@ PathEndLatchCheck::PathEndLatchCheck(Path *path, clk_path_ = enable_path; Search *search = sta->search(); // Same as PathEndPathDelay::findRequired. - if (path_delay_ && path_delay_->ignoreClkLatency()) + if (path_delay_ && ignoreClkLatency(sta)) src_clk_arrival_ = search->pathClkPathArrival(&path_); } @@ -1081,7 +1081,7 @@ PathEndLatchCheck::PathEndLatchCheck(Path *path, PathVertex *disable_path, MultiCyclePath *mcp, PathDelay *path_delay, - Delay src_clk_arrival, + Delay src_clk_arrival, Crpr crpr, bool crpr_valid) : PathEndCheck(path, check_arc, check_edge, clk_path, mcp, crpr, crpr_valid), @@ -1221,7 +1221,7 @@ PathEndLatchCheck::latchBorrowInfo(const StaState *sta, Latches *latches = sta->latches(); latches->latchBorrowInfo(path_.path(), targetClkPath(), latchDisable(), margin(sta), - path_delay_ && path_delay_->ignoreClkLatency(), + path_delay_ && ignoreClkLatency(sta), nom_pulse_width, open_latency, latency_diff, open_uncertainty, open_crpr, crpr_diff, max_borrow, @@ -1269,6 +1269,12 @@ PathEndLatchCheck::exceptPathCmp(const PathEnd *path_end, return cmp; } +bool +PathEndLatchCheck::ignoreClkLatency(const StaState *sta) const +{ + return PathEnd::ignoreClkLatency(path_, path_delay_, sta); +} + /////////////////////////////////////////////////////////////// PathEndOutputDelay::PathEndOutputDelay(OutputDelay *output_delay, @@ -1802,7 +1808,7 @@ PathEndPathDelay::typeName() const void PathEndPathDelay::findSrcClkArrival(const StaState *sta) { - if (path_delay_->ignoreClkLatency()) { + if (ignoreClkLatency(sta)) { Search *search = sta->search(); src_clk_arrival_ = search->pathClkPathArrival(&path_); } @@ -1873,7 +1879,7 @@ PathEnd::pathDelaySrcClkOffset(const PathRef &path, float offset = 0.0; const ClockEdge *clk_edge = path.clkEdge(sta); if (clk_edge) { - if (path_delay->ignoreClkLatency()) + if (ignoreClkLatency(path, path_delay, sta)) offset = -delayAsFloat(src_clk_arrival); else // Arrival includes src clock edge time that is not counted in the @@ -1883,6 +1889,14 @@ PathEnd::pathDelaySrcClkOffset(const PathRef &path, return offset; } +bool +PathEnd::ignoreClkLatency(const PathRef &path, + PathDelay *path_delay, + const StaState *sta) +{ + return path_delay->ignoreClkLatency() && !path.isClock(sta); +} + const ClockEdge * PathEndPathDelay::targetClkEdge(const StaState *sta) const { @@ -1927,7 +1941,7 @@ Required PathEndPathDelay::requiredTime(const StaState *sta) const { float delay = path_delay_->delay(); - if (path_delay_->ignoreClkLatency()) { + if (ignoreClkLatency(sta)) { if (minMax(sta) == MinMax::max()) return src_clk_arrival_ + delay - margin(sta); else @@ -1943,6 +1957,12 @@ PathEndPathDelay::requiredTime(const StaState *sta) const } } +bool +PathEndPathDelay::ignoreClkLatency(const StaState *sta) const +{ + return PathEnd::ignoreClkLatency(path_, path_delay_, sta); +} + int PathEndPathDelay::exceptPathCmp(const PathEnd *path_end, const StaState *sta) const diff --git a/search/ReportPath.cc b/search/ReportPath.cc index 662a1dba..f19f2e9e 100644 --- a/search/ReportPath.cc +++ b/search/ReportPath.cc @@ -686,7 +686,7 @@ ReportPath::reportFull(const PathEndPathDelay *end) // Based on reportSrcPathArrival. reportBlankLine(); PathDelay *path_delay = end->pathDelay(); - if (path_delay->ignoreClkLatency()) { + if (end->ignoreClkLatency(this)) { // Based on reportSrcPath. reportPathHeader(); reportPath3(end->path(), expanded, false, false, 0.0, diff --git a/search/Search.cc b/search/Search.cc index f8c0d0c1..86d68724 100644 --- a/search/Search.cc +++ b/search/Search.cc @@ -452,11 +452,11 @@ Search::findPathEnds(ExceptionFrom *from, recovery = removal = false; if (!sdc_->gatedClkChecksEnabled()) clk_gating_setup = clk_gating_hold = false; - updatePathGroups(group_count, endpoint_count, unique_pins, - slack_min, slack_max, - group_names, setup, hold, - recovery, removal, - clk_gating_setup, clk_gating_hold); + makePathGroups(group_count, endpoint_count, unique_pins, + slack_min, slack_max, + group_names, setup, hold, + recovery, removal, + clk_gating_setup, clk_gating_hold); ensureDownstreamClkPins(); PathEndSeq path_ends = path_groups_->makePathEnds(to, unconstrained_paths_, corner, min_max, @@ -3973,7 +3973,7 @@ Search::wnsSlack(Vertex *vertex, //////////////////////////////////////////////////////////////// -PathGroups * +void Search::makePathGroups(int group_count, int endpoint_count, bool unique_pins, @@ -3987,14 +3987,14 @@ Search::makePathGroups(int group_count, bool clk_gating_setup, bool clk_gating_hold) { - return new PathGroups(group_count, endpoint_count, unique_pins, - slack_min, slack_max, - group_names, - setup, hold, - recovery, removal, - clk_gating_setup, clk_gating_hold, - unconstrained_paths_, - this); + path_groups_ = new PathGroups(group_count, endpoint_count, unique_pins, + slack_min, slack_max, + group_names, + setup, hold, + recovery, removal, + clk_gating_setup, clk_gating_hold, + unconstrained_paths_, + this); } void @@ -4004,27 +4004,6 @@ Search::deletePathGroups() path_groups_ = nullptr; } -void -Search::updatePathGroups(int group_count, - int endpoint_count, - bool unique_pins, - float min_slack, - float max_slack, - PathGroupNameSet *group_names, - bool setup, - bool hold, - bool recovery, - bool removal, - bool clk_gating_setup, - bool clk_gating_hold) -{ - path_groups_ = makePathGroups(group_count, endpoint_count, unique_pins, - min_slack, max_slack, - group_names, setup, hold, - recovery, removal, - clk_gating_setup, clk_gating_hold); -} - PathGroup * Search::pathGroup(const PathEnd *path_end) const { diff --git a/tcl/StaTclTypes.i b/tcl/StaTclTypes.i index 08c30144..8a060807 100644 --- a/tcl/StaTclTypes.i +++ b/tcl/StaTclTypes.i @@ -40,6 +40,7 @@ #include "SearchClass.hh" #include "CircuitSim.hh" #include "ArcDelayCalc.hh" +#include "Property.hh" #include "Sta.hh" namespace sta {