diff --git a/src/database/manager/parser/liberty/Lib.cc b/src/database/manager/parser/liberty/Lib.cc index 807c2de35..b3d00ef7a 100644 --- a/src/database/manager/parser/liberty/Lib.cc +++ b/src/database/manager/parser/liberty/Lib.cc @@ -895,6 +895,23 @@ LibPort& LibPort::operator=(LibPort&& rhs) noexcept return *this; } +void LibPort::inheritBusAttributes(const LibPort& bus) +{ + _port_type = bus._port_type; + _is_clock_pin = bus._is_clock_pin; + _clock_gate_clock_pin = bus._clock_gate_clock_pin; + _clock_gate_enable_pin = bus._clock_gate_enable_pin; + _is_clock = bus._is_clock; + _func_expr = bus._func_expr; + _func_expr_str = bus._func_expr_str; + _port_cap = bus._port_cap; + _port_caps = bus._port_caps; + _cap_limits = bus._cap_limits; + _slew_limits = bus._slew_limits; + _fanout_load = bus._fanout_load; + _max_fanout = bus._max_fanout; +} + /** * @brief Set cap of max/min, rise/fall. * @@ -1067,6 +1084,17 @@ LibPortBus::LibPortBus(const char* port_bus_name) : LibPort(port_bus_name) { } +LibPort* LibPortBus::operator[](int index) +{ + std::string port_name = std::string(get_port_name()) + "[" + std::to_string(index) + "]"; + for (std::unique_ptr& port : _ports) { + if (port_name == port->get_port_name()) { + return port.get(); + } + } + return nullptr; +} + LibLeakagePower::LibLeakagePower() : _owner_cell(nullptr) { } diff --git a/src/database/manager/parser/liberty/Lib.hh b/src/database/manager/parser/liberty/Lib.hh index e5bc5384d..24d7ee57c 100644 --- a/src/database/manager/parser/liberty/Lib.hh +++ b/src/database/manager/parser/liberty/Lib.hh @@ -552,6 +552,8 @@ class LibPort : public LibObject LibPort(LibPort&& other) noexcept; LibPort& operator=(LibPort&& rhs) noexcept; + void inheritBusAttributes(const LibPort& bus); + const char* get_port_name() { return _port_name.c_str(); } void set_ower_cell(LibCell* ower_cell) { _ower_cell = ower_cell; } LibCell* get_ower_cell() { return _ower_cell; } @@ -715,11 +717,12 @@ class LibPortBus : public LibPort void addlibertyPort(std::unique_ptr&& port) { _ports.push_back(std::move(port)); } auto getBusSize() { return _bus_type ? _bus_type->get_bit_width() : _ports.size(); } + auto& get_ports() { return _ports; } void set_bus_type(LibType* bus_type) { _bus_type = bus_type; } auto* get_bus_type() { return _bus_type; } - LibPort* operator[](int index) { return _ports.empty() ? this : _ports[index].get(); } + LibPort* operator[](int index); private: absl::InlinedVector, 64> _ports; //!< The bus ports. diff --git a/src/database/manager/parser/liberty/LibParserCpp.cc b/src/database/manager/parser/liberty/LibParserCpp.cc index 035f2323f..3cf674cf0 100644 --- a/src/database/manager/parser/liberty/LibParserCpp.cc +++ b/src/database/manager/parser/liberty/LibParserCpp.cc @@ -1238,6 +1238,8 @@ unsigned LibertyReader::visitLeakagePower(LibertyGroupStmt* group) { unsigned LibertyReader::visitBus(LibertyGroupStmt* group) { LibBuilder* lib_builder = get_library_builder(); LibCell* cell = lib_builder->get_cell(); + LibPort* previous_port = lib_builder->get_port(); + LibPortBus* previous_bus = lib_builder->get_port_bus(); const char* bus_port_name = getGroupAttriName(group); auto lib_port_bus = std::make_unique(bus_port_name); @@ -1249,7 +1251,8 @@ unsigned LibertyReader::visitBus(LibertyGroupStmt* group) { unsigned is_ok = visitStmtInGroup(group); // reset the port bus pointer. - lib_builder->set_port_bus(nullptr); + lib_builder->set_port(previous_port); + lib_builder->set_port_bus(previous_bus); return is_ok; } @@ -1261,55 +1264,55 @@ unsigned LibertyReader::visitBus(LibertyGroupStmt* group) { * @return unsigned return 1 if success, else 0 */ unsigned LibertyReader::visitPin(LibertyGroupStmt* group) { + return visitPinGroup(group); +} + +template +unsigned LibertyReader::visitPinGroup(Group* group) +{ LibBuilder* lib_builder = get_library_builder(); LibCell* cell = lib_builder->get_cell(); - + LibPortBus* port_bus = lib_builder->get_port_bus(); + LibPort* previous_port = lib_builder->get_port(); const char* port_name = getGroupAttriName(group); + unsigned is_ok = 1; - auto create_port = [lib_builder, cell](const char* port_name) { - auto lib_port = std::make_unique(port_name); + auto create_port = [&](const char* name) { + std::unique_ptr lib_port = std::make_unique(name); lib_port->set_ower_cell(cell); - - if (auto* port_bus = lib_builder->get_port_bus(); !port_bus) { - lib_builder->set_port(lib_port.get()); - cell->addLibertyPort(std::move(lib_port)); - } else { - lib_port->set_port_type(port_bus->get_port_type()); - port_bus->addlibertyPort(std::move(lib_port)); + if (port_bus) { + lib_port->inheritBusAttributes(*port_bus); } - }; - - auto has_bus_range_marker = [](const char* port_name) { - for (const char* ch = port_name; *ch != '\0'; ++ch) { - if (*ch == '[') { - return true; - } + lib_builder->set_port(lib_port.get()); + if (port_bus) { + port_bus->addlibertyPort(std::move(lib_port)); + } else { + cell->addLibertyPort(std::move(lib_port)); } - return false; + // Every bit owns its attributes and tables, including conditional arcs. + is_ok &= visitStmtInGroup(group); }; - std::vector ret_val; - if (has_bus_range_marker(port_name)) { - std::string regex_pattern = "([A-Za-z]+)\\[(\\d+):(\\d+)\\]"; - ret_val = matchPattern(port_name, regex_pattern); + std::vector range; + if (std::string_view(port_name).find('[') != std::string_view::npos) { + range = matchPattern(port_name, "(.+)\\[(-?\\d+):(-?\\d+)\\]"); } - if (ret_val.empty()) { + if (range.empty()) { create_port(port_name); } else { - std::string port_bus_name = ret_val[1]; - int port_range_left = std::atoi(ret_val[2].c_str()); - int port_range_right = std::atoi(ret_val[3].c_str()); - - for (int index = port_range_left; index >= port_range_right; --index) { - std::string one_port_name = makeIndexedName(port_bus_name, index); - create_port(one_port_name.c_str()); + int left = std::stoi(range[2]); + int right = std::stoi(range[3]); + int step = left <= right ? 1 : -1; + for (int index = left;; index += step) { + std::string name = makeIndexedName(range[1], index); + create_port(name.c_str()); + if (index == right) { + break; + } } } - unsigned is_ok = visitStmtInGroup(group); - // reset the port pointer. - lib_builder->set_port(nullptr); - + lib_builder->set_port(previous_port); return is_ok; } @@ -1802,6 +1805,8 @@ unsigned LibertyReader::visitLeakagePower(liberty_ast::LibGroup* group) { unsigned LibertyReader::visitBus(liberty_ast::LibGroup* group) { LibBuilder* lib_builder = get_library_builder(); LibCell* cell = lib_builder->get_cell(); + LibPort* previous_port = lib_builder->get_port(); + LibPortBus* previous_bus = lib_builder->get_port_bus(); const char* port_bus_name = getGroupAttriName(group); @@ -1814,62 +1819,14 @@ unsigned LibertyReader::visitBus(liberty_ast::LibGroup* group) { unsigned is_ok = visitStmtInGroup(group); // reset the port bus pointer. - lib_builder->set_port_bus(nullptr); + lib_builder->set_port(previous_port); + lib_builder->set_port_bus(previous_bus); return is_ok; } unsigned LibertyReader::visitPin(liberty_ast::LibGroup* group) { - LibBuilder* lib_builder = get_library_builder(); - LibCell* cell = lib_builder->get_cell(); - - const char* port_name = getGroupAttriName(group); - - auto create_port = [lib_builder, cell](const char* port_name) { - auto lib_port = std::make_unique(port_name); - lib_port->set_ower_cell(cell); - - if (auto* port_bus = lib_builder->get_port_bus(); !port_bus) { - lib_builder->set_port(lib_port.get()); - cell->addLibertyPort(std::move(lib_port)); - } else { - lib_port->set_port_type(port_bus->get_port_type()); - port_bus->addlibertyPort(std::move(lib_port)); - } - }; - - auto has_bus_range_marker = [](const char* port_name) { - for (const char* ch = port_name; *ch != '\0'; ++ch) { - if (*ch == '[') { - return true; - } - } - return false; - }; - - std::vector ret_val; - if (has_bus_range_marker(port_name)) { - std::string regex_pattern = "([A-Za-z]+)\\[(\\d+):(\\d+)\\]"; - ret_val = matchPattern(port_name, regex_pattern); - } - if (ret_val.empty()) { - create_port(port_name); - } else { - std::string port_bus_name = ret_val[1]; - int port_range_left = std::atoi(ret_val[2].c_str()); - int port_range_right = std::atoi(ret_val[3].c_str()); - - for (int index = port_range_left; index >= port_range_right; --index) { - std::string one_port_name = makeIndexedName(port_bus_name, index); - create_port(one_port_name.c_str()); - } - } - - unsigned is_ok = visitStmtInGroup(group); - // reset the port pointer. - lib_builder->set_port(nullptr); - - return is_ok; + return visitPinGroup(group); } unsigned LibertyReader::visitTiming(liberty_ast::LibGroup* group) { diff --git a/src/database/manager/parser/liberty/LibParserCpp.hh b/src/database/manager/parser/liberty/LibParserCpp.hh index cf4481b39..7500fac7f 100644 --- a/src/database/manager/parser/liberty/LibParserCpp.hh +++ b/src/database/manager/parser/liberty/LibParserCpp.hh @@ -447,6 +447,9 @@ class LibertyReader auto* get_library_builder() { return _library_builder; } private: + template + unsigned visitPinGroup(Group* group); + const char* getGroupAttriName(LibertyGroupStmt* group); unsigned visitStmtInGroup(LibertyGroupStmt* group); diff --git a/src/operation/iSTA/interface/STAInterface.cpp b/src/operation/iSTA/interface/STAInterface.cpp index 3d116b3f8..29788acb6 100644 --- a/src/operation/iSTA/interface/STAInterface.cpp +++ b/src/operation/iSTA/interface/STAInterface.cpp @@ -688,6 +688,11 @@ void STAInterface::wrapTimingCell(idb::LibCell* lib_cell) for (std::unique_ptr& lib_port : lib_cell->get_cell_ports()) { wrapTimingCellPort(timing_cell, lib_port.get()); } + for (std::unique_ptr& lib_bus : lib_cell->get_cell_buses()) { + for (std::unique_ptr& lib_port : lib_bus->get_ports()) { + wrapTimingCellPort(timing_cell, lib_port.get()); + } + } wrapTimingCellSequential(timing_cell, lib_cell); wrapTimingCellPower(timing_cell, lib_cell); @@ -764,6 +769,14 @@ void STAInterface::wrapTimingCellPower(TimingCell& timing_cell, idb::LibCell* li timing_cell.get_power_arc_list().push_back(wrapTimingPortPowerArc(internal_power_info.get(), port_name, lib_library)); } } + for (std::unique_ptr& lib_bus : lib_cell->get_cell_buses()) { + for (std::unique_ptr& lib_port : lib_bus->get_ports()) { + std::string port_name = lib_port->get_port_name(); + for (std::unique_ptr& internal_power_info : lib_port->get_internal_powers()) { + timing_cell.get_power_arc_list().push_back(wrapTimingPortPowerArc(internal_power_info.get(), port_name, lib_library)); + } + } + } } void STAInterface::wrapTimingCellLeakagePower(TimingCell& timing_cell, idb::LibCell* lib_cell) diff --git a/src/operation/iSTA/source/module/timing_reporter/TimingReporter.cpp b/src/operation/iSTA/source/module/timing_reporter/TimingReporter.cpp index c62d4f166..ba19a449b 100644 --- a/src/operation/iSTA/source/module/timing_reporter/TimingReporter.cpp +++ b/src/operation/iSTA/source/module/timing_reporter/TimingReporter.cpp @@ -26,6 +26,10 @@ namespace ista { namespace { +constexpr int kTimingFanoutWidth = 8; +constexpr int kTimingValueWidth = 16; +constexpr int kTimingTableExtraWidth = 2 + kTimingFanoutWidth + 2 * kTimingValueWidth + 2; + std::string escapeJsonString(const std::string& value) { static constexpr char kHexDigits[] = "0123456789abcdef"; @@ -221,6 +225,7 @@ void TimingReporter::outputReportHeader(std::ofstream* report_file, DelayType de (*report_file) << "Nworst : " << STADM.getConfig().endpoint_path_report_number << "\n"; (*report_file) << "MaxPaths : " << STADM.getConfig().path_report_number << "\n"; (*report_file) << "SortBy : slack\n"; + (*report_file) << "Fanout : number of unique load pins driven by the point (blank for non-drivers)\n"; (*report_file) << "****************************************\n\n"; } @@ -1118,7 +1123,7 @@ std::size_t TimingReporter::outputTimingPointList(std::ofstream* report_file, Ti { std::size_t label_width = getTimingLineLabelWidth(timing_path, delay_type); outputTimingPointHeader(report_file, label_width); - (*report_file) << " " << std::string(label_width + 28, '-') << "\n"; + (*report_file) << " " << std::string(label_width + kTimingTableExtraWidth, '-') << "\n"; outputLaunchClockInfo(report_file, timing_path, delay_type, label_width); bool is_first_point = true; for (TimingPathPoint& path_point : timing_path.get_point_list()) { @@ -1197,7 +1202,8 @@ void TimingReporter::updateTimingLineLabelWidth(std::size_t& label_width, std::s void TimingReporter::outputTimingPointHeader(std::ofstream* report_file, std::size_t label_width) { - (*report_file) << " " << std::left << std::setw(label_width) << "Point" << std::right << std::setw(10) << "Incr" << std::setw(11) << "Path" + (*report_file) << " " << std::left << std::setw(label_width + 2) << "Point" << std::right << std::setw(kTimingFanoutWidth) << "Fanout" + << std::setw(kTimingValueWidth) << "Incr" << std::setw(kTimingValueWidth) << "Path" << "\n"; } @@ -1240,14 +1246,11 @@ std::string TimingReporter::getLaunchClockEdgeText(TimingPath& timing_path, Dela } void TimingReporter::outputTimingLine(std::ofstream* report_file, std::string_view label, double incr, double path, bool has_incr, std::string transition, - std::size_t label_width) + std::size_t label_width, std::optional fanout) { - if (has_incr) { - (*report_file) << " " << std::left << std::setw(label_width + 2) << label << getNumberString(incr) << "\n"; - (*report_file) << " " << std::setw(label_width + 13) << "" << getNumberString(path); - } else { - (*report_file) << " " << std::left << std::setw(label_width + 13) << label << getNumberString(path); - } + (*report_file) << " " << std::left << std::setw(label_width + 2) << label << std::right << std::setw(kTimingFanoutWidth) + << (fanout.has_value() ? std::to_string(*fanout) : "") << std::setw(kTimingValueWidth) << (has_incr ? getNumberString(incr) : "") + << std::setw(kTimingValueWidth) << getNumberString(path); if (!transition.empty()) { (*report_file) << " " << transition; } @@ -1256,7 +1259,7 @@ void TimingReporter::outputTimingLine(std::ofstream* report_file, std::string_vi void TimingReporter::outputTimingSummaryLine(std::ofstream* report_file, std::string label, double value, std::size_t label_width) { - (*report_file) << " " << std::left << std::setw(label_width + 13) << label << getNumberString(value) << "\n"; + outputTimingLine(report_file, label, 0.0, value, false, "", label_width); } std::string TimingReporter::getClockName(TimingPath& timing_path) @@ -1344,7 +1347,28 @@ void TimingReporter::outputTimingPoint(std::ofstream* report_file, TimingPath& t arc_delay = path_point.get_arrival() - timing_path.get_launch_time(); } outputTimingLine(report_file, getPointLabel(path_point), arc_delay, path_point.get_arrival(), true, GetTransTypeInitial()(path_point.get_trans_type()), - label_width); + label_width, getPinFanout(path_point.get_pin_name())); +} + +std::optional TimingReporter::getPinFanout(const std::string& pin_name) +{ + Database& database = STADM.getDatabase(); + auto pin_it = database.get_pin_map().find(pin_name); + if (pin_it == database.get_pin_map().end()) { + return std::nullopt; + } + auto net_it = database.get_net_map().find(pin_it->second.get_net_name()); + if (net_it == database.get_net_map().end()) { + return std::nullopt; + } + Net& net = net_it->second; + const std::vector& drivers = net.get_driver_pin_list(); + if (net.get_driver_pin() != pin_name && std::find(drivers.begin(), drivers.end(), pin_name) == drivers.end()) { + return std::nullopt; + } + std::set loads(net.get_load_pin_list().begin(), net.get_load_pin_list().end()); + loads.erase(pin_name); + return loads.size(); } std::string TimingReporter::getNumberString(double value) @@ -1478,10 +1502,10 @@ std::string TimingReporter::getPinLabel(std::string& pin_name) void TimingReporter::outputTimingPathSummary(std::ofstream* report_file, TimingPath& timing_path, std::size_t label_width) { - (*report_file) << " " << std::string(label_width + 28, '-') << "\n"; + (*report_file) << " " << std::string(label_width + kTimingTableExtraWidth, '-') << "\n"; outputTimingSummaryLine(report_file, "data required time", timing_path.get_required_time(), label_width); outputTimingSummaryLine(report_file, "data arrival time", -timing_path.get_path_delay(), label_width); - (*report_file) << " " << std::string(label_width + 28, '-') << "\n"; + (*report_file) << " " << std::string(label_width + kTimingTableExtraWidth, '-') << "\n"; outputTimingSummaryLine(report_file, STAUTIL.getString("slack (", getSlackStatus(timing_path), ")"), timing_path.get_slack(), label_width); (*report_file) << "\n\n"; } diff --git a/src/operation/iSTA/source/module/timing_reporter/TimingReporter.hpp b/src/operation/iSTA/source/module/timing_reporter/TimingReporter.hpp index a5f372a1e..cf9cda7ab 100644 --- a/src/operation/iSTA/source/module/timing_reporter/TimingReporter.hpp +++ b/src/operation/iSTA/source/module/timing_reporter/TimingReporter.hpp @@ -103,7 +103,7 @@ class TimingReporter void outputLaunchClockInfo(std::ofstream* report_file, TimingPath& timing_path, DelayType delay_type, std::size_t label_width); std::string getLaunchClockEdgeText(TimingPath& timing_path, DelayType delay_type); void outputTimingLine(std::ofstream* report_file, std::string_view label, double incr, double path, bool has_incr, std::string transition, - std::size_t label_width); + std::size_t label_width, std::optional fanout = std::nullopt); void outputTimingSummaryLine(std::ofstream* report_file, std::string label, double value, std::size_t label_width); std::string getClockName(TimingPath& timing_path); std::string_view getClockNetworkDelayLabel(TimingPath& timing_path); @@ -112,6 +112,7 @@ class TimingReporter double getInputDelay(TimingPath& timing_path, DelayType delay_type); std::string getStartClockPin(TimingPath& timing_path); void outputTimingPoint(std::ofstream* report_file, TimingPath& timing_path, TimingPathPoint& path_point, bool is_first_point, std::size_t label_width); + std::optional getPinFanout(const std::string& pin_name); std::string getNumberString(double value); std::string getPointLabel(TimingPathPoint& path_point); std::string getPTPinName(std::string& pin_name);