#include #include #include #include #include #include #include "MinMax.hh" #include "Transition.hh" #include "Property.hh" #include "ExceptionPath.hh" #include "TimingRole.hh" #include "Corner.hh" #include "Sta.hh" #include "Sdc.hh" #include "ReportTcl.hh" #include "RiseFallMinMax.hh" #include "Variables.hh" #include "LibertyClass.hh" #include "PathAnalysisPt.hh" #include "DcalcAnalysisPt.hh" #include "Search.hh" #include "Path.hh" #include "PathGroup.hh" #include "PathExpanded.hh" #include "SearchPred.hh" #include "SearchClass.hh" #include "ClkNetwork.hh" #include "VisitPathEnds.hh" #include "search/CheckMinPulseWidths.hh" #include "search/CheckMinPeriods.hh" #include "search/CheckMaxSkews.hh" #include "search/ClkSkew.hh" #include "search/ClkInfo.hh" #include "search/Tag.hh" #include "search/PathEnum.hh" #include "search/Genclks.hh" #include "search/Levelize.hh" #include "search/Sim.hh" #include "Bfs.hh" #include "search/WorstSlack.hh" #include "search/ReportPath.hh" #include "GraphDelayCalc.hh" #include "Debug.hh" #include "PowerClass.hh" #include "search/CheckCapacitanceLimits.hh" #include "search/CheckSlewLimits.hh" #include "search/CheckFanoutLimits.hh" #include "search/Crpr.hh" #include "search/GatedClk.hh" #include "search/ClkLatency.hh" #include "search/FindRegister.hh" #include "search/TagGroup.hh" #include "search/MakeTimingModelPvt.hh" #include "search/CheckTiming.hh" #include "search/Latches.hh" #include "Graph.hh" #include "Liberty.hh" #include "Network.hh" namespace sta { template static void expectCallablePointerUsable(FnPtr fn) { ASSERT_NE(fn, nullptr); EXPECT_TRUE((std::is_pointer_v || std::is_member_function_pointer_v)); EXPECT_TRUE(std::is_copy_constructible_v); EXPECT_TRUE(std::is_copy_assignable_v); FnPtr fn_copy = fn; EXPECT_EQ(fn_copy, fn); } static std::string makeUniqueSdcPath(const char *tag) { static std::atomic counter{0}; char buf[256]; snprintf(buf, sizeof(buf), "%s_%d_%d.sdc", tag, static_cast(getpid()), counter.fetch_add(1)); return std::string(buf); } static void expectSdcFileReadable(const std::string &filename) { FILE *f = fopen(filename.c_str(), "r"); ASSERT_NE(f, nullptr); std::string content; char chunk[512]; size_t read_count = 0; while ((read_count = fread(chunk, 1, sizeof(chunk), f)) > 0) content.append(chunk, read_count); fclose(f); EXPECT_FALSE(content.empty()); EXPECT_GT(content.size(), 10u); EXPECT_NE(content.find('\n'), std::string::npos); EXPECT_EQ(content.find('\0'), std::string::npos); const bool has_set_cmd = content.find("set_") != std::string::npos; const bool has_create_clock = content.find("create_clock") != std::string::npos; EXPECT_TRUE(has_set_cmd || has_create_clock); EXPECT_EQ(remove(filename.c_str()), 0); } static void expectStaDesignCoreState(Sta *sta, bool design_loaded) { ASSERT_NE(sta, nullptr); EXPECT_EQ(Sta::sta(), sta); EXPECT_NE(sta->network(), nullptr); EXPECT_NE(sta->search(), nullptr); EXPECT_NE(sta->sdc(), nullptr); EXPECT_NE(sta->corners(), nullptr); if (sta->corners()) EXPECT_GE(sta->corners()->count(), 1); EXPECT_NE(sta->cmdCorner(), nullptr); EXPECT_TRUE(design_loaded); if (sta->network()) EXPECT_NE(sta->network()->topInstance(), nullptr); } // ============================================================ // StaDesignTest fixture: loads nangate45 + example1.v + clocks // Used for R8_ tests that need a real linked design with timing // ============================================================ class StaDesignTest : public ::testing::Test { protected: void SetUp() override { interp_ = Tcl_CreateInterp(); initSta(); sta_ = new Sta; Sta::setSta(sta_); sta_->makeComponents(); ReportTcl *report = dynamic_cast(sta_->report()); if (report) report->setTclInterp(interp_); Corner *corner = sta_->cmdCorner(); const MinMaxAll *min_max = MinMaxAll::all(); LibertyLibrary *lib = sta_->readLiberty( "test/nangate45/Nangate45_typ.lib", corner, min_max, false); ASSERT_NE(lib, nullptr); lib_ = lib; bool ok = sta_->readVerilog("examples/example1.v"); ASSERT_TRUE(ok); ok = sta_->linkDesign("top", true); ASSERT_TRUE(ok); Network *network = sta_->network(); Instance *top = network->topInstance(); Pin *clk1 = network->findPin(top, "clk1"); Pin *clk2 = network->findPin(top, "clk2"); Pin *clk3 = network->findPin(top, "clk3"); ASSERT_NE(clk1, nullptr); ASSERT_NE(clk2, nullptr); ASSERT_NE(clk3, nullptr); PinSet *clk_pins = new PinSet(network); clk_pins->insert(clk1); clk_pins->insert(clk2); clk_pins->insert(clk3); FloatSeq *waveform = new FloatSeq; waveform->push_back(0.0f); waveform->push_back(5.0f); sta_->makeClock("clk", clk_pins, false, 10.0f, waveform, nullptr); // Set input delays Pin *in1 = network->findPin(top, "in1"); Pin *in2 = network->findPin(top, "in2"); Clock *clk = sta_->sdc()->findClock("clk"); if (in1 && clk) { sta_->setInputDelay(in1, RiseFallBoth::riseFall(), clk, RiseFall::rise(), nullptr, false, false, MinMaxAll::all(), true, 0.0f); } if (in2 && clk) { sta_->setInputDelay(in2, RiseFallBoth::riseFall(), clk, RiseFall::rise(), nullptr, false, false, MinMaxAll::all(), true, 0.0f); } sta_->updateTiming(true); design_loaded_ = true; } void TearDown() override { if (sta_) expectStaDesignCoreState(sta_, design_loaded_); deleteAllMemory(); sta_ = nullptr; if (interp_) Tcl_DeleteInterp(interp_); interp_ = nullptr; } // Helper: get a vertex for a pin by hierarchical name e.g. "r1/CK" Vertex *findVertex(const char *path_name) { Network *network = sta_->cmdNetwork(); Pin *pin = network->findPin(path_name); if (!pin) return nullptr; Graph *graph = sta_->graph(); if (!graph) return nullptr; return graph->pinDrvrVertex(pin); } Pin *findPin(const char *path_name) { Network *network = sta_->cmdNetwork(); return network->findPin(path_name); } Sta *sta_; Tcl_Interp *interp_; LibertyLibrary *lib_; bool design_loaded_ = false; }; // ============================================================ // R8_ tests: Sta.cc methods with loaded design // ============================================================ // --- vertexArrival overloads --- TEST_F(StaDesignTest, VertexArrivalMinMax) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Arrival arr = sta_->vertexArrival(v, MinMax::max()); (void)arr; } TEST_F(StaDesignTest, VertexArrivalRfPathAP) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Corner *corner = sta_->cmdCorner(); const PathAnalysisPt *path_ap = corner->findPathAnalysisPt(MinMax::max()); ASSERT_NE(path_ap, nullptr); Arrival arr = sta_->vertexArrival(v, RiseFall::rise(), path_ap); (void)arr; } // --- vertexRequired overloads --- TEST_F(StaDesignTest, VertexRequiredMinMax) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Required req = sta_->vertexRequired(v, MinMax::max()); (void)req; } TEST_F(StaDesignTest, VertexRequiredRfMinMax) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Required req = sta_->vertexRequired(v, RiseFall::rise(), MinMax::max()); (void)req; } TEST_F(StaDesignTest, VertexRequiredRfPathAP) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Corner *corner = sta_->cmdCorner(); const PathAnalysisPt *path_ap = corner->findPathAnalysisPt(MinMax::max()); ASSERT_NE(path_ap, nullptr); Required req = sta_->vertexRequired(v, RiseFall::rise(), path_ap); (void)req; } // --- vertexSlack overloads --- TEST_F(StaDesignTest, VertexSlackMinMax) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Slack slk = sta_->vertexSlack(v, MinMax::max()); (void)slk; } TEST_F(StaDesignTest, VertexSlackRfPathAP) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Corner *corner = sta_->cmdCorner(); const PathAnalysisPt *path_ap = corner->findPathAnalysisPt(MinMax::max()); ASSERT_NE(path_ap, nullptr); Slack slk = sta_->vertexSlack(v, RiseFall::rise(), path_ap); (void)slk; } // --- vertexSlacks --- TEST_F(StaDesignTest, VertexSlacks) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Slack slacks[RiseFall::index_count][MinMax::index_count]; sta_->vertexSlacks(v, slacks); // Just verify it doesn't crash; values depend on timing } // --- vertexSlew overloads --- TEST_F(StaDesignTest, VertexSlewRfCornerMinMax) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); Corner *corner = sta_->cmdCorner(); Slew slew = sta_->vertexSlew(v, RiseFall::rise(), corner, MinMax::max()); (void)slew; } TEST_F(StaDesignTest, VertexSlewRfDcalcAP) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); Corner *corner = sta_->cmdCorner(); const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(MinMax::max()); ASSERT_NE(dcalc_ap, nullptr); Slew slew = sta_->vertexSlew(v, RiseFall::rise(), dcalc_ap); (void)slew; } // --- vertexWorstRequiredPath --- TEST_F(StaDesignTest, VertexWorstRequiredPath) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstRequiredPath(v, MinMax::max()); // May be nullptr if no required; just check it doesn't crash (void)path; } TEST_F(StaDesignTest, VertexWorstRequiredPathRf) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstRequiredPath(v, RiseFall::rise(), MinMax::max()); (void)path; } // --- vertexPathIterator --- TEST_F(StaDesignTest, VertexPathIteratorRfPathAP) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Corner *corner = sta_->cmdCorner(); const PathAnalysisPt *path_ap = corner->findPathAnalysisPt(MinMax::max()); ASSERT_NE(path_ap, nullptr); VertexPathIterator *iter = sta_->vertexPathIterator(v, RiseFall::rise(), path_ap); ASSERT_NE(iter, nullptr); delete iter; } // --- checkSlewLimits --- TEST_F(StaDesignTest, CheckSlewLimitPreambleAndLimits) { ASSERT_NO_THROW(( [&](){ sta_->checkSlewLimitPreamble(); PinSeq pins = sta_->checkSlewLimits(nullptr, false, sta_->cmdCorner(), MinMax::max()); // May be empty; just check no crash }() )); } TEST_F(StaDesignTest, CheckSlewViolators) { ASSERT_NO_THROW(( [&](){ sta_->checkSlewLimitPreamble(); PinSeq pins = sta_->checkSlewLimits(nullptr, true, sta_->cmdCorner(), MinMax::max()); }() )); } // --- checkSlew (single pin) --- TEST_F(StaDesignTest, CheckSlew) { sta_->checkSlewLimitPreamble(); Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); const Corner *corner1 = nullptr; const RiseFall *tr = nullptr; Slew slew; float limit, slack; sta_->checkSlew(pin, sta_->cmdCorner(), MinMax::max(), false, corner1, tr, slew, limit, slack); } // --- findSlewLimit --- TEST_F(StaDesignTest, FindSlewLimit) { sta_->checkSlewLimitPreamble(); LibertyCell *buf = lib_->findLibertyCell("BUF_X1"); ASSERT_NE(buf, nullptr); LibertyPort *port_z = buf->findLibertyPort("Z"); ASSERT_NE(port_z, nullptr); float limit = 0.0f; bool exists = false; sta_->findSlewLimit(port_z, sta_->cmdCorner(), MinMax::max(), limit, exists); } // --- checkFanoutLimits --- TEST_F(StaDesignTest, CheckFanoutLimits) { ASSERT_NO_THROW(( [&](){ sta_->checkFanoutLimitPreamble(); PinSeq pins = sta_->checkFanoutLimits(nullptr, false, MinMax::max()); }() )); } TEST_F(StaDesignTest, CheckFanoutViolators) { ASSERT_NO_THROW(( [&](){ sta_->checkFanoutLimitPreamble(); PinSeq pins = sta_->checkFanoutLimits(nullptr, true, MinMax::max()); }() )); } // --- checkFanout (single pin) --- TEST_F(StaDesignTest, CheckFanout) { sta_->checkFanoutLimitPreamble(); Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); float fanout, limit, slack; sta_->checkFanout(pin, MinMax::max(), fanout, limit, slack); } // --- checkCapacitanceLimits --- TEST_F(StaDesignTest, CheckCapacitanceLimits) { ASSERT_NO_THROW(( [&](){ sta_->checkCapacitanceLimitPreamble(); PinSeq pins = sta_->checkCapacitanceLimits(nullptr, false, sta_->cmdCorner(), MinMax::max()); }() )); } TEST_F(StaDesignTest, CheckCapacitanceViolators) { ASSERT_NO_THROW(( [&](){ sta_->checkCapacitanceLimitPreamble(); PinSeq pins = sta_->checkCapacitanceLimits(nullptr, true, sta_->cmdCorner(), MinMax::max()); }() )); } // --- checkCapacitance (single pin) --- TEST_F(StaDesignTest, CheckCapacitance) { sta_->checkCapacitanceLimitPreamble(); Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); const Corner *corner1 = nullptr; const RiseFall *tr = nullptr; float cap, limit, slack; sta_->checkCapacitance(pin, sta_->cmdCorner(), MinMax::max(), corner1, tr, cap, limit, slack); } // --- minPulseWidthSlack --- TEST_F(StaDesignTest, MinPulseWidthSlack) { ASSERT_NO_THROW(( [&](){ MinPulseWidthCheck *check = sta_->minPulseWidthSlack(nullptr); // May be nullptr; just don't crash (void)check; }() )); } // --- minPulseWidthViolations --- TEST_F(StaDesignTest, MinPulseWidthViolations) { ASSERT_NO_THROW(( [&](){ MinPulseWidthCheckSeq &violations = sta_->minPulseWidthViolations(nullptr); (void)violations; }() )); } // --- minPulseWidthChecks (all) --- TEST_F(StaDesignTest, MinPulseWidthChecksAll) { ASSERT_NO_THROW(( [&](){ MinPulseWidthCheckSeq &checks = sta_->minPulseWidthChecks(nullptr); (void)checks; }() )); } // --- minPeriodSlack --- TEST_F(StaDesignTest, MinPeriodSlack) { ASSERT_NO_THROW(( [&](){ MinPeriodCheck *check = sta_->minPeriodSlack(); (void)check; }() )); } // --- minPeriodViolations --- TEST_F(StaDesignTest, MinPeriodViolations) { ASSERT_NO_THROW(( [&](){ MinPeriodCheckSeq &violations = sta_->minPeriodViolations(); (void)violations; }() )); } // --- maxSkewSlack --- TEST_F(StaDesignTest, MaxSkewSlack) { ASSERT_NO_THROW(( [&](){ MaxSkewCheck *check = sta_->maxSkewSlack(); (void)check; }() )); } // --- maxSkewViolations --- TEST_F(StaDesignTest, MaxSkewViolations) { ASSERT_NO_THROW(( [&](){ MaxSkewCheckSeq &violations = sta_->maxSkewViolations(); (void)violations; }() )); } // --- reportCheck (MaxSkewCheck) --- TEST_F(StaDesignTest, ReportCheckMaxSkew) { ASSERT_NO_THROW(( [&](){ MaxSkewCheck *check = sta_->maxSkewSlack(); if (check) { sta_->reportCheck(check, false); sta_->reportCheck(check, true); } }() )); } // --- reportCheck (MinPeriodCheck) --- TEST_F(StaDesignTest, ReportCheckMinPeriod) { ASSERT_NO_THROW(( [&](){ MinPeriodCheck *check = sta_->minPeriodSlack(); if (check) { sta_->reportCheck(check, false); sta_->reportCheck(check, true); } }() )); } // --- reportMpwCheck --- TEST_F(StaDesignTest, ReportMpwCheck) { ASSERT_NO_THROW(( [&](){ MinPulseWidthCheck *check = sta_->minPulseWidthSlack(nullptr); if (check) { sta_->reportMpwCheck(check, false); sta_->reportMpwCheck(check, true); } }() )); } // --- findPathEnds --- TEST_F(StaDesignTest, FindPathEnds) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, // unconstrained nullptr, // corner (all) MinMaxAll::max(), 10, // group_path_count 1, // endpoint_path_count false, // unique_pins false, // unique_edges -INF, // slack_min INF, // slack_max false, // sort_by_slack nullptr, // group_names true, // setup false, // hold false, // recovery false, // removal false, // clk_gating_setup false); // clk_gating_hold // Should find some path ends in this design }() )); } // --- reportPathEndHeader / Footer --- TEST_F(StaDesignTest, ReportPathEndHeaderFooter) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::full); sta_->reportPathEndHeader(); sta_->reportPathEndFooter(); }() )); } // --- reportPathEnd --- TEST_F(StaDesignTest, ReportPathEnd) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } // --- reportPathEnds --- TEST_F(StaDesignTest, ReportPathEnds) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); sta_->reportPathEnds(&ends); }() )); } // --- reportClkSkew --- TEST_F(StaDesignTest, ReportClkSkew) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ConstClockSeq clks; clks.push_back(clk); sta_->reportClkSkew(clks, nullptr, SetupHold::max(), false, 4); } // --- isClock(Net*) --- TEST_F(StaDesignTest, IsClockNet) { sta_->ensureClkNetwork(); Network *network = sta_->cmdNetwork(); Pin *clk1_pin = findPin("clk1"); ASSERT_NE(clk1_pin, nullptr); Net *clk_net = network->net(clk1_pin); if (clk_net) { bool is_clk = sta_->isClock(clk_net); EXPECT_TRUE(is_clk); } } // --- pins(Clock*) --- TEST_F(StaDesignTest, ClockPins) { sta_->ensureClkNetwork(); Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); const PinSet *pins = sta_->pins(clk); EXPECT_NE(pins, nullptr); if (pins) { EXPECT_GT(pins->size(), 0u); } } // --- pvt / setPvt --- TEST_F(StaDesignTest, PvtGetSet) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); const Pvt *p = sta_->pvt(top, MinMax::max()); // p may be nullptr if not set; just don't crash (void)p; sta_->setPvt(top, MinMaxAll::all(), 1.0f, 1.1f, 25.0f); p = sta_->pvt(top, MinMax::max()); }() )); } // --- findDelays(int) --- TEST_F(StaDesignTest, FindDelaysLevel) { ASSERT_NO_THROW(( [&](){ sta_->findDelays(0); }() )); } // --- findDelays (no arg - public) --- TEST_F(StaDesignTest, FindDelays) { ASSERT_NO_THROW(( [&](){ sta_->findDelays(); }() )); } // --- arrivalsInvalid / delaysInvalid --- TEST_F(StaDesignTest, ArrivalsInvalid) { ASSERT_NO_THROW(( [&](){ sta_->arrivalsInvalid(); }() )); } TEST_F(StaDesignTest, DelaysInvalid) { ASSERT_NO_THROW(( [&](){ sta_->delaysInvalid(); }() )); } // --- makeEquivCells --- TEST_F(StaDesignTest, MakeEquivCells) { ASSERT_NO_THROW(( [&](){ LibertyLibrarySeq *equiv_libs = new LibertyLibrarySeq; equiv_libs->push_back(lib_); LibertyLibrarySeq *map_libs = new LibertyLibrarySeq; map_libs->push_back(lib_); sta_->makeEquivCells(equiv_libs, map_libs); // Check equivCells for BUF_X1 LibertyCell *buf = lib_->findLibertyCell("BUF_X1"); if (buf) { LibertyCellSeq *equiv = sta_->equivCells(buf); (void)equiv; } }() )); } // --- maxPathCountVertex --- TEST_F(StaDesignTest, MaxPathCountVertex) { ASSERT_NO_THROW(( [&](){ Vertex *v = sta_->maxPathCountVertex(); // May be nullptr; just don't crash (void)v; }() )); } // --- makeParasiticAnalysisPts --- TEST_F(StaDesignTest, MakeParasiticAnalysisPts) { ASSERT_NO_THROW(( [&](){ sta_->setParasiticAnalysisPts(false); // Ensures parasitic analysis points are set up }() )); } // --- findLogicConstants (Sim) --- TEST_F(StaDesignTest, FindLogicConstants) { ASSERT_NO_THROW(( [&](){ sta_->findLogicConstants(); sta_->clearLogicConstants(); }() )); } // --- checkTiming --- TEST_F(StaDesignTest, CheckTiming) { ASSERT_NO_THROW(( [&](){ CheckErrorSeq &errors = sta_->checkTiming( true, // no_input_delay true, // no_output_delay true, // reg_multiple_clks true, // reg_no_clks true, // unconstrained_endpoints true, // loops true); // generated_clks (void)errors; }() )); } // --- Property methods --- TEST_F(StaDesignTest, PropertyGetPinArrival) { Properties &props = sta_->properties(); Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); PropertyValue pv = props.getProperty(pin, "arrival_max_rise"); (void)pv; } TEST_F(StaDesignTest, PropertyGetPinSlack) { Properties &props = sta_->properties(); Pin *pin = findPin("r3/D"); ASSERT_NE(pin, nullptr); PropertyValue pv = props.getProperty(pin, "slack_max"); (void)pv; } TEST_F(StaDesignTest, PropertyGetPinSlew) { Properties &props = sta_->properties(); Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); PropertyValue pv = props.getProperty(pin, "slew_max"); (void)pv; } TEST_F(StaDesignTest, PropertyGetPinArrivalFall) { Properties &props = sta_->properties(); Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); PropertyValue pv = props.getProperty(pin, "arrival_max_fall"); (void)pv; } TEST_F(StaDesignTest, PropertyGetInstanceName) { Properties &props = sta_->properties(); Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Instance *u1 = network->findChild(top, "u1"); ASSERT_NE(u1, nullptr); PropertyValue pv = props.getProperty(u1, "full_name"); (void)pv; } TEST_F(StaDesignTest, PropertyGetNetName) { Properties &props = sta_->properties(); Network *network = sta_->cmdNetwork(); Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); Net *net = network->net(pin); if (net) { PropertyValue pv = props.getProperty(net, "name"); (void)pv; } } // --- Search methods --- TEST_F(StaDesignTest, SearchCopyState) { Search *search = sta_->search(); ASSERT_NE(search, nullptr); search->copyState(sta_); } TEST_F(StaDesignTest, SearchFindPathGroupByName) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); // First ensure path groups exist sta_->findPathEnds(nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); PathGroup *pg = search->findPathGroup("clk", MinMax::max()); // May or may not find it (void)pg; }() )); } TEST_F(StaDesignTest, SearchFindPathGroupByClock) { Search *search = sta_->search(); sta_->findPathEnds(nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); PathGroup *pg = search->findPathGroup(clk, MinMax::max()); (void)pg; } TEST_F(StaDesignTest, SearchReportTagGroups) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->reportTagGroups(); }() )); } TEST_F(StaDesignTest, SearchDeletePathGroups) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); // Ensure path groups exist first sta_->findPathEnds(nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); search->deletePathGroups(); }() )); } TEST_F(StaDesignTest, SearchVisitEndpoints) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Network *network = sta_->cmdNetwork(); PinSet pins(network); VertexPinCollector collector(pins); search->visitEndpoints(&collector); }() )); } // --- Search: visitStartpoints --- TEST_F(StaDesignTest, SearchVisitStartpoints) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Network *network = sta_->cmdNetwork(); PinSet pins(network); VertexPinCollector collector(pins); search->visitStartpoints(&collector); }() )); } TEST_F(StaDesignTest, SearchTagGroup) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); // Tag group index 0 may or may not exist; just don't crash if (search->tagGroupCount() > 0) { TagGroup *tg = search->tagGroup(0); (void)tg; } }() )); } TEST_F(StaDesignTest, SearchClockDomainsVertex) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Vertex *v = findVertex("r1/CK"); if (v) { ClockSet domains = search->clockDomains(v); (void)domains; } }() )); } TEST_F(StaDesignTest, SearchIsGenClkSrc) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Vertex *v = findVertex("r1/Q"); if (v) { bool is_gen = search->isGenClkSrc(v); (void)is_gen; } }() )); } TEST_F(StaDesignTest, SearchPathGroups) { ASSERT_NO_THROW(( [&](){ // Get a path end to query its path groups PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { Search *search = sta_->search(); PathGroupSeq groups = search->pathGroups(ends[0]); (void)groups; } }() )); } TEST_F(StaDesignTest, SearchPathClkPathArrival) { Search *search = sta_->search(); // Get a path from a vertex Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { Arrival arr = search->pathClkPathArrival(path); (void)arr; } } // --- ReportPath methods --- // --- ReportPath: reportFull exercised through reportPathEnd (full format) --- TEST_F(StaDesignTest, ReportPathFullClockFormat) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::full_clock); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathFullClockExpandedFormat) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::full_clock_expanded); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathShorterFormat) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::shorter); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathJsonFormat) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::json); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathShortMpw) { ASSERT_NO_THROW(( [&](){ MinPulseWidthCheck *check = sta_->minPulseWidthSlack(nullptr); if (check) { ReportPath *rpt = sta_->reportPath(); rpt->reportShort(check); } }() )); } TEST_F(StaDesignTest, ReportPathVerboseMpw) { ASSERT_NO_THROW(( [&](){ MinPulseWidthCheck *check = sta_->minPulseWidthSlack(nullptr); if (check) { ReportPath *rpt = sta_->reportPath(); rpt->reportVerbose(check); } }() )); } // --- ReportPath: reportJson --- TEST_F(StaDesignTest, ReportJsonHeaderFooter) { ReportPath *rpt = sta_->reportPath(); ASSERT_NE(rpt, nullptr); rpt->reportJsonHeader(); rpt->reportJsonFooter(); } TEST_F(StaDesignTest, ReportJsonPathEnd) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { ReportPath *rpt = sta_->reportPath(); rpt->reportJsonHeader(); rpt->reportJson(ends[0], ends.size() == 1); rpt->reportJsonFooter(); } }() )); } // --- disable / removeDisable --- TEST_F(StaDesignTest, DisableEnableLibertyPort) { LibertyCell *buf = lib_->findLibertyCell("BUF_X1"); ASSERT_NE(buf, nullptr); LibertyPort *port_a = buf->findLibertyPort("A"); ASSERT_NE(port_a, nullptr); sta_->disable(port_a); sta_->removeDisable(port_a); } TEST_F(StaDesignTest, DisableEnableTimingArcSet) { LibertyCell *buf = lib_->findLibertyCell("BUF_X1"); ASSERT_NE(buf, nullptr); const TimingArcSetSeq &arc_sets = buf->timingArcSets(); ASSERT_GT(arc_sets.size(), 0u); sta_->disable(arc_sets[0]); sta_->removeDisable(arc_sets[0]); } TEST_F(StaDesignTest, DisableEnableEdge) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); // Get an edge from this vertex VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); sta_->disable(edge); sta_->removeDisable(edge); } } // --- disableClockGatingCheck / removeDisableClockGatingCheck --- TEST_F(StaDesignTest, DisableClockGatingCheckPin) { Pin *pin = findPin("r1/CK"); ASSERT_NE(pin, nullptr); sta_->disableClockGatingCheck(pin); sta_->removeDisableClockGatingCheck(pin); } // --- setCmdNamespace1 (Sta internal) --- TEST_F(StaDesignTest, SetCmdNamespace1) { sta_->setCmdNamespace(CmdNamespace::sdc); EXPECT_EQ(sta_->cmdNamespace(), CmdNamespace::sdc); sta_->setCmdNamespace(CmdNamespace::sta); EXPECT_EQ(sta_->cmdNamespace(), CmdNamespace::sta); } // --- delaysInvalidFromFanin --- TEST_F(StaDesignTest, DelaysInvalidFromFaninPin) { Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); sta_->delaysInvalidFromFanin(pin); } // --- setArcDelayAnnotated --- TEST_F(StaDesignTest, SetArcDelayAnnotated) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); TimingArcSet *arc_set = edge->timingArcSet(); if (arc_set) { const TimingArcSeq &arcs = arc_set->arcs(); if (!arcs.empty()) { Corner *corner = sta_->cmdCorner(); DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(MinMax::max()); sta_->setArcDelayAnnotated(edge, arcs[0], dcalc_ap, true); sta_->setArcDelayAnnotated(edge, arcs[0], dcalc_ap, false); } } } } // --- pathAnalysisPt / pathDcalcAnalysisPt --- TEST_F(StaDesignTest, PathAnalysisPt) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { PathAnalysisPt *pa = sta_->pathAnalysisPt(path); (void)pa; DcalcAnalysisPt *da = sta_->pathDcalcAnalysisPt(path); (void)da; } } // --- worstSlack / totalNegativeSlack --- TEST_F(StaDesignTest, WorstSlack) { ASSERT_NO_THROW(( [&](){ Slack worst; Vertex *worst_vertex = nullptr; sta_->worstSlack(MinMax::max(), worst, worst_vertex); (void)worst; }() )); } TEST_F(StaDesignTest, WorstSlackCorner) { ASSERT_NO_THROW(( [&](){ Slack worst; Vertex *worst_vertex = nullptr; Corner *corner = sta_->cmdCorner(); sta_->worstSlack(corner, MinMax::max(), worst, worst_vertex); (void)worst; }() )); } TEST_F(StaDesignTest, TotalNegativeSlack) { ASSERT_NO_THROW(( [&](){ Slack tns = sta_->totalNegativeSlack(MinMax::max()); (void)tns; }() )); } TEST_F(StaDesignTest, TotalNegativeSlackCorner) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); Slack tns = sta_->totalNegativeSlack(corner, MinMax::max()); (void)tns; }() )); } // --- endpoints / endpointViolationCount --- TEST_F(StaDesignTest, Endpoints) { VertexSet *eps = sta_->endpoints(); EXPECT_NE(eps, nullptr); } TEST_F(StaDesignTest, EndpointViolationCount) { ASSERT_NO_THROW(( [&](){ int count = sta_->endpointViolationCount(MinMax::max()); (void)count; }() )); } // --- findRequireds --- TEST_F(StaDesignTest, FindRequireds) { ASSERT_NO_THROW(( [&](){ sta_->findRequireds(); }() )); } // --- Search: tag(0) --- TEST_F(StaDesignTest, SearchTag) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); if (search->tagCount() > 0) { Tag *t = search->tag(0); (void)t; } }() )); } // --- Levelize: checkLevels --- TEST_F(StaDesignTest, GraphLoops) { ASSERT_NO_THROW(( [&](){ GraphLoopSeq &loops = sta_->graphLoops(); (void)loops; }() )); } // --- reportPath (Path*) --- TEST_F(StaDesignTest, ReportPath) { Vertex *v = findVertex("u2/ZN"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { sta_->reportPath(path); } } // --- ClkNetwork: clocks(Pin*) --- TEST_F(StaDesignTest, ClkNetworkClocksPinDirect) { sta_->ensureClkNetwork(); ClkNetwork *clk_net = sta_->clkNetwork(); ASSERT_NE(clk_net, nullptr); Pin *clk1_pin = findPin("clk1"); ASSERT_NE(clk1_pin, nullptr); const ClockSet *clks = clk_net->clocks(clk1_pin); (void)clks; } // --- ClkNetwork: pins(Clock*) --- TEST_F(StaDesignTest, ClkNetworkPins) { sta_->ensureClkNetwork(); ClkNetwork *clk_net = sta_->clkNetwork(); ASSERT_NE(clk_net, nullptr); Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); const PinSet *pins = clk_net->pins(clk); EXPECT_NE(pins, nullptr); } // --- ClkNetwork: isClock(Net*) --- TEST_F(StaDesignTest, ClkNetworkIsClockNet) { sta_->ensureClkNetwork(); ClkNetwork *clk_net = sta_->clkNetwork(); ASSERT_NE(clk_net, nullptr); Pin *clk1_pin = findPin("clk1"); ASSERT_NE(clk1_pin, nullptr); Network *network = sta_->cmdNetwork(); Net *net = network->net(clk1_pin); if (net) { bool is_clk = clk_net->isClock(net); (void)is_clk; } } // --- ClkInfo accessors --- TEST_F(StaDesignTest, ClkInfoAccessors) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); if (search->tagCount() > 0) { Tag *tag = search->tag(0); if (tag) { const ClkInfo *clk_info = tag->clkInfo(); if (clk_info) { const ClockEdge *edge = clk_info->clkEdge(); (void)edge; bool propagated = clk_info->isPropagated(); (void)propagated; bool is_gen = clk_info->isGenClkSrcPath(); (void)is_gen; } } } }() )); } // --- Tag accessors --- TEST_F(StaDesignTest, TagAccessors) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); if (search->tagCount() > 0) { Tag *tag = search->tag(0); if (tag) { PathAPIndex idx = tag->pathAPIndex(); (void)idx; const Pin *src = tag->clkSrc(); (void)src; } } }() )); } // --- TagGroup::report --- TEST_F(StaDesignTest, TagGroupReport) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); if (search->tagGroupCount() > 0) { TagGroup *tg = search->tagGroup(0); if (tg) { tg->report(sta_); } } }() )); } // --- BfsIterator --- TEST_F(StaDesignTest, BfsIteratorInit) { BfsFwdIterator *iter = sta_->search()->arrivalIterator(); ASSERT_NE(iter, nullptr); // Just verify the iterator exists - init is called internally } // --- SearchPredNonReg2 --- TEST_F(StaDesignTest, SearchPredNonReg2SearchThru) { SearchPredNonReg2 pred(sta_); Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); bool thru = pred.searchThru(edge); (void)thru; } } // --- PathExpanded --- TEST_F(StaDesignTest, PathExpanded) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { PathExpanded expanded(path, false, sta_); size_t size = expanded.size(); for (size_t i = 0; i < size; i++) { const Path *p = expanded.path(i); (void)p; } } } // --- Search: endpoints --- TEST_F(StaDesignTest, SearchEndpoints) { Search *search = sta_->search(); VertexSet *eps = search->endpoints(); EXPECT_NE(eps, nullptr); } // --- FindRegister (findRegs) --- TEST_F(StaDesignTest, FindRegPins) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ClockSet clk_set; clk_set.insert(clk); PinSet reg_clk_pins = sta_->findRegisterClkPins(&clk_set, RiseFallBoth::riseFall(), false, false); (void)reg_clk_pins; } TEST_F(StaDesignTest, FindRegDataPins) { ASSERT_NO_THROW(( [&](){ PinSet reg_data_pins = sta_->findRegisterDataPins(nullptr, RiseFallBoth::riseFall(), false, false); (void)reg_data_pins; }() )); } TEST_F(StaDesignTest, FindRegOutputPins) { ASSERT_NO_THROW(( [&](){ PinSet reg_out_pins = sta_->findRegisterOutputPins(nullptr, RiseFallBoth::riseFall(), false, false); (void)reg_out_pins; }() )); } TEST_F(StaDesignTest, FindRegAsyncPins) { ASSERT_NO_THROW(( [&](){ PinSet reg_async_pins = sta_->findRegisterAsyncPins(nullptr, RiseFallBoth::riseFall(), false, false); (void)reg_async_pins; }() )); } TEST_F(StaDesignTest, FindRegInstances) { ASSERT_NO_THROW(( [&](){ InstanceSet reg_insts = sta_->findRegisterInstances(nullptr, RiseFallBoth::riseFall(), false, false); (void)reg_insts; }() )); } // --- Sim::findLogicConstants --- TEST_F(StaDesignTest, SimFindLogicConstants) { Sim *sim = sta_->sim(); ASSERT_NE(sim, nullptr); sim->findLogicConstants(); } // --- reportSlewLimitShortHeader --- TEST_F(StaDesignTest, ReportSlewLimitShortHeader) { ASSERT_NO_THROW(( [&](){ sta_->reportSlewLimitShortHeader(); }() )); } // --- reportFanoutLimitShortHeader --- TEST_F(StaDesignTest, ReportFanoutLimitShortHeader) { ASSERT_NO_THROW(( [&](){ sta_->reportFanoutLimitShortHeader(); }() )); } // --- reportCapacitanceLimitShortHeader --- TEST_F(StaDesignTest, ReportCapacitanceLimitShortHeader) { ASSERT_NO_THROW(( [&](){ sta_->reportCapacitanceLimitShortHeader(); }() )); } // --- Path methods --- TEST_F(StaDesignTest, PathTransition) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { const RiseFall *rf = path->transition(sta_); (void)rf; } } // --- endpointSlack --- TEST_F(StaDesignTest, EndpointSlack) { Pin *pin = findPin("r3/D"); ASSERT_NE(pin, nullptr); Slack slk = sta_->endpointSlack(pin, "clk", MinMax::max()); (void)slk; } // --- replaceCell --- TEST_F(StaDesignTest, ReplaceCell) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); // Find instance u1 (BUF_X1) Instance *u1 = network->findChild(top, "u1"); ASSERT_NE(u1, nullptr); // Replace with BUF_X2 (should exist in nangate45) LibertyCell *buf_x2 = lib_->findLibertyCell("BUF_X2"); if (buf_x2) { sta_->replaceCell(u1, buf_x2); // Replace back LibertyCell *buf_x1 = lib_->findLibertyCell("BUF_X1"); if (buf_x1) sta_->replaceCell(u1, buf_x1); } } // --- reportPathEnd with prev_end --- TEST_F(StaDesignTest, ReportPathEndWithPrev) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (ends.size() >= 2) { sta_->reportPathEnd(ends[1], ends[0], false); } }() )); } // --- PathEnd static methods --- TEST_F(StaDesignTest, PathEndLess) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (ends.size() >= 2) { bool less = PathEnd::less(ends[0], ends[1], sta_); (void)less; int cmp = PathEnd::cmpNoCrpr(ends[0], ends[1], sta_); (void)cmp; } }() )); } // --- PathEnd accessors on real path ends --- TEST_F(StaDesignTest, PathEndAccessors) { PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { PathEnd *end = ends[0]; const char *tn = end->typeName(); EXPECT_NE(tn, nullptr); PathEnd::Type t = end->type(); (void)t; const RiseFall *rf = end->transition(sta_); (void)rf; PathAPIndex idx = end->pathIndex(sta_); (void)idx; const Clock *tgt_clk = end->targetClk(sta_); (void)tgt_clk; Arrival tgt_arr = end->targetClkArrival(sta_); (void)tgt_arr; float tgt_time = end->targetClkTime(sta_); (void)tgt_time; float tgt_offset = end->targetClkOffset(sta_); (void)tgt_offset; Delay tgt_delay = end->targetClkDelay(sta_); (void)tgt_delay; Delay tgt_ins = end->targetClkInsertionDelay(sta_); (void)tgt_ins; float tgt_unc = end->targetClkUncertainty(sta_); (void)tgt_unc; float ni_unc = end->targetNonInterClkUncertainty(sta_); (void)ni_unc; float inter_unc = end->interClkUncertainty(sta_); (void)inter_unc; float mcp_adj = end->targetClkMcpAdjustment(sta_); (void)mcp_adj; } } // --- ReportPath: reportShort for MinPeriodCheck --- TEST_F(StaDesignTest, ReportPathShortMinPeriod) { ASSERT_NO_THROW(( [&](){ MinPeriodCheck *check = sta_->minPeriodSlack(); if (check) { ReportPath *rpt = sta_->reportPath(); rpt->reportShort(check); } }() )); } // --- ReportPath: reportShort for MaxSkewCheck --- TEST_F(StaDesignTest, ReportPathShortMaxSkew) { ASSERT_NO_THROW(( [&](){ MaxSkewCheck *check = sta_->maxSkewSlack(); if (check) { ReportPath *rpt = sta_->reportPath(); rpt->reportShort(check); } }() )); } // --- ReportPath: reportCheck for MaxSkewCheck --- TEST_F(StaDesignTest, ReportPathCheckMaxSkew) { ASSERT_NO_THROW(( [&](){ MaxSkewCheck *check = sta_->maxSkewSlack(); if (check) { ReportPath *rpt = sta_->reportPath(); rpt->reportCheck(check, false); rpt->reportCheck(check, true); } }() )); } // --- ReportPath: reportVerbose for MaxSkewCheck --- TEST_F(StaDesignTest, ReportPathVerboseMaxSkew) { ASSERT_NO_THROW(( [&](){ MaxSkewCheck *check = sta_->maxSkewSlack(); if (check) { ReportPath *rpt = sta_->reportPath(); rpt->reportVerbose(check); } }() )); } // --- ReportPath: reportMpwChecks (covers mpwCheckHiLow internally) --- TEST_F(StaDesignTest, ReportMpwChecks) { ASSERT_NO_THROW(( [&](){ MinPulseWidthCheckSeq &checks = sta_->minPulseWidthChecks(nullptr); if (!checks.empty()) { ReportPath *rpt = sta_->reportPath(); rpt->reportMpwChecks(&checks, false); rpt->reportMpwChecks(&checks, true); } }() )); } // --- findClkMinPeriod --- TEST_F(StaDesignTest, FindClkMinPeriod) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); float min_period = sta_->findClkMinPeriod(clk, false); (void)min_period; } // --- slowDrivers --- TEST_F(StaDesignTest, SlowDrivers) { ASSERT_NO_THROW(( [&](){ InstanceSeq slow = sta_->slowDrivers(5); (void)slow; }() )); } // --- vertexLevel --- TEST_F(StaDesignTest, VertexLevel) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); Level lvl = sta_->vertexLevel(v); EXPECT_GE(lvl, 0); } // --- simLogicValue --- TEST_F(StaDesignTest, SimLogicValue) { Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); LogicValue val = sta_->simLogicValue(pin); (void)val; } // --- Search: clear (exercises initVars internally) --- TEST_F(StaDesignTest, SearchClear) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); // clear() calls initVars() internally search->clear(); }() )); } // --- readLibertyFile (protected, call through public readLiberty) --- // This tests readLibertyFile indirectly TEST_F(StaDesignTest, ReadLibertyFile) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); LibertyLibrary *lib = sta_->readLiberty( "test/nangate45/Nangate45_slow.lib", corner, MinMaxAll::min(), false); // May or may not succeed depending on file existence; just check no crash (void)lib; }() )); } // --- Property: getProperty on LibertyLibrary --- TEST_F(StaDesignTest, PropertyGetPropertyLibertyLibrary) { Properties &props = sta_->properties(); ASSERT_NE(lib_, nullptr); PropertyValue pv = props.getProperty(lib_, "name"); (void)pv; } // --- Property: getProperty on LibertyCell --- TEST_F(StaDesignTest, PropertyGetPropertyLibertyCell) { Properties &props = sta_->properties(); LibertyCell *buf = lib_->findLibertyCell("BUF_X1"); ASSERT_NE(buf, nullptr); PropertyValue pv = props.getProperty(buf, "name"); (void)pv; } // --- findPathEnds with unconstrained --- TEST_F(StaDesignTest, FindPathEndsUnconstrained) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, true, // unconstrained nullptr, // corner (all) MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); (void)ends; }() )); } // --- findPathEnds with hold --- TEST_F(StaDesignTest, FindPathEndsHold) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::min(), 10, 1, false, false, -INF, INF, false, nullptr, false, true, false, false, false, false); (void)ends; }() )); } // --- Search: findAllArrivals --- TEST_F(StaDesignTest, SearchFindAllArrivals) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->findAllArrivals(); }() )); } // --- Search: findArrivals / findRequireds --- TEST_F(StaDesignTest, SearchFindArrivalsRequireds) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->findArrivals(); search->findRequireds(); }() )); } // --- Search: clocks for vertex --- TEST_F(StaDesignTest, SearchClocksVertex) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Vertex *v = findVertex("r1/CK"); if (v) { ClockSet clks = search->clocks(v); (void)clks; } }() )); } // --- Search: wnsSlack --- TEST_F(StaDesignTest, SearchWnsSlack) { Search *search = sta_->search(); Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Slack slk = search->wnsSlack(v, 0); (void)slk; } // --- Search: isEndpoint --- TEST_F(StaDesignTest, SearchIsEndpoint) { Search *search = sta_->search(); Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); bool is_ep = search->isEndpoint(v); (void)is_ep; } // --- reportParasiticAnnotation --- TEST_F(StaDesignTest, ReportParasiticAnnotation) { ASSERT_NO_THROW(( [&](){ sta_->reportParasiticAnnotation(false, sta_->cmdCorner()); }() )); } // --- findClkDelays --- TEST_F(StaDesignTest, FindClkDelays) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ClkDelays delays = sta_->findClkDelays(clk, false); (void)delays; } // --- reportClkLatency --- TEST_F(StaDesignTest, ReportClkLatency) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ConstClockSeq clks; clks.push_back(clk); sta_->reportClkLatency(clks, nullptr, false, 4); } // --- findWorstClkSkew --- TEST_F(StaDesignTest, FindWorstClkSkew) { ASSERT_NO_THROW(( [&](){ float worst = sta_->findWorstClkSkew(SetupHold::max(), false); (void)worst; }() )); } // --- ReportPath: reportJson on a Path --- TEST_F(StaDesignTest, ReportJsonPath) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { ReportPath *rpt = sta_->reportPath(); rpt->reportJson(path); } } // --- reportEndHeader / reportEndLine --- TEST_F(StaDesignTest, ReportEndHeaderLine) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::endpoint); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); ReportPath *rpt = sta_->reportPath(); rpt->reportEndHeader(); if (!ends.empty()) { rpt->reportEndLine(ends[0]); } }() )); } // --- reportSummaryHeader / reportSummaryLine --- TEST_F(StaDesignTest, ReportSummaryHeaderLine) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::summary); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); ReportPath *rpt = sta_->reportPath(); rpt->reportSummaryHeader(); if (!ends.empty()) { rpt->reportSummaryLine(ends[0]); } }() )); } // --- reportSlackOnlyHeader / reportSlackOnly --- TEST_F(StaDesignTest, ReportSlackOnly) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::slack_only); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); ReportPath *rpt = sta_->reportPath(); rpt->reportSlackOnlyHeader(); if (!ends.empty()) { rpt->reportSlackOnly(ends[0]); } }() )); } // --- Search: reportArrivals --- TEST_F(StaDesignTest, SearchReportArrivals) { Search *search = sta_->search(); Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); search->reportArrivals(v, false); } // --- Search: reportPathCountHistogram --- TEST_F(StaDesignTest, SearchReportPathCountHistogram) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->reportPathCountHistogram(); }() )); } // --- Search: reportTags --- TEST_F(StaDesignTest, SearchReportTags) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->reportTags(); }() )); } // --- Search: reportClkInfos --- TEST_F(StaDesignTest, SearchReportClkInfos) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->reportClkInfos(); }() )); } // --- setReportPathFields --- TEST_F(StaDesignTest, SetReportPathFields) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFields(true, true, true, true, true, true, true); }() )); } // --- setReportPathFieldOrder --- TEST_F(StaDesignTest, SetReportPathFieldOrder) { ASSERT_NO_THROW(( [&](){ StringSeq *fields = new StringSeq; fields->push_back("Fanout"); fields->push_back("Cap"); sta_->setReportPathFieldOrder(fields); }() )); } // --- Search: saveEnumPath --- // (This is complex - need a valid enumerated path. Test existence.) TEST_F(StaDesignTest, SearchSaveEnumPathExists) { auto fn = &Search::saveEnumPath; expectCallablePointerUsable(fn); } // --- vertexPathCount --- TEST_F(StaDesignTest, VertexPathCount) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); int count = sta_->vertexPathCount(v); EXPECT_GE(count, 0); } // --- pathCount --- TEST_F(StaDesignTest, PathCount) { int count = sta_->pathCount(); EXPECT_GE(count, 0); } // --- writeSdc --- TEST_F(StaDesignTest, WriteSdc) { ASSERT_NO_THROW(( [&](){ sta_->writeSdc("/dev/null", false, false, 4, false, true); }() )); } // --- ReportPath: reportFull for PathEndCheck --- TEST_F(StaDesignTest, ReportPathFullPathEnd) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::full); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { // reportPathEnd with full format calls reportFull sta_->reportPathEnd(ends[0]); } }() )); } // --- Search: ensureDownstreamClkPins --- TEST_F(StaDesignTest, SearchEnsureDownstreamClkPins) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->ensureDownstreamClkPins(); }() )); } // --- Genclks --- TEST_F(StaDesignTest, GenclksAccessor) { Search *search = sta_->search(); Genclks *genclks = search->genclks(); EXPECT_NE(genclks, nullptr); } // --- CheckCrpr accessor --- TEST_F(StaDesignTest, CheckCrprAccessor) { Search *search = sta_->search(); CheckCrpr *crpr = search->checkCrpr(); EXPECT_NE(crpr, nullptr); } // --- GatedClk accessor --- TEST_F(StaDesignTest, GatedClkAccessor) { Search *search = sta_->search(); GatedClk *gated = search->gatedClk(); EXPECT_NE(gated, nullptr); } // --- VisitPathEnds accessor --- TEST_F(StaDesignTest, VisitPathEndsAccessor) { Search *search = sta_->search(); VisitPathEnds *vpe = search->visitPathEnds(); EXPECT_NE(vpe, nullptr); } // ============================================================ // Additional R8_ tests for more coverage // ============================================================ // --- Search: worstSlack (triggers WorstSlack methods) --- TEST_F(StaDesignTest, SearchWorstSlackMinMax) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Slack worst; Vertex *worst_vertex = nullptr; search->worstSlack(MinMax::max(), worst, worst_vertex); (void)worst; }() )); } TEST_F(StaDesignTest, SearchWorstSlackCorner) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Corner *corner = sta_->cmdCorner(); Slack worst; Vertex *worst_vertex = nullptr; search->worstSlack(corner, MinMax::max(), worst, worst_vertex); (void)worst; }() )); } // --- Search: totalNegativeSlack --- TEST_F(StaDesignTest, SearchTotalNegativeSlack) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Slack tns = search->totalNegativeSlack(MinMax::max()); (void)tns; }() )); } TEST_F(StaDesignTest, SearchTotalNegativeSlackCorner) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Corner *corner = sta_->cmdCorner(); Slack tns = search->totalNegativeSlack(corner, MinMax::max()); (void)tns; }() )); } // --- Property: getProperty on Edge --- TEST_F(StaDesignTest, PropertyGetEdge) { Properties &props = sta_->properties(); Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); PropertyValue pv = props.getProperty(edge, "full_name"); (void)pv; } } // --- Property: getProperty on Clock --- TEST_F(StaDesignTest, PropertyGetClock) { Properties &props = sta_->properties(); Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); PropertyValue pv = props.getProperty(clk, "name"); (void)pv; } // --- Property: getProperty on LibertyPort --- TEST_F(StaDesignTest, PropertyGetLibertyPort) { Properties &props = sta_->properties(); LibertyCell *buf = lib_->findLibertyCell("BUF_X1"); ASSERT_NE(buf, nullptr); LibertyPort *port = buf->findLibertyPort("A"); ASSERT_NE(port, nullptr); PropertyValue pv = props.getProperty(port, "name"); (void)pv; } // --- Property: getProperty on Port --- TEST_F(StaDesignTest, PropertyGetPort) { Properties &props = sta_->properties(); Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Cell *cell = network->cell(top); ASSERT_NE(cell, nullptr); Port *port = network->findPort(cell, "clk1"); if (port) { PropertyValue pv = props.getProperty(port, "name"); (void)pv; } } // --- Sta: makeInstance / deleteInstance --- TEST_F(StaDesignTest, MakeDeleteInstance) { LibertyCell *buf = lib_->findLibertyCell("BUF_X1"); ASSERT_NE(buf, nullptr); Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Instance *new_inst = sta_->makeInstance("test_buf", buf, top); ASSERT_NE(new_inst, nullptr); sta_->deleteInstance(new_inst); } // --- Sta: makeNet / deleteNet --- TEST_F(StaDesignTest, MakeDeleteNet) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Net *new_net = sta_->makeNet("test_net", top); ASSERT_NE(new_net, nullptr); sta_->deleteNet(new_net); } // --- Sta: connectPin / disconnectPin --- TEST_F(StaDesignTest, ConnectDisconnectPin) { LibertyCell *buf = lib_->findLibertyCell("BUF_X1"); ASSERT_NE(buf, nullptr); LibertyPort *port_a = buf->findLibertyPort("A"); ASSERT_NE(port_a, nullptr); Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Instance *new_inst = sta_->makeInstance("test_buf2", buf, top); ASSERT_NE(new_inst, nullptr); Net *new_net = sta_->makeNet("test_net2", top); ASSERT_NE(new_net, nullptr); sta_->connectPin(new_inst, port_a, new_net); // Find the pin and disconnect Pin *pin = network->findPin(new_inst, "A"); ASSERT_NE(pin, nullptr); sta_->disconnectPin(pin); sta_->deleteNet(new_net); sta_->deleteInstance(new_inst); } // --- Sta: endpointPins --- TEST_F(StaDesignTest, EndpointPins) { PinSet eps = sta_->endpointPins(); EXPECT_GT(eps.size(), 0u); } // --- Sta: startpointPins --- TEST_F(StaDesignTest, StartpointPins) { PinSet sps = sta_->startpointPins(); EXPECT_GT(sps.size(), 0u); } // --- Search: arrivalsValid --- TEST_F(StaDesignTest, SearchArrivalsValidDesign) { Search *search = sta_->search(); bool valid = search->arrivalsValid(); EXPECT_TRUE(valid); } // --- Sta: netSlack --- TEST_F(StaDesignTest, NetSlack) { Network *network = sta_->cmdNetwork(); Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); Net *net = network->net(pin); if (net) { Slack slk = sta_->netSlack(net, MinMax::max()); (void)slk; } } // --- Sta: pinSlack --- TEST_F(StaDesignTest, PinSlackMinMax) { Pin *pin = findPin("r3/D"); ASSERT_NE(pin, nullptr); Slack slk = sta_->pinSlack(pin, MinMax::max()); (void)slk; } TEST_F(StaDesignTest, PinSlackRfMinMax) { Pin *pin = findPin("r3/D"); ASSERT_NE(pin, nullptr); Slack slk = sta_->pinSlack(pin, RiseFall::rise(), MinMax::max()); (void)slk; } // --- Sta: pinArrival --- TEST_F(StaDesignTest, PinArrival) { Pin *pin = findPin("u1/Z"); ASSERT_NE(pin, nullptr); Arrival arr = sta_->pinArrival(pin, RiseFall::rise(), MinMax::max()); (void)arr; } // --- Sta: clocks / clockDomains --- TEST_F(StaDesignTest, ClocksOnPin) { Pin *pin = findPin("clk1"); ASSERT_NE(pin, nullptr); ClockSet clks = sta_->clocks(pin); (void)clks; } TEST_F(StaDesignTest, ClockDomainsOnPin) { Pin *pin = findPin("r1/CK"); ASSERT_NE(pin, nullptr); ClockSet domains = sta_->clockDomains(pin); (void)domains; } // --- Sta: vertexWorstArrivalPath (both overloads) --- TEST_F(StaDesignTest, VertexWorstArrivalPathMinMax) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); (void)path; } TEST_F(StaDesignTest, VertexWorstArrivalPathRf) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, RiseFall::rise(), MinMax::max()); (void)path; } // --- Sta: vertexWorstSlackPath --- TEST_F(StaDesignTest, VertexWorstSlackPath) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstSlackPath(v, MinMax::max()); (void)path; } TEST_F(StaDesignTest, VertexWorstSlackPathRf) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstSlackPath(v, RiseFall::rise(), MinMax::max()); (void)path; } // --- Search: isClock on clock vertex --- TEST_F(StaDesignTest, SearchIsClockVertex) { Search *search = sta_->search(); Vertex *v = findVertex("r1/CK"); ASSERT_NE(v, nullptr); bool is_clk = search->isClock(v); (void)is_clk; } // --- Search: clkPathArrival --- TEST_F(StaDesignTest, SearchClkPathArrival) { Search *search = sta_->search(); // Need a clock path Vertex *v = findVertex("r1/CK"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { Arrival arr = search->clkPathArrival(path); (void)arr; } } // --- Sta: removeDelaySlewAnnotations --- TEST_F(StaDesignTest, RemoveDelaySlewAnnotations) { ASSERT_NO_THROW(( [&](){ sta_->removeDelaySlewAnnotations(); }() )); } // --- Sta: deleteParasitics --- TEST_F(StaDesignTest, DeleteParasitics) { ASSERT_NO_THROW(( [&](){ sta_->deleteParasitics(); }() )); } // --- Sta: constraintsChanged --- TEST_F(StaDesignTest, ConstraintsChanged) { ASSERT_NO_THROW(( [&](){ sta_->constraintsChanged(); }() )); } // --- Sta: networkChanged --- TEST_F(StaDesignTest, NetworkChanged) { ASSERT_NO_THROW(( [&](){ sta_->networkChanged(); }() )); } // --- Search: endpointsInvalid --- TEST_F(StaDesignTest, EndpointsInvalid) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->endpointsInvalid(); }() )); } // --- Search: requiredsInvalid --- TEST_F(StaDesignTest, RequiredsInvalid) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->requiredsInvalid(); }() )); } // --- Search: deleteFilter / filteredEndpoints --- TEST_F(StaDesignTest, SearchDeleteFilter) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); // No filter set, but calling is safe search->deleteFilter(); }() )); } // --- Sta: reportDelayCalc --- TEST_F(StaDesignTest, ReportDelayCalc) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); TimingArcSet *arc_set = edge->timingArcSet(); if (arc_set && !arc_set->arcs().empty()) { Corner *corner = sta_->cmdCorner(); std::string report = sta_->reportDelayCalc( edge, arc_set->arcs()[0], corner, MinMax::max(), 4); (void)report; } } } // --- Sta: arcDelay --- TEST_F(StaDesignTest, ArcDelay) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); TimingArcSet *arc_set = edge->timingArcSet(); if (arc_set && !arc_set->arcs().empty()) { Corner *corner = sta_->cmdCorner(); const DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(MinMax::max()); ArcDelay delay = sta_->arcDelay(edge, arc_set->arcs()[0], dcalc_ap); (void)delay; } } } // --- Sta: arcDelayAnnotated --- TEST_F(StaDesignTest, ArcDelayAnnotated) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); TimingArcSet *arc_set = edge->timingArcSet(); if (arc_set && !arc_set->arcs().empty()) { Corner *corner = sta_->cmdCorner(); DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(MinMax::max()); bool annotated = sta_->arcDelayAnnotated(edge, arc_set->arcs()[0], dcalc_ap); (void)annotated; } } } // --- Sta: findReportPathField --- TEST_F(StaDesignTest, FindReportPathField) { ASSERT_NO_THROW(( [&](){ ReportField *field = sta_->findReportPathField("Fanout"); (void)field; }() )); } // --- Search: arrivalInvalid on a vertex --- TEST_F(StaDesignTest, SearchArrivalInvalid) { Search *search = sta_->search(); Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); search->arrivalInvalid(v); } // --- Search: requiredInvalid on a vertex --- TEST_F(StaDesignTest, SearchRequiredInvalid) { Search *search = sta_->search(); Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); search->requiredInvalid(v); } // --- Search: isSegmentStart --- TEST_F(StaDesignTest, SearchIsSegmentStart) { Search *search = sta_->search(); Pin *pin = findPin("in1"); ASSERT_NE(pin, nullptr); bool is_seg = search->isSegmentStart(pin); (void)is_seg; } // --- Search: isInputArrivalSrchStart --- TEST_F(StaDesignTest, SearchIsInputArrivalSrchStart) { Search *search = sta_->search(); Vertex *v = findVertex("in1"); ASSERT_NE(v, nullptr); bool is_start = search->isInputArrivalSrchStart(v); (void)is_start; } // --- Sta: operatingConditions --- TEST_F(StaDesignTest, OperatingConditions) { ASSERT_NO_THROW(( [&](){ OperatingConditions *op = sta_->operatingConditions(MinMax::max()); (void)op; }() )); } // --- Search: evalPred / searchAdj --- TEST_F(StaDesignTest, SearchEvalPred) { Search *search = sta_->search(); EvalPred *ep = search->evalPred(); EXPECT_NE(ep, nullptr); } TEST_F(StaDesignTest, SearchSearchAdj) { Search *search = sta_->search(); SearchPred *sp = search->searchAdj(); EXPECT_NE(sp, nullptr); } // --- Search: endpointInvalid --- TEST_F(StaDesignTest, SearchEndpointInvalid) { Search *search = sta_->search(); Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); search->endpointInvalid(v); } // --- Search: tnsInvalid --- TEST_F(StaDesignTest, SearchTnsInvalid) { Search *search = sta_->search(); Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); search->tnsInvalid(v); } // --- Sta: unsetTimingDerate --- TEST_F(StaDesignTest, UnsetTimingDerate) { ASSERT_NO_THROW(( [&](){ sta_->unsetTimingDerate(); }() )); } // --- Sta: setAnnotatedSlew --- TEST_F(StaDesignTest, SetAnnotatedSlew) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); Corner *corner = sta_->cmdCorner(); sta_->setAnnotatedSlew(v, corner, MinMaxAll::all(), RiseFallBoth::riseFall(), 1.0e-10f); } // --- Sta: vertexPathIterator with MinMax --- TEST_F(StaDesignTest, VertexPathIteratorMinMax) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); VertexPathIterator *iter = sta_->vertexPathIterator(v, RiseFall::rise(), MinMax::max()); ASSERT_NE(iter, nullptr); // Iterate through paths while (iter->hasNext()) { Path *path = iter->next(); (void)path; } delete iter; } // --- Tag comparison operations (exercised through timing) --- TEST_F(StaDesignTest, TagOperations) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); TagIndex count = search->tagCount(); if (count >= 2) { Tag *t0 = search->tag(0); Tag *t1 = search->tag(1); if (t0 && t1) { // Exercise TagLess TagLess less(sta_); bool result = less(t0, t1); (void)result; // Exercise TagIndexLess TagIndexLess idx_less; result = idx_less(t0, t1); (void)result; // Exercise Tag::equal bool eq = Tag::equal(t0, t1, sta_); (void)eq; } } }() )); } // --- PathEnd::cmp --- TEST_F(StaDesignTest, PathEndCmp) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (ends.size() >= 2) { int cmp = PathEnd::cmp(ends[0], ends[1], sta_); (void)cmp; int cmp_slack = PathEnd::cmpSlack(ends[0], ends[1], sta_); (void)cmp_slack; int cmp_arrival = PathEnd::cmpArrival(ends[0], ends[1], sta_); (void)cmp_arrival; } }() )); } // --- PathEnd: various accessors on specific PathEnd types --- TEST_F(StaDesignTest, PathEndSlackNoCrpr) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { PathEnd *end = ends[0]; Slack slk = end->slack(sta_); (void)slk; Slack slk_no_crpr = end->slackNoCrpr(sta_); (void)slk_no_crpr; ArcDelay margin = end->margin(sta_); (void)margin; Required req = end->requiredTime(sta_); (void)req; Arrival arr = end->dataArrivalTime(sta_); (void)arr; float src_offset = end->sourceClkOffset(sta_); (void)src_offset; const ClockEdge *src_edge = end->sourceClkEdge(sta_); (void)src_edge; Delay src_lat = end->sourceClkLatency(sta_); (void)src_lat; } }() )); } // --- PathEnd: reportShort --- TEST_F(StaDesignTest, PathEndReportShort) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { ReportPath *rpt = sta_->reportPath(); ends[0]->reportShort(rpt); } }() )); } // --- PathEnd: copy --- TEST_F(StaDesignTest, PathEndCopy) { PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { PathEnd *copy = ends[0]->copy(); EXPECT_NE(copy, nullptr); delete copy; } } // --- Search: tagGroup for a vertex --- TEST_F(StaDesignTest, SearchTagGroupForVertex) { Search *search = sta_->search(); Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); TagGroup *tg = search->tagGroup(v); (void)tg; } // --- Sta: findFaninPins / findFanoutPins --- TEST_F(StaDesignTest, FindFaninPins) { Pin *pin = findPin("r3/D"); ASSERT_NE(pin, nullptr); PinSeq to_pins; to_pins.push_back(pin); PinSet fanin = sta_->findFaninPins(&to_pins, false, false, 0, 10, false, false); (void)fanin; } TEST_F(StaDesignTest, FindFanoutPins) { Pin *pin = findPin("r1/Q"); ASSERT_NE(pin, nullptr); PinSeq from_pins; from_pins.push_back(pin); PinSet fanout = sta_->findFanoutPins(&from_pins, false, false, 0, 10, false, false); (void)fanout; } // --- Sta: findFaninInstances / findFanoutInstances --- TEST_F(StaDesignTest, FindFaninInstances) { Pin *pin = findPin("r3/D"); ASSERT_NE(pin, nullptr); PinSeq to_pins; to_pins.push_back(pin); InstanceSet fanin = sta_->findFaninInstances(&to_pins, false, false, 0, 10, false, false); (void)fanin; } // --- Sta: setVoltage --- TEST_F(StaDesignTest, SetVoltage) { ASSERT_NO_THROW(( [&](){ sta_->setVoltage(MinMax::max(), 1.1f); }() )); } // --- Sta: removeConstraints --- TEST_F(StaDesignTest, RemoveConstraints) { ASSERT_NO_THROW(( [&](){ // This is a destructive operation, so call it but re-create constraints after // Just verifying it doesn't crash sta_->removeConstraints(); }() )); } // --- Search: filter --- TEST_F(StaDesignTest, SearchFilter) { Search *search = sta_->search(); FilterPath *filter = search->filter(); // filter should be null since we haven't set one EXPECT_EQ(filter, nullptr); } // --- PathExpanded: path(i) and pathsIndex --- TEST_F(StaDesignTest, PathExpandedPaths) { Vertex *v = findVertex("u2/ZN"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { PathExpanded expanded(path, true, sta_); for (size_t i = 0; i < expanded.size(); i++) { const Path *p = expanded.path(i); (void)p; } } } // --- Sta: setOutputDelay --- TEST_F(StaDesignTest, SetOutputDelay) { Pin *out = findPin("out"); ASSERT_NE(out, nullptr); Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); sta_->setOutputDelay(out, RiseFallBoth::riseFall(), clk, RiseFall::rise(), nullptr, false, false, MinMaxAll::all(), true, 0.0f); } // --- Sta: findPathEnds with setup+hold --- TEST_F(StaDesignTest, FindPathEndsSetupHold) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::all(), 10, 1, false, false, -INF, INF, false, nullptr, true, true, false, false, false, false); (void)ends; }() )); } // --- Sta: findPathEnds unique_pins --- TEST_F(StaDesignTest, FindPathEndsUniquePins) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 3, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); (void)ends; }() )); } // --- Sta: findPathEnds sort_by_slack --- TEST_F(StaDesignTest, FindPathEndsSortBySlack) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, true, nullptr, true, false, false, false, false, false); (void)ends; }() )); } // --- Sta: reportChecks for MinPeriod --- TEST_F(StaDesignTest, ReportChecksMinPeriod) { ASSERT_NO_THROW(( [&](){ MinPeriodCheckSeq &checks = sta_->minPeriodViolations(); sta_->reportChecks(&checks, false); sta_->reportChecks(&checks, true); }() )); } // --- Sta: reportChecks for MaxSkew --- TEST_F(StaDesignTest, ReportChecksMaxSkew) { ASSERT_NO_THROW(( [&](){ MaxSkewCheckSeq &checks = sta_->maxSkewViolations(); sta_->reportChecks(&checks, false); sta_->reportChecks(&checks, true); }() )); } // --- ReportPath: reportPeriodHeaderShort --- TEST_F(StaDesignTest, ReportPeriodHeaderShort) { ASSERT_NO_THROW(( [&](){ ReportPath *rpt = sta_->reportPath(); rpt->reportPeriodHeaderShort(); }() )); } // --- ReportPath: reportMpwHeaderShort --- TEST_F(StaDesignTest, ReportMpwHeaderShort) { ASSERT_NO_THROW(( [&](){ ReportPath *rpt = sta_->reportPath(); rpt->reportMpwHeaderShort(); }() )); } // --- Sta: maxSlewCheck --- TEST_F(StaDesignTest, MaxSlewCheck) { ASSERT_NO_THROW(( [&](){ sta_->checkSlewLimitPreamble(); const Pin *pin = nullptr; Slew slew; float slack, limit; sta_->maxSlewCheck(pin, slew, slack, limit); // pin may be null if no slew limits }() )); } // --- Sta: maxFanoutCheck --- TEST_F(StaDesignTest, MaxFanoutCheck) { ASSERT_NO_THROW(( [&](){ sta_->checkFanoutLimitPreamble(); const Pin *pin = nullptr; float fanout, slack, limit; sta_->maxFanoutCheck(pin, fanout, slack, limit); }() )); } // --- Sta: maxCapacitanceCheck --- TEST_F(StaDesignTest, MaxCapacitanceCheck) { ASSERT_NO_THROW(( [&](){ sta_->checkCapacitanceLimitPreamble(); const Pin *pin = nullptr; float cap, slack, limit; sta_->maxCapacitanceCheck(pin, cap, slack, limit); }() )); } // --- Sta: vertexSlack with RiseFall + MinMax --- TEST_F(StaDesignTest, VertexSlackRfMinMax) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Slack slk = sta_->vertexSlack(v, RiseFall::rise(), MinMax::max()); (void)slk; } // --- Sta: vertexSlew with MinMax only --- TEST_F(StaDesignTest, VertexSlewMinMax) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); Slew slew = sta_->vertexSlew(v, MinMax::max()); (void)slew; } // --- Sta: setReportPathFormat to each format and report --- TEST_F(StaDesignTest, ReportPathEndpointFormat) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::endpoint); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (ends.size() >= 2) { sta_->reportPathEnd(ends[0], nullptr, false); sta_->reportPathEnd(ends[1], ends[0], true); } }() )); } // --- Search: findClkVertexPins --- TEST_F(StaDesignTest, SearchFindClkVertexPins) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); PinSet clk_pins(sta_->cmdNetwork()); search->findClkVertexPins(clk_pins); (void)clk_pins; }() )); } // --- Property: getProperty on PathEnd --- TEST_F(StaDesignTest, PropertyGetPathEnd) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(ends[0], "slack"); (void)pv; } }() )); } // --- Property: getProperty on Path --- TEST_F(StaDesignTest, PropertyGetPath) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(path, "arrival"); (void)pv; } } // --- Property: getProperty on TimingArcSet --- TEST_F(StaDesignTest, PropertyGetTimingArcSet) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); TimingArcSet *arc_set = edge->timingArcSet(); if (arc_set) { Properties &props = sta_->properties(); try { PropertyValue pv = props.getProperty(arc_set, "from_pin"); (void)pv; } catch (...) {} } } } // --- Sta: setParasiticAnalysisPts per_corner --- TEST_F(StaDesignTest, SetParasiticAnalysisPtsPerCorner) { ASSERT_NO_THROW(( [&](){ sta_->setParasiticAnalysisPts(true); }() )); } // ============================================================ // R9_ tests: Comprehensive coverage for search module // ============================================================ // --- FindRegister tests --- TEST_F(StaDesignTest, FindRegisterInstances) { ClockSet *clks = nullptr; InstanceSet reg_insts = sta_->findRegisterInstances(clks, RiseFallBoth::riseFall(), true, false); // Design has 3 DFF_X1 instances EXPECT_GE(reg_insts.size(), 1u); } TEST_F(StaDesignTest, FindRegisterDataPins) { ClockSet *clks = nullptr; PinSet data_pins = sta_->findRegisterDataPins(clks, RiseFallBoth::riseFall(), true, false); EXPECT_GE(data_pins.size(), 1u); } TEST_F(StaDesignTest, FindRegisterClkPins) { ClockSet *clks = nullptr; PinSet clk_pins = sta_->findRegisterClkPins(clks, RiseFallBoth::riseFall(), true, false); EXPECT_GE(clk_pins.size(), 1u); } TEST_F(StaDesignTest, FindRegisterAsyncPins) { ASSERT_NO_THROW(( [&](){ ClockSet *clks = nullptr; PinSet async_pins = sta_->findRegisterAsyncPins(clks, RiseFallBoth::riseFall(), true, false); // May be empty if no async pins (void)async_pins; }() )); } TEST_F(StaDesignTest, FindRegisterOutputPins) { ClockSet *clks = nullptr; PinSet out_pins = sta_->findRegisterOutputPins(clks, RiseFallBoth::riseFall(), true, false); EXPECT_GE(out_pins.size(), 1u); } TEST_F(StaDesignTest, FindRegisterInstancesWithClock) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ClockSet *clks = new ClockSet; clks->insert(clk); InstanceSet reg_insts = sta_->findRegisterInstances(clks, RiseFallBoth::riseFall(), true, false); EXPECT_GE(reg_insts.size(), 1u); } TEST_F(StaDesignTest, FindRegisterDataPinsWithClock) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ClockSet *clks = new ClockSet; clks->insert(clk); PinSet data_pins = sta_->findRegisterDataPins(clks, RiseFallBoth::riseFall(), true, false); EXPECT_GE(data_pins.size(), 1u); } TEST_F(StaDesignTest, FindRegisterClkPinsWithClock) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ClockSet *clks = new ClockSet; clks->insert(clk); PinSet clk_pins = sta_->findRegisterClkPins(clks, RiseFallBoth::riseFall(), true, false); EXPECT_GE(clk_pins.size(), 1u); } TEST_F(StaDesignTest, FindRegisterOutputPinsWithClock) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ClockSet *clks = new ClockSet; clks->insert(clk); PinSet out_pins = sta_->findRegisterOutputPins(clks, RiseFallBoth::riseFall(), true, false); EXPECT_GE(out_pins.size(), 1u); } TEST_F(StaDesignTest, FindRegisterRiseOnly) { ASSERT_NO_THROW(( [&](){ ClockSet *clks = nullptr; PinSet clk_pins = sta_->findRegisterClkPins(clks, RiseFallBoth::rise(), true, false); (void)clk_pins; }() )); } TEST_F(StaDesignTest, FindRegisterFallOnly) { ASSERT_NO_THROW(( [&](){ ClockSet *clks = nullptr; PinSet clk_pins = sta_->findRegisterClkPins(clks, RiseFallBoth::fall(), true, false); (void)clk_pins; }() )); } TEST_F(StaDesignTest, FindRegisterLatches) { ASSERT_NO_THROW(( [&](){ ClockSet *clks = nullptr; InstanceSet insts = sta_->findRegisterInstances(clks, RiseFallBoth::riseFall(), false, true); // No latches in this design (void)insts; }() )); } TEST_F(StaDesignTest, FindRegisterBothEdgeAndLatch) { ClockSet *clks = nullptr; InstanceSet insts = sta_->findRegisterInstances(clks, RiseFallBoth::riseFall(), true, true); EXPECT_GE(insts.size(), 1u); } TEST_F(StaDesignTest, FindRegisterAsyncPinsWithClock) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ClockSet *clks = new ClockSet; clks->insert(clk); PinSet async_pins = sta_->findRegisterAsyncPins(clks, RiseFallBoth::riseFall(), true, false); (void)async_pins; } // --- PathEnd: detailed accessors --- TEST_F(StaDesignTest, PathEndType) { PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { PathEnd::Type t = end->type(); const char *name = end->typeName(); EXPECT_NE(name, nullptr); (void)t; } } TEST_F(StaDesignTest, PathEndCheckRole) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { const TimingRole *role = end->checkRole(sta_); (void)role; const TimingRole *generic_role = end->checkGenericRole(sta_); (void)generic_role; } }() )); } TEST_F(StaDesignTest, PathEndVertex) { PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { Vertex *v = end->vertex(sta_); EXPECT_NE(v, nullptr); } } TEST_F(StaDesignTest, PathEndMinMax) { PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { const MinMax *mm = end->minMax(sta_); EXPECT_NE(mm, nullptr); const EarlyLate *el = end->pathEarlyLate(sta_); EXPECT_NE(el, nullptr); } } TEST_F(StaDesignTest, PathEndTransition) { PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { const RiseFall *rf = end->transition(sta_); EXPECT_NE(rf, nullptr); } } TEST_F(StaDesignTest, PathEndPathAnalysisPt) { PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { PathAnalysisPt *path_ap = end->pathAnalysisPt(sta_); EXPECT_NE(path_ap, nullptr); PathAPIndex idx = end->pathIndex(sta_); (void)idx; } } TEST_F(StaDesignTest, PathEndTargetClkAccessors) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { const Clock *tgt_clk = end->targetClk(sta_); (void)tgt_clk; const ClockEdge *tgt_edge = end->targetClkEdge(sta_); (void)tgt_edge; float tgt_time = end->targetClkTime(sta_); (void)tgt_time; float tgt_offset = end->targetClkOffset(sta_); (void)tgt_offset; Arrival tgt_arr = end->targetClkArrival(sta_); (void)tgt_arr; Delay tgt_delay = end->targetClkDelay(sta_); (void)tgt_delay; Delay tgt_ins = end->targetClkInsertionDelay(sta_); (void)tgt_ins; } }() )); } TEST_F(StaDesignTest, PathEndTargetClkUncertainty) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { float non_inter = end->targetNonInterClkUncertainty(sta_); (void)non_inter; float inter = end->interClkUncertainty(sta_); (void)inter; float total = end->targetClkUncertainty(sta_); (void)total; float mcp_adj = end->targetClkMcpAdjustment(sta_); (void)mcp_adj; } }() )); } TEST_F(StaDesignTest, PathEndClkEarlyLate) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { const EarlyLate *el = end->clkEarlyLate(sta_); (void)el; } }() )); } TEST_F(StaDesignTest, PathEndIsTypePredicates) { PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { bool is_check = end->isCheck(); bool is_uncon = end->isUnconstrained(); bool is_data = end->isDataCheck(); bool is_latch = end->isLatchCheck(); bool is_output = end->isOutputDelay(); bool is_gated = end->isGatedClock(); bool is_pd = end->isPathDelay(); // At least one should be true bool any = is_check || is_uncon || is_data || is_latch || is_output || is_gated || is_pd; EXPECT_TRUE(any); } } TEST_F(StaDesignTest, PathEndCrpr) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { Crpr crpr = end->crpr(sta_); (void)crpr; Crpr check_crpr = end->checkCrpr(sta_); (void)check_crpr; } }() )); } TEST_F(StaDesignTest, PathEndClkSkew) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { Delay skew = end->clkSkew(sta_); (void)skew; } }() )); } TEST_F(StaDesignTest, PathEndBorrow) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { Arrival borrow = end->borrow(sta_); (void)borrow; } }() )); } TEST_F(StaDesignTest, PathEndSourceClkInsertionDelay) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { Delay ins = end->sourceClkInsertionDelay(sta_); (void)ins; } }() )); } TEST_F(StaDesignTest, PathEndTargetClkPath) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { Path *tgt_clk = end->targetClkPath(); (void)tgt_clk; const Path *tgt_clk_const = const_cast(end)->targetClkPath(); (void)tgt_clk_const; } }() )); } TEST_F(StaDesignTest, PathEndTargetClkEndTrans) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { const RiseFall *rf = end->targetClkEndTrans(sta_); (void)rf; } }() )); } TEST_F(StaDesignTest, PathEndExceptPathCmp) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (ends.size() >= 2) { int cmp = ends[0]->exceptPathCmp(ends[1], sta_); (void)cmp; } }() )); } TEST_F(StaDesignTest, PathEndDataArrivalTimeOffset) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { Arrival arr_offset = end->dataArrivalTimeOffset(sta_); (void)arr_offset; } }() )); } TEST_F(StaDesignTest, PathEndRequiredTimeOffset) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { Required req = end->requiredTimeOffset(sta_); (void)req; } }() )); } TEST_F(StaDesignTest, PathEndMultiCyclePath) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { MultiCyclePath *mcp = end->multiCyclePath(); (void)mcp; PathDelay *pd = end->pathDelay(); (void)pd; } }() )); } TEST_F(StaDesignTest, PathEndCmpNoCrpr) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (ends.size() >= 2) { int cmp = PathEnd::cmpNoCrpr(ends[0], ends[1], sta_); (void)cmp; } }() )); } TEST_F(StaDesignTest, PathEndLess2) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (ends.size() >= 2) { bool less = PathEnd::less(ends[0], ends[1], sta_); (void)less; } }() )); } TEST_F(StaDesignTest, PathEndMacroClkTreeDelay) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { float macro_delay = end->macroClkTreeDelay(sta_); (void)macro_delay; } }() )); } // --- PathEnd: hold check --- TEST_F(StaDesignTest, FindPathEndsHold2) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::min(), 10, 1, false, false, -INF, INF, false, nullptr, false, true, false, false, false, false); (void)ends; }() )); } TEST_F(StaDesignTest, FindPathEndsHoldAccessors) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::min(), 10, 1, false, false, -INF, INF, false, nullptr, false, true, false, false, false, false); for (auto *end : ends) { Slack slk = end->slack(sta_); (void)slk; Required req = end->requiredTime(sta_); (void)req; ArcDelay margin = end->margin(sta_); (void)margin; } }() )); } // --- PathEnd: unconstrained --- TEST_F(StaDesignTest, FindPathEndsUnconstrained2) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, true, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (auto *end : ends) { if (end->isUnconstrained()) { end->reportShort(sta_->reportPath()); Required req = end->requiredTime(sta_); (void)req; } } }() )); } // --- ReportPath: various report functions --- TEST_F(StaDesignTest, ReportPathEndHeader) { ASSERT_NO_THROW(( [&](){ sta_->reportPathEndHeader(); }() )); } TEST_F(StaDesignTest, ReportPathEndFooter) { ASSERT_NO_THROW(( [&](){ sta_->reportPathEndFooter(); }() )); } TEST_F(StaDesignTest, ReportPathEnd2) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathEnds2) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); sta_->reportPathEnds(&ends); }() )); } TEST_F(StaDesignTest, ReportPathEndFull) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::full); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathEndFullClkPath) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::full_clock); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathEndFullClkExpanded) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::full_clock_expanded); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathEndShortFormat) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::shorter); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathEndSummary) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::summary); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathEndSlackOnly) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::slack_only); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathEndJson) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFormat(ReportPathFormat::json); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } TEST_F(StaDesignTest, ReportPathFromVertex) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { sta_->reportPath(path); } } TEST_F(StaDesignTest, ReportPathFullWithPrevEnd) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (ends.size() >= 2) { sta_->setReportPathFormat(ReportPathFormat::full); sta_->reportPathEnd(ends[0], nullptr, false); sta_->reportPathEnd(ends[1], ends[0], true); } }() )); } TEST_F(StaDesignTest, ReportPathFieldOrder) { ASSERT_NO_THROW(( [&](){ StringSeq *field_names = new StringSeq; field_names->push_back("fanout"); field_names->push_back("capacitance"); field_names->push_back("slew"); sta_->setReportPathFieldOrder(field_names); }() )); } TEST_F(StaDesignTest, ReportPathFields) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathFields(true, true, true, true, true, true, true); }() )); } TEST_F(StaDesignTest, ReportPathDigits) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathDigits(4); }() )); } TEST_F(StaDesignTest, ReportPathNoSplit) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathNoSplit(true); }() )); } TEST_F(StaDesignTest, ReportPathSigmas) { ASSERT_NO_THROW(( [&](){ sta_->setReportPathSigmas(true); }() )); } TEST_F(StaDesignTest, FindReportPathField2) { ReportField *field = sta_->findReportPathField("fanout"); EXPECT_NE(field, nullptr); field = sta_->findReportPathField("capacitance"); EXPECT_NE(field, nullptr); field = sta_->findReportPathField("slew"); EXPECT_NE(field, nullptr); } TEST_F(StaDesignTest, ReportPathFieldAccessors) { ReportPath *rpt = sta_->reportPath(); ReportField *slew = rpt->fieldSlew(); EXPECT_NE(slew, nullptr); ReportField *fanout = rpt->fieldFanout(); EXPECT_NE(fanout, nullptr); ReportField *cap = rpt->fieldCapacitance(); EXPECT_NE(cap, nullptr); } // --- ReportPath: MinPulseWidth check --- TEST_F(StaDesignTest, MinPulseWidthSlack2) { ASSERT_NO_THROW(( [&](){ MinPulseWidthCheck *check = sta_->minPulseWidthSlack(nullptr); (void)check; }() )); } TEST_F(StaDesignTest, MinPulseWidthViolations2) { ASSERT_NO_THROW(( [&](){ MinPulseWidthCheckSeq &viols = sta_->minPulseWidthViolations(nullptr); (void)viols; }() )); } TEST_F(StaDesignTest, MinPulseWidthChecksAll2) { ASSERT_NO_THROW(( [&](){ MinPulseWidthCheckSeq &checks = sta_->minPulseWidthChecks(nullptr); sta_->reportMpwChecks(&checks, false); sta_->reportMpwChecks(&checks, true); }() )); } TEST_F(StaDesignTest, MinPulseWidthCheckForPin) { ASSERT_NO_THROW(( [&](){ Pin *pin = findPin("r1/CK"); if (pin) { PinSeq pins; pins.push_back(pin); MinPulseWidthCheckSeq &checks = sta_->minPulseWidthChecks(&pins, nullptr); (void)checks; } }() )); } // --- ReportPath: MinPeriod --- TEST_F(StaDesignTest, MinPeriodSlack2) { ASSERT_NO_THROW(( [&](){ MinPeriodCheck *check = sta_->minPeriodSlack(); (void)check; }() )); } TEST_F(StaDesignTest, MinPeriodViolations2) { ASSERT_NO_THROW(( [&](){ MinPeriodCheckSeq &viols = sta_->minPeriodViolations(); (void)viols; }() )); } TEST_F(StaDesignTest, MinPeriodCheckVerbose) { ASSERT_NO_THROW(( [&](){ MinPeriodCheck *check = sta_->minPeriodSlack(); if (check) { sta_->reportCheck(check, false); sta_->reportCheck(check, true); } }() )); } // --- ReportPath: MaxSkew --- TEST_F(StaDesignTest, MaxSkewSlack2) { ASSERT_NO_THROW(( [&](){ MaxSkewCheck *check = sta_->maxSkewSlack(); (void)check; }() )); } TEST_F(StaDesignTest, MaxSkewViolations2) { ASSERT_NO_THROW(( [&](){ MaxSkewCheckSeq &viols = sta_->maxSkewViolations(); (void)viols; }() )); } TEST_F(StaDesignTest, MaxSkewCheckVerbose) { ASSERT_NO_THROW(( [&](){ MaxSkewCheck *check = sta_->maxSkewSlack(); if (check) { sta_->reportCheck(check, false); sta_->reportCheck(check, true); } }() )); } TEST_F(StaDesignTest, ReportMaxSkewHeaderShort) { ASSERT_NO_THROW(( [&](){ ReportPath *rpt = sta_->reportPath(); rpt->reportMaxSkewHeaderShort(); }() )); } // --- ClkSkew / ClkLatency --- TEST_F(StaDesignTest, ReportClkSkewSetup) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ConstClockSeq clks; clks.push_back(clk); sta_->reportClkSkew(clks, nullptr, SetupHold::max(), false, 3); } TEST_F(StaDesignTest, ReportClkSkewHold) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ConstClockSeq clks; clks.push_back(clk); sta_->reportClkSkew(clks, nullptr, SetupHold::min(), false, 3); } TEST_F(StaDesignTest, ReportClkSkewWithInternalLatency) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ConstClockSeq clks; clks.push_back(clk); sta_->reportClkSkew(clks, nullptr, SetupHold::max(), true, 3); } TEST_F(StaDesignTest, FindWorstClkSkew2) { ASSERT_NO_THROW(( [&](){ float worst = sta_->findWorstClkSkew(SetupHold::max(), false); (void)worst; }() )); } TEST_F(StaDesignTest, ReportClkLatency2) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ConstClockSeq clks; clks.push_back(clk); sta_->reportClkLatency(clks, nullptr, false, 3); } TEST_F(StaDesignTest, ReportClkLatencyWithInternal) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ConstClockSeq clks; clks.push_back(clk); sta_->reportClkLatency(clks, nullptr, true, 3); } TEST_F(StaDesignTest, FindClkDelays2) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); ClkDelays delays = sta_->findClkDelays(clk, false); (void)delays; } TEST_F(StaDesignTest, FindClkMinPeriod2) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); float min_period = sta_->findClkMinPeriod(clk, false); (void)min_period; } TEST_F(StaDesignTest, FindClkMinPeriodWithPorts) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); float min_period = sta_->findClkMinPeriod(clk, true); (void)min_period; } // --- Property tests --- TEST_F(StaDesignTest, PropertyGetLibrary) { Network *network = sta_->cmdNetwork(); LibraryIterator *lib_iter = network->libraryIterator(); if (lib_iter->hasNext()) { Library *lib = lib_iter->next(); Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(lib, "name"); EXPECT_EQ(pv.type(), PropertyValue::type_string); } delete lib_iter; } TEST_F(StaDesignTest, PropertyGetCell) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Cell *cell = network->cell(top); if (cell) { Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(cell, "name"); EXPECT_EQ(pv.type(), PropertyValue::type_string); } } TEST_F(StaDesignTest, PropertyGetLibertyLibrary) { Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(lib_, "name"); EXPECT_EQ(pv.type(), PropertyValue::type_string); } TEST_F(StaDesignTest, PropertyGetLibertyCell) { LibertyCell *cell = lib_->findLibertyCell("DFF_X1"); ASSERT_NE(cell, nullptr); Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(cell, "name"); EXPECT_EQ(pv.type(), PropertyValue::type_string); } TEST_F(StaDesignTest, PropertyGetLibertyPort2) { LibertyCell *cell = lib_->findLibertyCell("DFF_X1"); ASSERT_NE(cell, nullptr); LibertyPort *port = cell->findLibertyPort("D"); ASSERT_NE(port, nullptr); Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(port, "name"); EXPECT_EQ(pv.type(), PropertyValue::type_string); } TEST_F(StaDesignTest, PropertyGetInstance) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); InstanceChildIterator *child_iter = network->childIterator(top); if (child_iter->hasNext()) { Instance *inst = child_iter->next(); Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(inst, "name"); EXPECT_EQ(pv.type(), PropertyValue::type_string); } delete child_iter; } TEST_F(StaDesignTest, PropertyGetPin) { Pin *pin = findPin("r1/Q"); ASSERT_NE(pin, nullptr); Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(pin, "name"); EXPECT_EQ(pv.type(), PropertyValue::type_string); } TEST_F(StaDesignTest, PropertyGetPinDirection) { Pin *pin = findPin("r1/Q"); ASSERT_NE(pin, nullptr); Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(pin, "direction"); EXPECT_EQ(pv.type(), PropertyValue::type_string); } TEST_F(StaDesignTest, PropertyGetNet) { Network *network = sta_->cmdNetwork(); Pin *pin = findPin("r1/Q"); ASSERT_NE(pin, nullptr); Net *net = network->net(pin); if (net) { Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(net, "name"); EXPECT_EQ(pv.type(), PropertyValue::type_string); } } TEST_F(StaDesignTest, PropertyGetClock2) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(clk, "name"); EXPECT_EQ(pv.type(), PropertyValue::type_string); } TEST_F(StaDesignTest, PropertyGetClockPeriod) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(clk, "period"); EXPECT_EQ(pv.type(), PropertyValue::type_float); } TEST_F(StaDesignTest, PropertyGetPort2) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Cell *cell = network->cell(top); CellPortIterator *port_iter = network->portIterator(cell); if (port_iter->hasNext()) { Port *port = port_iter->next(); Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(port, "name"); EXPECT_EQ(pv.type(), PropertyValue::type_string); } delete port_iter; } TEST_F(StaDesignTest, PropertyGetEdge2) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(edge, "from_pin"); (void)pv; } } TEST_F(StaDesignTest, PropertyGetPathEndSlack) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(ends[0], "startpoint"); (void)pv; pv = props.getProperty(ends[0], "endpoint"); (void)pv; } }() )); } TEST_F(StaDesignTest, PropertyGetPathEndMore) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { Properties &props = sta_->properties(); PropertyValue pv = props.getProperty(ends[0], "startpoint_clock"); (void)pv; pv = props.getProperty(ends[0], "endpoint_clock"); (void)pv; pv = props.getProperty(ends[0], "points"); (void)pv; } }() )); } // --- Property: pin arrival/slack --- TEST_F(StaDesignTest, PinArrival2) { Pin *pin = findPin("r1/Q"); ASSERT_NE(pin, nullptr); Arrival arr = sta_->pinArrival(pin, RiseFall::rise(), MinMax::max()); (void)arr; } TEST_F(StaDesignTest, PinSlack) { Pin *pin = findPin("r3/D"); ASSERT_NE(pin, nullptr); Slack slk = sta_->pinSlack(pin, MinMax::max()); (void)slk; Slack slk_rf = sta_->pinSlack(pin, RiseFall::rise(), MinMax::max()); (void)slk_rf; } TEST_F(StaDesignTest, NetSlack2) { Network *network = sta_->cmdNetwork(); Pin *pin = findPin("r3/D"); ASSERT_NE(pin, nullptr); Net *net = network->net(pin); if (net) { Slack slk = sta_->netSlack(net, MinMax::max()); (void)slk; } } // --- Search: various methods --- TEST_F(StaDesignTest, SearchIsClock) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Vertex *v = findVertex("r1/CK"); if (v) { bool is_clk = search->isClock(v); (void)is_clk; } }() )); } TEST_F(StaDesignTest, SearchIsGenClkSrc2) { Search *search = sta_->search(); Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); bool is_gen = search->isGenClkSrc(v); (void)is_gen; } TEST_F(StaDesignTest, SearchClocks) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Vertex *v = findVertex("r1/CK"); if (v) { ClockSet clks = search->clocks(v); (void)clks; } }() )); } TEST_F(StaDesignTest, SearchClockDomains) { Search *search = sta_->search(); Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); ClockSet domains = search->clockDomains(v); (void)domains; } TEST_F(StaDesignTest, SearchClockDomainsPin) { Search *search = sta_->search(); Pin *pin = findPin("r1/Q"); ASSERT_NE(pin, nullptr); ClockSet domains = search->clockDomains(pin); (void)domains; } TEST_F(StaDesignTest, SearchClocksPin) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Pin *pin = findPin("r1/CK"); if (pin) { ClockSet clks = search->clocks(pin); (void)clks; } }() )); } TEST_F(StaDesignTest, SearchIsEndpoint2) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Vertex *v_data = findVertex("r3/D"); if (v_data) { bool is_ep = search->isEndpoint(v_data); (void)is_ep; } Vertex *v_out = findVertex("r1/Q"); if (v_out) { bool is_ep = search->isEndpoint(v_out); (void)is_ep; } }() )); } TEST_F(StaDesignTest, SearchHavePathGroups) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); bool have = search->havePathGroups(); (void)have; }() )); } TEST_F(StaDesignTest, SearchFindPathGroup) { Search *search = sta_->search(); Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); PathGroup *pg = search->findPathGroup(clk, MinMax::max()); (void)pg; } TEST_F(StaDesignTest, SearchClkInfoCount) { Search *search = sta_->search(); int count = search->clkInfoCount(); EXPECT_GE(count, 0); } TEST_F(StaDesignTest, SearchTagGroupCount) { Search *search = sta_->search(); TagGroupIndex count = search->tagGroupCount(); EXPECT_GE(count, 0u); } TEST_F(StaDesignTest, SearchTagGroupByIndex) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); TagGroupIndex count = search->tagGroupCount(); if (count > 0) { TagGroup *tg = search->tagGroup(0); (void)tg; } }() )); } TEST_F(StaDesignTest, SearchReportTagGroups2) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->reportTagGroups(); }() )); } TEST_F(StaDesignTest, SearchReportArrivals2) { Search *search = sta_->search(); Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); search->reportArrivals(v, false); search->reportArrivals(v, true); } TEST_F(StaDesignTest, SearchSeedArrival) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Vertex *v = findVertex("in1"); if (v) { search->seedArrival(v); } }() )); } TEST_F(StaDesignTest, SearchPathClkPathArrival2) { Search *search = sta_->search(); Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { Arrival arr = search->pathClkPathArrival(path); (void)arr; } } TEST_F(StaDesignTest, SearchFindClkArrivals) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->findClkArrivals(); }() )); } TEST_F(StaDesignTest, SearchFindRequireds) { Search *search = sta_->search(); search->findRequireds(); EXPECT_TRUE(search->requiredsExist()); } TEST_F(StaDesignTest, SearchRequiredsSeeded) { ASSERT_NO_THROW(( [&](){ sta_->findRequireds(); Search *search = sta_->search(); bool seeded = search->requiredsSeeded(); (void)seeded; }() )); } TEST_F(StaDesignTest, SearchArrivalsAtEndpoints) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); bool exist = search->arrivalsAtEndpointsExist(); (void)exist; }() )); } TEST_F(StaDesignTest, SearchArrivalIterator) { Search *search = sta_->search(); BfsFwdIterator *fwd = search->arrivalIterator(); EXPECT_NE(fwd, nullptr); } TEST_F(StaDesignTest, SearchRequiredIterator) { Search *search = sta_->search(); BfsBkwdIterator *bkwd = search->requiredIterator(); EXPECT_NE(bkwd, nullptr); } TEST_F(StaDesignTest, SearchWnsSlack2) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Vertex *v = findVertex("r3/D"); if (v) { Slack wns = search->wnsSlack(v, 0); (void)wns; } }() )); } TEST_F(StaDesignTest, SearchDeratedDelay) { Search *search = sta_->search(); Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); Corner *corner = sta_->cmdCorner(); const PathAnalysisPt *path_ap = corner->findPathAnalysisPt(MinMax::max()); VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); TimingArcSet *arc_set = edge->timingArcSet(); if (!arc_set->arcs().empty()) { TimingArc *arc = arc_set->arcs()[0]; ArcDelay delay = search->deratedDelay(edge->from(sta_->graph()), arc, edge, false, path_ap); (void)delay; } } } TEST_F(StaDesignTest, SearchMatchesFilter) { Search *search = sta_->search(); Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { bool matches = search->matchesFilter(path, nullptr); (void)matches; } } TEST_F(StaDesignTest, SearchEnsureDownstreamClkPins2) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->ensureDownstreamClkPins(); }() )); } TEST_F(StaDesignTest, SearchVisitPathEnds) { Search *search = sta_->search(); VisitPathEnds *vpe = search->visitPathEnds(); EXPECT_NE(vpe, nullptr); } TEST_F(StaDesignTest, SearchGatedClk) { Search *search = sta_->search(); GatedClk *gc = search->gatedClk(); EXPECT_NE(gc, nullptr); } TEST_F(StaDesignTest, SearchGenclks) { Search *search = sta_->search(); Genclks *gen = search->genclks(); EXPECT_NE(gen, nullptr); } TEST_F(StaDesignTest, SearchCheckCrpr) { Search *search = sta_->search(); CheckCrpr *crpr = search->checkCrpr(); EXPECT_NE(crpr, nullptr); } // --- Sta: various methods --- TEST_F(StaDesignTest, StaIsClock) { ASSERT_NO_THROW(( [&](){ sta_->ensureClkNetwork(); Pin *clk_pin = findPin("r1/CK"); if (clk_pin) { bool is_clk = sta_->isClock(clk_pin); (void)is_clk; } }() )); } TEST_F(StaDesignTest, StaIsClockNet) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); sta_->ensureClkNetwork(); Pin *clk_pin = findPin("r1/CK"); if (clk_pin) { Net *net = network->net(clk_pin); if (net) { bool is_clk = sta_->isClock(net); (void)is_clk; } } }() )); } TEST_F(StaDesignTest, StaIsIdealClock) { ASSERT_NO_THROW(( [&](){ sta_->ensureClkNetwork(); Pin *clk_pin = findPin("r1/CK"); if (clk_pin) { bool is_ideal = sta_->isIdealClock(clk_pin); (void)is_ideal; } }() )); } TEST_F(StaDesignTest, StaIsPropagatedClock) { ASSERT_NO_THROW(( [&](){ sta_->ensureClkNetwork(); Pin *clk_pin = findPin("r1/CK"); if (clk_pin) { bool is_prop = sta_->isPropagatedClock(clk_pin); (void)is_prop; } }() )); } TEST_F(StaDesignTest, StaPins) { Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); sta_->ensureClkNetwork(); const PinSet *pins = sta_->pins(clk); (void)pins; } TEST_F(StaDesignTest, StaStartpointPins) { PinSet startpoints = sta_->startpointPins(); EXPECT_GE(startpoints.size(), 1u); } TEST_F(StaDesignTest, StaEndpointPins) { PinSet endpoints = sta_->endpointPins(); EXPECT_GE(endpoints.size(), 1u); } TEST_F(StaDesignTest, StaEndpoints) { VertexSet *endpoints = sta_->endpoints(); EXPECT_NE(endpoints, nullptr); EXPECT_GE(endpoints->size(), 1u); } TEST_F(StaDesignTest, StaEndpointViolationCount) { ASSERT_NO_THROW(( [&](){ int count = sta_->endpointViolationCount(MinMax::max()); (void)count; }() )); } TEST_F(StaDesignTest, StaTotalNegativeSlack) { ASSERT_NO_THROW(( [&](){ Slack tns = sta_->totalNegativeSlack(MinMax::max()); (void)tns; }() )); } TEST_F(StaDesignTest, StaTotalNegativeSlackCorner) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); Slack tns = sta_->totalNegativeSlack(corner, MinMax::max()); (void)tns; }() )); } TEST_F(StaDesignTest, StaWorstSlack) { ASSERT_NO_THROW(( [&](){ Slack wns = sta_->worstSlack(MinMax::max()); (void)wns; }() )); } TEST_F(StaDesignTest, StaWorstSlackVertex) { ASSERT_NO_THROW(( [&](){ Slack worst_slack; Vertex *worst_vertex; sta_->worstSlack(MinMax::max(), worst_slack, worst_vertex); (void)worst_slack; (void)worst_vertex; }() )); } TEST_F(StaDesignTest, StaWorstSlackCornerVertex) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); Slack worst_slack; Vertex *worst_vertex; sta_->worstSlack(corner, MinMax::max(), worst_slack, worst_vertex); (void)worst_slack; (void)worst_vertex; }() )); } TEST_F(StaDesignTest, StaVertexWorstSlackPath) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstSlackPath(v, MinMax::max()); (void)path; } TEST_F(StaDesignTest, StaVertexWorstSlackPathRf) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstSlackPath(v, RiseFall::rise(), MinMax::max()); (void)path; } TEST_F(StaDesignTest, StaVertexWorstRequiredPath) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstRequiredPath(v, MinMax::max()); (void)path; } TEST_F(StaDesignTest, StaVertexWorstRequiredPathRf) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstRequiredPath(v, RiseFall::rise(), MinMax::max()); (void)path; } TEST_F(StaDesignTest, StaVertexWorstArrivalPathRf) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, RiseFall::rise(), MinMax::max()); (void)path; } TEST_F(StaDesignTest, StaVertexSlacks) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Slack slacks[RiseFall::index_count][MinMax::index_count]; sta_->vertexSlacks(v, slacks); // slacks should be populated } TEST_F(StaDesignTest, StaVertexSlewRfCorner) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); Corner *corner = sta_->cmdCorner(); Slew slew = sta_->vertexSlew(v, RiseFall::rise(), corner, MinMax::max()); (void)slew; } TEST_F(StaDesignTest, StaVertexSlewRfMinMax) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); Slew slew = sta_->vertexSlew(v, RiseFall::rise(), MinMax::max()); (void)slew; } TEST_F(StaDesignTest, StaVertexRequiredRfPathAP) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Corner *corner = sta_->cmdCorner(); const PathAnalysisPt *path_ap = corner->findPathAnalysisPt(MinMax::max()); Required req = sta_->vertexRequired(v, RiseFall::rise(), path_ap); (void)req; } TEST_F(StaDesignTest, StaVertexArrivalClkEdge) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); const ClockEdge *edge = clk->edge(RiseFall::rise()); Corner *corner = sta_->cmdCorner(); const PathAnalysisPt *path_ap = corner->findPathAnalysisPt(MinMax::max()); Arrival arr = sta_->vertexArrival(v, RiseFall::rise(), edge, path_ap, MinMax::max()); (void)arr; } // --- Sta: CheckTiming --- TEST_F(StaDesignTest, CheckTiming2) { ASSERT_NO_THROW(( [&](){ CheckErrorSeq &errors = sta_->checkTiming( true, true, true, true, true, true, true); (void)errors; }() )); } TEST_F(StaDesignTest, CheckTimingNoInputDelay) { ASSERT_NO_THROW(( [&](){ CheckErrorSeq &errors = sta_->checkTiming( true, false, false, false, false, false, false); (void)errors; }() )); } TEST_F(StaDesignTest, CheckTimingNoOutputDelay) { ASSERT_NO_THROW(( [&](){ CheckErrorSeq &errors = sta_->checkTiming( false, true, false, false, false, false, false); (void)errors; }() )); } TEST_F(StaDesignTest, CheckTimingUnconstrained) { ASSERT_NO_THROW(( [&](){ CheckErrorSeq &errors = sta_->checkTiming( false, false, false, false, true, false, false); (void)errors; }() )); } TEST_F(StaDesignTest, CheckTimingLoops) { ASSERT_NO_THROW(( [&](){ CheckErrorSeq &errors = sta_->checkTiming( false, false, false, false, false, true, false); (void)errors; }() )); } // --- Sta: delay calc --- TEST_F(StaDesignTest, ReportDelayCalc2) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); Corner *corner = sta_->cmdCorner(); VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); TimingArcSet *arc_set = edge->timingArcSet(); if (!arc_set->arcs().empty()) { TimingArc *arc = arc_set->arcs()[0]; std::string report = sta_->reportDelayCalc(edge, arc, corner, MinMax::max(), 3); EXPECT_FALSE(report.empty()); } } } // --- Sta: CRPR settings --- TEST_F(StaDesignTest, CrprEnabled) { bool enabled = sta_->crprEnabled(); (void)enabled; sta_->setCrprEnabled(true); EXPECT_TRUE(sta_->crprEnabled()); sta_->setCrprEnabled(false); } TEST_F(StaDesignTest, CrprMode) { CrprMode mode = sta_->crprMode(); (void)mode; sta_->setCrprMode(CrprMode::same_pin); EXPECT_EQ(sta_->crprMode(), CrprMode::same_pin); } // --- Sta: propagateGatedClockEnable --- TEST_F(StaDesignTest, PropagateGatedClockEnable) { bool prop = sta_->propagateGatedClockEnable(); (void)prop; sta_->setPropagateGatedClockEnable(true); EXPECT_TRUE(sta_->propagateGatedClockEnable()); sta_->setPropagateGatedClockEnable(false); } // --- Sta: analysis mode --- TEST_F(StaDesignTest, CmdNamespace) { ASSERT_NO_THROW(( [&](){ CmdNamespace ns = sta_->cmdNamespace(); (void)ns; }() )); } TEST_F(StaDesignTest, CmdCorner) { Corner *corner = sta_->cmdCorner(); EXPECT_NE(corner, nullptr); } TEST_F(StaDesignTest, FindCorner) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->findCorner("default"); (void)corner; }() )); } TEST_F(StaDesignTest, MultiCorner) { ASSERT_NO_THROW(( [&](){ bool multi = sta_->multiCorner(); (void)multi; }() )); } // --- PathExpanded: detailed accessors --- TEST_F(StaDesignTest, PathExpandedSize) { Vertex *v = findVertex("u2/ZN"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { PathExpanded expanded(path, sta_); EXPECT_GT(expanded.size(), 0u); } } TEST_F(StaDesignTest, PathExpandedStartPath) { Vertex *v = findVertex("u2/ZN"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { PathExpanded expanded(path, sta_); if (expanded.size() > 0) { const Path *start = expanded.startPath(); (void)start; } } } // --- Sta: Timing derate --- TEST_F(StaDesignTest, SetTimingDerate) { ASSERT_NO_THROW(( [&](){ sta_->setTimingDerate(TimingDerateType::cell_delay, PathClkOrData::clk, RiseFallBoth::riseFall(), EarlyLate::early(), 0.95f); sta_->unsetTimingDerate(); }() )); } // --- Sta: setArcDelay --- TEST_F(StaDesignTest, SetArcDelay) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); Corner *corner = sta_->cmdCorner(); VertexInEdgeIterator edge_iter(v, sta_->graph()); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); TimingArcSet *arc_set = edge->timingArcSet(); if (!arc_set->arcs().empty()) { TimingArc *arc = arc_set->arcs()[0]; sta_->setArcDelay(edge, arc, corner, MinMaxAll::all(), 1.0e-10f); } } } // --- Sta: removeDelaySlewAnnotations --- TEST_F(StaDesignTest, RemoveDelaySlewAnnotations2) { ASSERT_NO_THROW(( [&](){ sta_->removeDelaySlewAnnotations(); }() )); } // --- Sta: endpoint slack --- TEST_F(StaDesignTest, EndpointSlack2) { ASSERT_NO_THROW(( [&](){ Pin *pin = findPin("r3/D"); if (pin) { Slack slk = sta_->endpointSlack(pin, "clk", MinMax::max()); (void)slk; } }() )); } // --- Sta: delaysInvalid/arrivalsInvalid --- TEST_F(StaDesignTest, DelaysInvalid2) { ASSERT_NO_THROW(( [&](){ sta_->delaysInvalid(); sta_->updateTiming(true); }() )); } TEST_F(StaDesignTest, ArrivalsInvalid2) { ASSERT_NO_THROW(( [&](){ sta_->arrivalsInvalid(); sta_->updateTiming(true); }() )); } TEST_F(StaDesignTest, DelaysInvalidFrom) { ASSERT_NO_THROW(( [&](){ Pin *pin = findPin("u1/Z"); if (pin) { sta_->delaysInvalidFrom(pin); } }() )); } TEST_F(StaDesignTest, DelaysInvalidFromFanin) { ASSERT_NO_THROW(( [&](){ Pin *pin = findPin("r3/D"); if (pin) { sta_->delaysInvalidFromFanin(pin); } }() )); } // --- Sta: searchPreamble --- TEST_F(StaDesignTest, SearchPreamble) { ASSERT_NO_THROW(( [&](){ sta_->searchPreamble(); }() )); } // --- Sta: ensureLevelized / ensureGraph / ensureLinked --- TEST_F(StaDesignTest, EnsureLevelized) { ASSERT_NO_THROW(( [&](){ sta_->ensureLevelized(); }() )); } TEST_F(StaDesignTest, EnsureGraph) { Graph *graph = sta_->ensureGraph(); EXPECT_NE(graph, nullptr); } TEST_F(StaDesignTest, EnsureLinked) { Network *network = sta_->ensureLinked(); EXPECT_NE(network, nullptr); } TEST_F(StaDesignTest, EnsureLibLinked) { Network *network = sta_->ensureLibLinked(); EXPECT_NE(network, nullptr); } TEST_F(StaDesignTest, EnsureClkArrivals) { ASSERT_NO_THROW(( [&](){ sta_->ensureClkArrivals(); }() )); } TEST_F(StaDesignTest, EnsureClkNetwork) { ASSERT_NO_THROW(( [&](){ sta_->ensureClkNetwork(); }() )); } // --- Sta: findDelays --- TEST_F(StaDesignTest, FindDelays2) { ASSERT_NO_THROW(( [&](){ sta_->findDelays(); }() )); } // --- Sta: setVoltage for net --- TEST_F(StaDesignTest, SetVoltageNet) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Pin *pin = findPin("r1/Q"); if (pin) { Net *net = network->net(pin); if (net) { sta_->setVoltage(net, MinMax::max(), 1.1f); } } }() )); } // --- Sta: PVT --- TEST_F(StaDesignTest, GetPvt) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); const Pvt *pvt = sta_->pvt(top, MinMax::max()); (void)pvt; }() )); } // --- ClkNetwork --- TEST_F(StaDesignTest, ClkNetworkIsClock) { ASSERT_NO_THROW(( [&](){ ClkNetwork *clk_network = sta_->search()->clkNetwork(); if (clk_network) { Pin *clk_pin = findPin("r1/CK"); if (clk_pin) { bool is_clk = clk_network->isClock(clk_pin); (void)is_clk; } } }() )); } // --- Tag operations --- TEST_F(StaDesignTest, TagPathAPIndex) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); TagIndex count = search->tagCount(); if (count > 0) { Tag *t = search->tag(0); if (t) { PathAPIndex idx = t->pathAPIndex(); (void)idx; } } }() )); } TEST_F(StaDesignTest, TagCmp) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); TagIndex count = search->tagCount(); if (count >= 2) { Tag *t0 = search->tag(0); Tag *t1 = search->tag(1); if (t0 && t1) { int cmp = Tag::cmp(t0, t1, sta_); (void)cmp; int mcmp = Tag::matchCmp(t0, t1, true, sta_); (void)mcmp; } } }() )); } TEST_F(StaDesignTest, TagHash) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); TagIndex count = search->tagCount(); if (count > 0) { Tag *t = search->tag(0); if (t) { size_t h = t->hash(true, sta_); (void)h; size_t mh = t->matchHash(true, sta_); (void)mh; } } }() )); } TEST_F(StaDesignTest, TagMatchHashEqual) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); TagIndex count = search->tagCount(); if (count >= 2) { Tag *t0 = search->tag(0); Tag *t1 = search->tag(1); if (t0 && t1) { TagMatchHash hash(true, sta_); size_t h0 = hash(t0); size_t h1 = hash(t1); (void)h0; (void)h1; TagMatchEqual eq(true, sta_); bool result = eq(t0, t1); (void)result; } } }() )); } // --- ClkInfo operations --- TEST_F(StaDesignTest, ClkInfoAccessors2) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); VertexPathIterator *iter = sta_->vertexPathIterator(v, RiseFall::rise(), MinMax::max()); if (iter && iter->hasNext()) { Path *path = iter->next(); Tag *tag = path->tag(sta_); if (tag) { const ClkInfo *clk_info = tag->clkInfo(); if (clk_info) { const ClockEdge *edge = clk_info->clkEdge(); (void)edge; bool prop = clk_info->isPropagated(); (void)prop; bool gen = clk_info->isGenClkSrcPath(); (void)gen; PathAPIndex idx = clk_info->pathAPIndex(); (void)idx; } } } delete iter; } // --- Sim --- TEST_F(StaDesignTest, SimLogicValue2) { Sim *sim = sta_->sim(); ASSERT_NE(sim, nullptr); Pin *pin = findPin("r1/D"); if (pin) { LogicValue val = sim->logicValue(pin); (void)val; } } TEST_F(StaDesignTest, SimLogicZeroOne) { Sim *sim = sta_->sim(); ASSERT_NE(sim, nullptr); Pin *pin = findPin("r1/D"); if (pin) { bool zeroone = sim->logicZeroOne(pin); (void)zeroone; } } TEST_F(StaDesignTest, SimEnsureConstantsPropagated) { Sim *sim = sta_->sim(); ASSERT_NE(sim, nullptr); sim->ensureConstantsPropagated(); } TEST_F(StaDesignTest, SimFunctionSense) { Sim *sim = sta_->sim(); ASSERT_NE(sim, nullptr); // Use u1 (BUF_X1) which has known input A and output Z Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Instance *u1 = network->findChild(top, "u1"); if (u1) { Pin *from_pin = findPin("u1/A"); Pin *to_pin = findPin("u1/Z"); if (from_pin && to_pin) { TimingSense sense = sim->functionSense(u1, from_pin, to_pin); (void)sense; } } } // --- Levelize --- TEST_F(StaDesignTest, LevelizeMaxLevel) { Levelize *lev = sta_->levelize(); ASSERT_NE(lev, nullptr); Level max_level = lev->maxLevel(); EXPECT_GT(max_level, 0); } TEST_F(StaDesignTest, LevelizeLevelized) { Levelize *lev = sta_->levelize(); ASSERT_NE(lev, nullptr); bool is_levelized = lev->levelized(); EXPECT_TRUE(is_levelized); } // --- Sta: makeParasiticNetwork --- TEST_F(StaDesignTest, MakeParasiticNetwork) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Pin *pin = findPin("r1/Q"); if (pin) { Net *net = network->net(pin); if (net) { Corner *corner = sta_->cmdCorner(); const ParasiticAnalysisPt *ap = corner->findParasiticAnalysisPt(MinMax::max()); if (ap) { Parasitic *parasitic = sta_->makeParasiticNetwork(net, false, ap); (void)parasitic; } } } }() )); } // --- Path: operations on actual paths --- TEST_F(StaDesignTest, PathIsNull) { Path path; EXPECT_TRUE(path.isNull()); } TEST_F(StaDesignTest, PathFromVertex) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { Vertex *pv = path->vertex(sta_); EXPECT_NE(pv, nullptr); Tag *tag = path->tag(sta_); (void)tag; Arrival arr = path->arrival(); (void)arr; const RiseFall *rf = path->transition(sta_); EXPECT_NE(rf, nullptr); const MinMax *mm = path->minMax(sta_); EXPECT_NE(mm, nullptr); } } TEST_F(StaDesignTest, PathPrevPath) { Vertex *v = findVertex("u2/ZN"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && !path->isNull()) { Path *prev = path->prevPath(); (void)prev; TimingArc *prev_arc = path->prevArc(sta_); (void)prev_arc; Edge *prev_edge = path->prevEdge(sta_); (void)prev_edge; } } // --- PathExpanded: with clk path --- TEST_F(StaDesignTest, PathExpandedWithClk) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { Path *path = ends[0]->path(); if (path && !path->isNull()) { PathExpanded expanded(path, true, sta_); for (size_t i = 0; i < expanded.size(); i++) { const Path *p = expanded.path(i); (void)p; } } } }() )); } // --- GatedClk --- TEST_F(StaDesignTest, GatedClkIsEnable) { ASSERT_NO_THROW(( [&](){ GatedClk *gc = sta_->search()->gatedClk(); Vertex *v = findVertex("u1/Z"); if (v) { bool is_enable = gc->isGatedClkEnable(v); (void)is_enable; } }() )); } TEST_F(StaDesignTest, GatedClkEnables) { ASSERT_NO_THROW(( [&](){ GatedClk *gc = sta_->search()->gatedClk(); Vertex *v = findVertex("r1/CK"); if (v) { PinSet enables(sta_->network()); gc->gatedClkEnables(v, enables); (void)enables; } }() )); } // --- Genclks --- TEST_F(StaDesignTest, GenclksClear) { ASSERT_NO_THROW(( [&](){ Genclks *gen = sta_->search()->genclks(); // Clear should not crash on design without generated clocks gen->clear(); }() )); } // --- Search: visitStartpoints/visitEndpoints --- TEST_F(StaDesignTest, SearchVisitEndpoints2) { Search *search = sta_->search(); PinSet pins(sta_->network()); VertexPinCollector collector(pins); search->visitEndpoints(&collector); EXPECT_GE(pins.size(), 1u); } TEST_F(StaDesignTest, SearchVisitStartpoints2) { Search *search = sta_->search(); PinSet pins(sta_->network()); VertexPinCollector collector(pins); search->visitStartpoints(&collector); EXPECT_GE(pins.size(), 1u); } // --- PathGroup --- TEST_F(StaDesignTest, PathGroupFindByName) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); // After findPathEnds, path groups should exist PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { PathGroup *pg = ends[0]->pathGroup(); if (pg) { const char *name = pg->name(); (void)name; } } }() )); } TEST_F(StaDesignTest, PathGroups) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { Search *search = sta_->search(); PathGroupSeq groups = search->pathGroups(ends[0]); (void)groups; } }() )); } // --- VertexPathIterator with PathAnalysisPt --- TEST_F(StaDesignTest, VertexPathIteratorPathAP) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Corner *corner = sta_->cmdCorner(); const PathAnalysisPt *path_ap = corner->findPathAnalysisPt(MinMax::max()); VertexPathIterator *iter = sta_->vertexPathIterator(v, RiseFall::rise(), path_ap); ASSERT_NE(iter, nullptr); while (iter->hasNext()) { Path *path = iter->next(); (void)path; } delete iter; } // --- Sta: setOutputDelay and find unconstrained --- TEST_F(StaDesignTest, SetOutputDelayAndCheck) { Pin *out = findPin("out"); ASSERT_NE(out, nullptr); Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); sta_->setOutputDelay(out, RiseFallBoth::riseFall(), clk, RiseFall::rise(), nullptr, false, false, MinMaxAll::all(), true, 2.0f); sta_->updateTiming(true); // Now find paths to output PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, nullptr, true, false, false, false, false, false); // Should have paths including output delay (void)ends; } // --- Sta: unique_edges findPathEnds --- TEST_F(StaDesignTest, FindPathEndsUniqueEdges) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, nullptr, MinMaxAll::max(), 10, 3, false, true, -INF, INF, false, nullptr, true, false, false, false, false, false); (void)ends; }() )); } // --- Sta: corner path analysis pt --- TEST_F(StaDesignTest, CornerPathAnalysisPt) { Corner *corner = sta_->cmdCorner(); ASSERT_NE(corner, nullptr); const PathAnalysisPt *max_ap = corner->findPathAnalysisPt(MinMax::max()); EXPECT_NE(max_ap, nullptr); const PathAnalysisPt *min_ap = corner->findPathAnalysisPt(MinMax::min()); EXPECT_NE(min_ap, nullptr); } // --- Sta: incrementalDelayTolerance --- TEST_F(StaDesignTest, IncrementalDelayTolerance) { ASSERT_NO_THROW(( [&](){ sta_->setIncrementalDelayTolerance(0.01f); }() )); } // --- Sta: pocvEnabled --- TEST_F(StaDesignTest, PocvEnabled) { ASSERT_NO_THROW(( [&](){ bool enabled = sta_->pocvEnabled(); (void)enabled; }() )); } // --- Sta: makePiElmore --- TEST_F(StaDesignTest, MakePiElmore) { Pin *pin = findPin("r1/Q"); ASSERT_NE(pin, nullptr); sta_->makePiElmore(pin, RiseFall::rise(), MinMaxAll::all(), 1.0e-15f, 100.0f, 1.0e-15f); float c2, rpi, c1; bool exists; sta_->findPiElmore(pin, RiseFall::rise(), MinMax::max(), c2, rpi, c1, exists); if (exists) { EXPECT_GT(c2, 0.0f); } } // --- Sta: deleteParasitics --- TEST_F(StaDesignTest, DeleteParasitics2) { ASSERT_NO_THROW(( [&](){ sta_->deleteParasitics(); }() )); } // --- Search: arrivalsChanged --- TEST_F(StaDesignTest, SearchArrivalsVertexData) { // Verify arrivals exist through the Sta API Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Arrival arr = sta_->vertexArrival(v, MinMax::max()); (void)arr; Required req = sta_->vertexRequired(v, MinMax::max()); (void)req; } // --- Sta: activity --- TEST_F(StaDesignTest, PinActivity) { Pin *pin = findPin("r1/Q"); ASSERT_NE(pin, nullptr); PwrActivity act = sta_->activity(pin); (void)act; } // --- Search: isInputArrivalSrchStart --- TEST_F(StaDesignTest, IsInputArrivalSrchStart) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Vertex *v = findVertex("in1"); if (v) { bool is_start = search->isInputArrivalSrchStart(v); (void)is_start; } }() )); } TEST_F(StaDesignTest, IsSegmentStart) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Pin *pin = findPin("in1"); if (pin) { bool is_seg = search->isSegmentStart(pin); (void)is_seg; } }() )); } // --- Search: clockInsertion --- TEST_F(StaDesignTest, ClockInsertion) { Search *search = sta_->search(); Clock *clk = sta_->sdc()->findClock("clk"); ASSERT_NE(clk, nullptr); Pin *pin = findPin("r1/CK"); if (pin) { Corner *corner = sta_->cmdCorner(); const PathAnalysisPt *path_ap = corner->findPathAnalysisPt(MinMax::max()); Arrival ins = search->clockInsertion(clk, pin, RiseFall::rise(), MinMax::max(), EarlyLate::late(), path_ap); (void)ins; } } // --- Levelize: edges --- TEST_F(StaDesignTest, LevelizeLevelsValid) { Levelize *lev = sta_->levelize(); ASSERT_NE(lev, nullptr); bool valid = lev->levelized(); EXPECT_TRUE(valid); } // --- Search: reporting --- TEST_F(StaDesignTest, SearchReportPathCountHistogram2) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->reportPathCountHistogram(); }() )); } TEST_F(StaDesignTest, SearchReportTags2) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->reportTags(); }() )); } TEST_F(StaDesignTest, SearchReportClkInfos2) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->reportClkInfos(); }() )); } // --- Search: filteredEndpoints --- TEST_F(StaDesignTest, SearchFilteredEndpoints) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); VertexSeq endpoints = search->filteredEndpoints(); (void)endpoints; }() )); } // --- Sta: findFanoutInstances --- TEST_F(StaDesignTest, FindFanoutInstances) { Pin *pin = findPin("r1/Q"); ASSERT_NE(pin, nullptr); PinSeq from_pins; from_pins.push_back(pin); InstanceSet fanout = sta_->findFanoutInstances(&from_pins, false, false, 0, 10, false, false); EXPECT_GE(fanout.size(), 1u); } // --- Sta: search endpointsInvalid --- TEST_F(StaDesignTest, EndpointsInvalid2) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->endpointsInvalid(); }() )); } // --- Sta: constraintsChanged --- TEST_F(StaDesignTest, ConstraintsChanged2) { ASSERT_NO_THROW(( [&](){ sta_->constraintsChanged(); }() )); } // --- Sta: networkChanged --- TEST_F(StaDesignTest, NetworkChanged2) { ASSERT_NO_THROW(( [&](){ sta_->networkChanged(); }() )); } // --- Sta: clkPinsInvalid --- TEST_F(StaDesignTest, ClkPinsInvalid) { ASSERT_NO_THROW(( [&](){ sta_->clkPinsInvalid(); }() )); } // --- PropertyValue constructors and types --- TEST_F(StaDesignTest, PropertyValueConstructors) { PropertyValue pv1; EXPECT_EQ(pv1.type(), PropertyValue::type_none); PropertyValue pv2("test"); EXPECT_EQ(pv2.type(), PropertyValue::type_string); EXPECT_STREQ(pv2.stringValue(), "test"); PropertyValue pv3(true); EXPECT_EQ(pv3.type(), PropertyValue::type_bool); EXPECT_TRUE(pv3.boolValue()); // Copy constructor PropertyValue pv4(pv2); EXPECT_EQ(pv4.type(), PropertyValue::type_string); // Move constructor PropertyValue pv5(std::move(pv3)); EXPECT_EQ(pv5.type(), PropertyValue::type_bool); } // --- Sta: setPvt --- TEST_F(StaDesignTest, SetPvt) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); sta_->setPvt(top, MinMaxAll::all(), 1.0f, 1.1f, 25.0f); const Pvt *pvt = sta_->pvt(top, MinMax::max()); (void)pvt; }() )); } // --- Search: propagateClkSense --- TEST_F(StaDesignTest, SearchClkPathArrival2) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Vertex *v = findVertex("r1/CK"); if (v) { VertexPathIterator *iter = sta_->vertexPathIterator(v, RiseFall::rise(), MinMax::max()); if (iter && iter->hasNext()) { Path *path = iter->next(); Arrival arr = search->clkPathArrival(path); (void)arr; } delete iter; } }() )); } // ============================================================ // R10_ tests: Additional coverage for search module uncovered functions // ============================================================ // --- Properties: pinArrival, pinSlack via Properties --- TEST_F(StaDesignTest, PropertyPinArrivalRf) { ASSERT_NO_THROW(( [&](){ // Cover Properties::pinArrival(pin, rf, min_max) Properties &props = sta_->properties(); Pin *pin = findPin("r1/D"); if (pin) { PropertyValue pv = props.getProperty(pin, "arrival_max_rise"); (void)pv; PropertyValue pv2 = props.getProperty(pin, "arrival_max_fall"); (void)pv2; } }() )); } TEST_F(StaDesignTest, PropertyPinSlackMinMax) { ASSERT_NO_THROW(( [&](){ // Cover Properties::pinSlack(pin, min_max) Properties &props = sta_->properties(); Pin *pin = findPin("r1/D"); if (pin) { PropertyValue pv = props.getProperty(pin, "slack_max"); (void)pv; PropertyValue pv2 = props.getProperty(pin, "slack_min"); (void)pv2; } }() )); } TEST_F(StaDesignTest, PropertyPinSlackRf) { ASSERT_NO_THROW(( [&](){ // Cover Properties::pinSlack(pin, rf, min_max) Properties &props = sta_->properties(); Pin *pin = findPin("r1/D"); if (pin) { PropertyValue pv = props.getProperty(pin, "slack_max_rise"); (void)pv; PropertyValue pv2 = props.getProperty(pin, "slack_min_fall"); (void)pv2; } }() )); } TEST_F(StaDesignTest, PropertyDelayPropertyValue) { ASSERT_NO_THROW(( [&](){ // Cover Properties::delayPropertyValue, resistancePropertyValue, capacitancePropertyValue Properties &props = sta_->properties(); Graph *graph = sta_->graph(); Vertex *v = findVertex("r1/D"); if (v && graph) { VertexInEdgeIterator in_iter(v, graph); if (in_iter.hasNext()) { Edge *edge = in_iter.next(); PropertyValue pv = props.getProperty(edge, "delay_max_rise"); (void)pv; } } }() )); } TEST_F(StaDesignTest, PropertyGetCellAndLibrary) { ASSERT_NO_THROW(( [&](){ // Cover PropertyRegistry::getProperty, PropertyRegistry::getProperty Properties &props = sta_->properties(); Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Cell *cell = network->cell(top); if (cell) { PropertyValue pv = props.getProperty(cell, "name"); (void)pv; } LibertyLibrary *lib = network->defaultLibertyLibrary(); if (lib) { PropertyValue pv = props.getProperty(lib, "name"); (void)pv; } }() )); } TEST_F(StaDesignTest, PropertyUnknownException) { // Cover PropertyUnknown constructor and what() Properties &props = sta_->properties(); Pin *pin = findPin("r1/D"); if (pin) { try { PropertyValue pv = props.getProperty(pin, "nonexistent_property_xyz123"); (void)pv; } catch (const std::exception &e) { const char *msg = e.what(); EXPECT_NE(msg, nullptr); } } } TEST_F(StaDesignTest, PropertyTypeWrongException) { // Cover PropertyTypeWrong constructor and what() PropertyValue pv("test_string"); EXPECT_EQ(pv.type(), PropertyValue::type_string); try { float val = pv.floatValue(); (void)val; } catch (const std::exception &e) { const char *msg = e.what(); EXPECT_NE(msg, nullptr); } } // --- CheckTiming: hasClkedCheck, clear --- TEST_F(StaDesignTest, CheckTimingClear) { ASSERT_NO_THROW(( [&](){ CheckErrorSeq &errors = sta_->checkTiming(true, true, true, true, true, true, true); (void)errors; CheckErrorSeq &errors2 = sta_->checkTiming(true, true, true, true, true, true, true); (void)errors2; }() )); } // --- BfsIterator: init, destructor, enqueueAdjacentVertices --- TEST_F(StaDesignTest, BfsIterator) { ASSERT_NO_THROW(( [&](){ Graph *graph = sta_->graph(); if (graph) { SearchPred1 pred(sta_); BfsFwdIterator bfs(BfsIndex::other, &pred, sta_); Vertex *v = findVertex("r1/Q"); if (v) { bfs.enqueue(v); while (bfs.hasNext()) { Vertex *vert = bfs.next(); (void)vert; break; } } } }() )); } // --- ClkInfo accessors --- TEST_F(StaDesignTest, ClkInfoAccessors3) { ASSERT_NO_THROW(( [&](){ Pin *clk_pin = findPin("r1/CK"); if (clk_pin) { Vertex *v = findVertex("r1/CK"); if (v) { VertexPathIterator *iter = sta_->vertexPathIterator(v, RiseFall::rise(), MinMax::max()); if (iter && iter->hasNext()) { Path *path = iter->next(); Tag *tag = path->tag(sta_); if (tag) { const ClkInfo *clk_info = tag->clkInfo(); if (clk_info) { const ClockEdge *edge = clk_info->clkEdge(); (void)edge; bool prop = clk_info->isPropagated(); (void)prop; bool gen = clk_info->isGenClkSrcPath(); (void)gen; } } } delete iter; } } }() )); } // --- Tag: pathAPIndex --- TEST_F(StaDesignTest, TagPathAPIndex2) { Vertex *v = findVertex("r1/D"); if (v) { VertexPathIterator *iter = sta_->vertexPathIterator(v, RiseFall::rise(), MinMax::max()); if (iter && iter->hasNext()) { Path *path = iter->next(); Tag *tag = path->tag(sta_); if (tag) { int ap_idx = tag->pathAPIndex(); EXPECT_GE(ap_idx, 0); } } delete iter; } } // --- Path: tagIndex, prevVertex --- TEST_F(StaDesignTest, PathAccessors) { ASSERT_NO_THROW(( [&](){ Vertex *v = findVertex("r1/D"); if (v) { VertexPathIterator *iter = sta_->vertexPathIterator(v, RiseFall::rise(), MinMax::max()); if (iter && iter->hasNext()) { Path *path = iter->next(); TagIndex ti = path->tagIndex(sta_); (void)ti; Vertex *prev = path->prevVertex(sta_); (void)prev; } delete iter; } }() )); } // --- PathGroup constructor --- TEST_F(StaDesignTest, PathGroupConstructor) { Search *search = sta_->search(); if (search) { PathGroup *pg = search->findPathGroup("clk", MinMax::max()); if (pg) { EXPECT_NE(pg, nullptr); } } } // --- PathLess --- TEST_F(StaDesignTest, PathLessComparator) { Vertex *v = findVertex("r1/D"); if (v) { VertexPathIterator *iter = sta_->vertexPathIterator(v, RiseFall::rise(), MinMax::max()); if (iter && iter->hasNext()) { Path *p1 = iter->next(); PathLess less(sta_); bool result = less(p1, p1); EXPECT_FALSE(result); } delete iter; } } // --- PathEnd methods on real path ends --- TEST_F(StaDesignTest, PathEndTargetClkMethods) { ASSERT_NO_THROW(( [&](){ CornerSeq &corners = sta_->corners()->corners(); Corner *corner = corners[0]; PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (PathEnd *pe : ends) { const Clock *tgt_clk = pe->targetClk(sta_); (void)tgt_clk; Arrival tgt_arr = pe->targetClkArrival(sta_); (void)tgt_arr; Delay tgt_delay = pe->targetClkDelay(sta_); (void)tgt_delay; Delay tgt_ins = pe->targetClkInsertionDelay(sta_); (void)tgt_ins; float non_inter = pe->targetNonInterClkUncertainty(sta_); (void)non_inter; float inter = pe->interClkUncertainty(sta_); (void)inter; float tgt_unc = pe->targetClkUncertainty(sta_); (void)tgt_unc; float mcp_adj = pe->targetClkMcpAdjustment(sta_); (void)mcp_adj; } }() )); } TEST_F(StaDesignTest, PathEndUnconstrainedMethods) { ASSERT_NO_THROW(( [&](){ CornerSeq &corners = sta_->corners()->corners(); Corner *corner = corners[0]; PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, true, corner, MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (PathEnd *pe : ends) { if (pe->isUnconstrained()) { Required req = pe->requiredTime(sta_); (void)req; break; } } }() )); } // --- PathEndPathDelay methods --- TEST_F(StaDesignTest, PathEndPathDelay) { sta_->makePathDelay(nullptr, nullptr, nullptr, MinMax::max(), false, false, 5.0, nullptr); sta_->updateTiming(true); CornerSeq &corners = sta_->corners()->corners(); Corner *corner = corners[0]; PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 10, 10, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (PathEnd *pe : ends) { if (pe->isPathDelay()) { EXPECT_EQ(pe->type(), PathEnd::path_delay); const char *tn = pe->typeName(); EXPECT_NE(tn, nullptr); float tgt_time = pe->targetClkTime(sta_); (void)tgt_time; float tgt_off = pe->targetClkOffset(sta_); (void)tgt_off; break; } } } // --- ReportPath methods via sta_ calls --- TEST_F(StaDesignTest, ReportPathShortMinPeriod2) { ASSERT_NO_THROW(( [&](){ MinPeriodCheckSeq &checks = sta_->minPeriodViolations(); if (!checks.empty()) { sta_->reportCheck(checks[0], false); } }() )); } TEST_F(StaDesignTest, ReportPathCheckMaxSkew2) { ASSERT_NO_THROW(( [&](){ MaxSkewCheckSeq &violations = sta_->maxSkewViolations(); if (!violations.empty()) { sta_->reportCheck(violations[0], true); sta_->reportCheck(violations[0], false); } }() )); } // --- ReportPath full report --- TEST_F(StaDesignTest, ReportPathFullReport) { ASSERT_NO_THROW(( [&](){ CornerSeq &corners = sta_->corners()->corners(); Corner *corner = corners[0]; sta_->setReportPathFormat(ReportPathFormat::full); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { PathEnd *pe = ends[0]; sta_->reportPathEnd(pe); } }() )); } TEST_F(StaDesignTest, ReportPathFullClkExpanded) { ASSERT_NO_THROW(( [&](){ CornerSeq &corners = sta_->corners()->corners(); Corner *corner = corners[0]; sta_->setReportPathFormat(ReportPathFormat::full_clock_expanded); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } // --- WorstSlack: worstSlack, sortQueue, checkQueue --- TEST_F(StaDesignTest, WorstSlackMethods) { ASSERT_NO_THROW(( [&](){ Slack worst_slack; Vertex *worst_vertex; sta_->worstSlack(MinMax::max(), worst_slack, worst_vertex); sta_->worstSlack(MinMax::max(), worst_slack, worst_vertex); CornerSeq &corners = sta_->corners()->corners(); Corner *corner = corners[0]; sta_->worstSlack(corner, MinMax::max(), worst_slack, worst_vertex); sta_->worstSlack(corner, MinMax::min(), worst_slack, worst_vertex); }() )); } // --- WnsSlackLess --- TEST_F(StaDesignTest, WnsSlackLess) { ASSERT_NO_THROW(( [&](){ CornerSeq &corners = sta_->corners()->corners(); Corner *corner = corners[0]; PathAnalysisPt *path_ap = corner->findPathAnalysisPt(MinMax::max()); if (path_ap) { WnsSlackLess less(path_ap->index(), sta_); Vertex *v1 = findVertex("r1/D"); Vertex *v2 = findVertex("r2/D"); if (v1 && v2) { bool result = less(v1, v2); (void)result; } } }() )); } // --- Search: various methods --- TEST_F(StaDesignTest, SearchInitVars) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->clear(); sta_->updateTiming(true); }() )); } TEST_F(StaDesignTest, SearchCheckPrevPaths) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->checkPrevPaths(); }() )); } TEST_F(StaDesignTest, SearchPathClkPathArrival1) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Vertex *v = findVertex("r1/D"); if (v) { VertexPathIterator *iter = sta_->vertexPathIterator(v, RiseFall::rise(), MinMax::max()); if (iter && iter->hasNext()) { Path *path = iter->next(); Arrival arr = search->pathClkPathArrival(path); (void)arr; } delete iter; } }() )); } // --- Sim --- TEST_F(StaDesignTest, SimMethods) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *pin = network->findPin(top, "r1/D"); if (pin) { Sim *sim = sta_->sim(); LogicValue val = sim->logicValue(pin); (void)val; } }() )); } // --- Levelize --- TEST_F(StaDesignTest, LevelizeCheckLevels) { ASSERT_NO_THROW(( [&](){ sta_->ensureLevelized(); }() )); } // --- Sta: clkSkewPreamble (called by reportClkSkew) --- TEST_F(StaDesignTest, ClkSkewPreamble) { ASSERT_NO_THROW(( [&](){ ConstClockSeq clks; Clock *clk = sta_->sdc()->findClock("clk"); if (clk) { clks.push_back(clk); CornerSeq &corners = sta_->corners()->corners(); Corner *corner = corners[0]; sta_->reportClkSkew(clks, corner, MinMax::max(), false, 3); } }() )); } // --- Sta: delayCalcPreamble --- TEST_F(StaDesignTest, DelayCalcPreamble) { ASSERT_NO_THROW(( [&](){ sta_->findDelays(); }() )); } // --- Sta: setCmdNamespace --- TEST_F(StaDesignTest, SetCmdNamespace12) { ASSERT_NO_THROW(( [&](){ sta_->setCmdNamespace(CmdNamespace::sta); sta_->setCmdNamespace(CmdNamespace::sdc); }() )); } // --- Sta: replaceCell --- TEST_F(StaDesignTest, ReplaceCell2) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); InstanceChildIterator *inst_iter = network->childIterator(top); if (inst_iter->hasNext()) { Instance *inst = inst_iter->next(); Cell *cell = network->cell(inst); if (cell) { sta_->replaceCell(inst, cell); } } delete inst_iter; }() )); } // --- ClkSkew: srcInternalClkLatency, tgtInternalClkLatency --- TEST_F(StaDesignTest, ClkSkewInternalLatency) { ASSERT_NO_THROW(( [&](){ ConstClockSeq clks; Clock *clk = sta_->sdc()->findClock("clk"); if (clk) { clks.push_back(clk); CornerSeq &corners = sta_->corners()->corners(); Corner *corner = corners[0]; sta_->reportClkSkew(clks, corner, MinMax::max(), true, 3); } }() )); } // --- MaxSkewCheck accessors --- TEST_F(StaDesignTest, MaxSkewCheckAccessors) { ASSERT_NO_THROW(( [&](){ MaxSkewCheckSeq &checks = sta_->maxSkewViolations(); if (!checks.empty()) { MaxSkewCheck *c1 = checks[0]; Pin *clk = c1->clkPin(sta_); (void)clk; Pin *ref = c1->refPin(sta_); (void)ref; ArcDelay max_skew = c1->maxSkew(sta_); (void)max_skew; Slack slack = c1->slack(sta_); (void)slack; } if (checks.size() >= 2) { MaxSkewSlackLess less(sta_); bool result = less(checks[0], checks[1]); (void)result; } }() )); } // --- MinPeriodSlackLess --- TEST_F(StaDesignTest, MinPeriodCheckAccessors) { ASSERT_NO_THROW(( [&](){ MinPeriodCheckSeq &checks = sta_->minPeriodViolations(); if (checks.size() >= 2) { MinPeriodSlackLess less(sta_); bool result = less(checks[0], checks[1]); (void)result; } MinPeriodCheck *min_check = sta_->minPeriodSlack(); (void)min_check; }() )); } // --- MinPulseWidthCheck: corner --- TEST_F(StaDesignTest, MinPulseWidthCheckCorner) { ASSERT_NO_THROW(( [&](){ CornerSeq &corners = sta_->corners()->corners(); Corner *corner = corners[0]; MinPulseWidthCheckSeq &checks = sta_->minPulseWidthChecks(corner); if (!checks.empty()) { MinPulseWidthCheck *check = checks[0]; const Corner *c = check->corner(sta_); (void)c; } }() )); } TEST_F(StaDesignTest, MinPulseWidthSlack3) { ASSERT_NO_THROW(( [&](){ CornerSeq &corners = sta_->corners()->corners(); Corner *corner = corners[0]; MinPulseWidthCheck *min_check = sta_->minPulseWidthSlack(corner); (void)min_check; }() )); } // --- GraphLoop: report --- TEST_F(StaDesignTest, GraphLoopReport) { ASSERT_NO_THROW(( [&](){ sta_->ensureLevelized(); GraphLoopSeq &loops = sta_->graphLoops(); for (GraphLoop *loop : loops) { loop->report(sta_); } }() )); } // --- Sta: makePortPinAfter --- TEST_F(StaDesignTest, MakePortPinAfter) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *pin = network->findPin(top, "clk1"); if (pin) { sta_->makePortPinAfter(pin); } }() )); } // --- Sta: removeDataCheck --- TEST_F(StaDesignTest, RemoveDataCheck) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *from_pin = network->findPin(top, "r1/D"); Pin *to_pin = network->findPin(top, "r1/CK"); if (from_pin && to_pin) { sta_->setDataCheck(from_pin, RiseFallBoth::riseFall(), to_pin, RiseFallBoth::riseFall(), nullptr, MinMaxAll::max(), 1.0); sta_->removeDataCheck(from_pin, RiseFallBoth::riseFall(), to_pin, RiseFallBoth::riseFall(), nullptr, MinMaxAll::max()); } }() )); } // --- PathEnum via multiple path ends --- TEST_F(StaDesignTest, PathEnum) { CornerSeq &corners = sta_->corners()->corners(); Corner *corner = corners[0]; PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 3, 3, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); EXPECT_GT(ends.size(), 0u); } // --- EndpointPathEndVisitor --- TEST_F(StaDesignTest, EndpointPins2) { PinSet pins = sta_->endpointPins(); EXPECT_GE(pins.size(), 0u); } // --- FindEndRequiredVisitor, RequiredCmp --- TEST_F(StaDesignTest, FindRequiredsAgain) { ASSERT_NO_THROW(( [&](){ sta_->findRequireds(); sta_->findRequireds(); }() )); } // --- FindEndSlackVisitor --- TEST_F(StaDesignTest, TotalNegativeSlackBothMinMax) { ASSERT_NO_THROW(( [&](){ Slack tns_max = sta_->totalNegativeSlack(MinMax::max()); (void)tns_max; Slack tns_min = sta_->totalNegativeSlack(MinMax::min()); (void)tns_min; }() )); } // --- ReportPath: reportEndpoint for output delay --- TEST_F(StaDesignTest, ReportPathOutputDelay) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); Clock *clk = sta_->sdc()->findClock("clk"); if (out && clk) { sta_->setOutputDelay(out, RiseFallBoth::riseFall(), clk, RiseFall::rise(), nullptr, false, false, MinMaxAll::all(), true, 2.0f); sta_->updateTiming(true); CornerSeq &corners = sta_->corners()->corners(); Corner *corner = corners[0]; PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (PathEnd *pe : ends) { if (pe->isOutputDelay()) { sta_->reportPathEnd(pe); break; } } } }() )); } // --- Sta: writeSdc --- TEST_F(StaDesignTest, WriteSdc2) { std::string filename = makeUniqueSdcPath("test_write_sdc_r10.sdc"); sta_->writeSdc(filename.c_str(), false, false, 4, false, true); expectSdcFileReadable(filename); } TEST_F(StaDesignTest, WriteSdcWithConstraints) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); Clock *clk = sta_->sdc()->findClock("clk"); if (out && clk) { sta_->setOutputDelay(out, RiseFallBoth::riseFall(), clk, RiseFall::rise(), nullptr, false, false, MinMaxAll::all(), true, 2.0f); } sta_->makeFalsePath(nullptr, nullptr, nullptr, MinMaxAll::all(), nullptr); if (out) { Port *port = network->port(out); Corner *corner = sta_->cmdCorner(); if (port && corner) sta_->setPortExtPinCap(port, RiseFallBoth::riseFall(), corner, MinMaxAll::all(), 0.5f); } std::string filename = makeUniqueSdcPath("test_write_sdc_r10_constrained.sdc"); sta_->writeSdc(filename.c_str(), false, false, 4, false, true); expectSdcFileReadable(filename); } TEST_F(StaDesignTest, WriteSdcNative) { std::string filename = makeUniqueSdcPath("test_write_sdc_r10_native.sdc"); sta_->writeSdc(filename.c_str(), false, true, 4, false, true); expectSdcFileReadable(filename); } TEST_F(StaDesignTest, WriteSdcLeaf) { std::string filename = makeUniqueSdcPath("test_write_sdc_r10_leaf.sdc"); sta_->writeSdc(filename.c_str(), true, false, 4, false, true); expectSdcFileReadable(filename); } // --- Path ends with sorting --- TEST_F(StaDesignTest, SaveEnumPath) { ASSERT_NO_THROW(( [&](){ CornerSeq &corners = sta_->corners()->corners(); Corner *corner = corners[0]; PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); (void)ends; }() )); } TEST_F(StaDesignTest, ReportPathLess) { ASSERT_NO_THROW(( [&](){ CornerSeq &corners = sta_->corners()->corners(); Corner *corner = corners[0]; PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); (void)ends; }() )); } // --- ClkDelays --- TEST_F(StaDesignTest, ClkDelaysDelay) { ASSERT_NO_THROW(( [&](){ Clock *clk = sta_->sdc()->findClock("clk"); if (clk) { CornerSeq &corners = sta_->corners()->corners(); Corner *corner = corners[0]; float min_period = sta_->findClkMinPeriod(clk, corner); (void)min_period; } }() )); } // --- Sta WriteSdc with Derating --- TEST_F(StaDesignTest, WriteSdcDerating) { sta_->setTimingDerate(TimingDerateType::cell_delay, PathClkOrData::data, RiseFallBoth::riseFall(), EarlyLate::early(), 0.95); sta_->setTimingDerate(TimingDerateType::net_delay, PathClkOrData::data, RiseFallBoth::riseFall(), EarlyLate::late(), 1.05); std::string filename = makeUniqueSdcPath("test_write_sdc_r10_derate.sdc"); sta_->writeSdc(filename.c_str(), false, false, 4, false, true); expectSdcFileReadable(filename); } // --- Sta WriteSdc with disable edges --- TEST_F(StaDesignTest, WriteSdcDisableEdge) { Graph *graph = sta_->graph(); Vertex *v = findVertex("r1/D"); if (v && graph) { VertexInEdgeIterator in_iter(v, graph); if (in_iter.hasNext()) { Edge *edge = in_iter.next(); sta_->disable(edge); } } std::string filename = makeUniqueSdcPath("test_write_sdc_r10_disable.sdc"); sta_->writeSdc(filename.c_str(), false, false, 4, false, true); expectSdcFileReadable(filename); } // --- ClkInfoHash, ClkInfoEqual --- TEST_F(StaDesignTest, ClkInfoHashEqual) { Vertex *v = findVertex("r1/CK"); if (v) { VertexPathIterator *iter = sta_->vertexPathIterator(v, RiseFall::rise(), MinMax::max()); if (iter && iter->hasNext()) { Path *path = iter->next(); Tag *tag = path->tag(sta_); if (tag) { const ClkInfo *ci = tag->clkInfo(); if (ci) { ClkInfoHash hasher; size_t h = hasher(ci); (void)h; ClkInfoEqual eq(sta_); bool e = eq(ci, ci); EXPECT_TRUE(e); } } } delete iter; } } // --- Report MPW checks --- TEST_F(StaDesignTest, ReportMpwChecksAll) { ASSERT_NO_THROW(( [&](){ CornerSeq &corners = sta_->corners()->corners(); Corner *corner = corners[0]; MinPulseWidthCheckSeq &checks = sta_->minPulseWidthChecks(corner); sta_->reportMpwChecks(&checks, false); sta_->reportMpwChecks(&checks, true); }() )); } // --- Report min period checks --- TEST_F(StaDesignTest, ReportMinPeriodChecks) { ASSERT_NO_THROW(( [&](){ MinPeriodCheckSeq &checks = sta_->minPeriodViolations(); for (auto *check : checks) { sta_->reportCheck(check, false); sta_->reportCheck(check, true); } }() )); } // --- Endpoints hold --- TEST_F(StaDesignTest, FindPathEndsHold3) { ASSERT_NO_THROW(( [&](){ CornerSeq &corners = sta_->corners()->corners(); Corner *corner = corners[0]; PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::min(), 5, 5, true, false, -INF, INF, false, nullptr, false, true, false, false, false, false); for (PathEnd *pe : ends) { Required req = pe->requiredTime(sta_); (void)req; Slack slack = pe->slack(sta_); (void)slack; } }() )); } // --- Report path end as JSON --- TEST_F(StaDesignTest, ReportPathEndJson2) { ASSERT_NO_THROW(( [&](){ CornerSeq &corners = sta_->corners()->corners(); Corner *corner = corners[0]; sta_->setReportPathFormat(ReportPathFormat::json); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEndHeader(); sta_->reportPathEnd(ends[0]); sta_->reportPathEndFooter(); } }() )); } // --- Report path end shorter --- TEST_F(StaDesignTest, ReportPathEndShorter) { ASSERT_NO_THROW(( [&](){ CornerSeq &corners = sta_->corners()->corners(); Corner *corner = corners[0]; sta_->setReportPathFormat(ReportPathFormat::shorter); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } // --- WriteSdc with clock groups --- TEST_F(StaDesignTest, WriteSdcWithClockGroups) { Clock *clk = sta_->sdc()->findClock("clk"); if (clk) { ClockGroups *cg = sta_->makeClockGroups("test_group", true, false, false, false, nullptr); EXPECT_NE(cg, nullptr); sta_->updateTiming(true); std::string filename = makeUniqueSdcPath("test_write_sdc_r10_clkgrp.sdc"); sta_->writeSdc(filename.c_str(), false, false, 4, false, true); expectSdcFileReadable(filename); } } // --- WriteSdc with inter-clock uncertainty --- TEST_F(StaDesignTest, WriteSdcInterClkUncertainty) { Clock *clk = sta_->sdc()->findClock("clk"); if (clk) { sta_->setClockUncertainty(clk, RiseFallBoth::riseFall(), clk, RiseFallBoth::riseFall(), MinMaxAll::max(), 0.1f); std::string filename = makeUniqueSdcPath("test_write_sdc_r10_interclk.sdc"); sta_->writeSdc(filename.c_str(), false, false, 4, false, true); expectSdcFileReadable(filename); } } // --- WriteSdc with clock latency --- TEST_F(StaDesignTest, WriteSdcClockLatency) { Clock *clk = sta_->sdc()->findClock("clk"); if (clk) { sta_->setClockLatency(clk, nullptr, RiseFallBoth::riseFall(), MinMaxAll::all(), 0.5f); std::string filename = makeUniqueSdcPath("test_write_sdc_r10_clklat.sdc"); sta_->writeSdc(filename.c_str(), false, false, 4, false, true); expectSdcFileReadable(filename); } } // ============================================================ // R10_ Additional Tests - Round 2 // ============================================================ // --- FindRegister: find register instances --- TEST_F(StaDesignTest, FindRegisterInstances2) { ClockSet *clks = nullptr; // all clocks InstanceSet regs = sta_->findRegisterInstances(clks, RiseFallBoth::riseFall(), true, true); // example1.v has registers (r1, r2, r3), so we should find some EXPECT_GT(regs.size(), 0u); } // --- FindRegister: data pins --- TEST_F(StaDesignTest, FindRegisterDataPins2) { ClockSet *clks = nullptr; PinSet data_pins = sta_->findRegisterDataPins(clks, RiseFallBoth::riseFall(), true, true); EXPECT_GT(data_pins.size(), 0u); } // --- FindRegister: clock pins --- TEST_F(StaDesignTest, FindRegisterClkPins2) { ClockSet *clks = nullptr; PinSet clk_pins = sta_->findRegisterClkPins(clks, RiseFallBoth::riseFall(), true, true); EXPECT_GT(clk_pins.size(), 0u); } // --- FindRegister: async pins --- TEST_F(StaDesignTest, FindRegisterAsyncPins2) { ASSERT_NO_THROW(( [&](){ ClockSet *clks = nullptr; PinSet async_pins = sta_->findRegisterAsyncPins(clks, RiseFallBoth::riseFall(), true, true); // May be empty if no async pins in the design (void)async_pins; }() )); } // --- FindRegister: output pins --- TEST_F(StaDesignTest, FindRegisterOutputPins2) { ClockSet *clks = nullptr; PinSet out_pins = sta_->findRegisterOutputPins(clks, RiseFallBoth::riseFall(), true, true); EXPECT_GT(out_pins.size(), 0u); } // --- FindRegister: with specific clock --- TEST_F(StaDesignTest, FindRegisterWithClock) { Sdc *sdc = sta_->sdc(); Clock *clk = sdc->findClock("clk"); ASSERT_NE(clk, nullptr); ClockSet *clks = new ClockSet; clks->insert(clk); InstanceSet regs = sta_->findRegisterInstances(clks, RiseFallBoth::rise(), true, false); // registers clocked by rise edge of "clk" (void)regs; delete clks; } // --- FindRegister: registers only (no latches) --- TEST_F(StaDesignTest, FindRegisterRegistersOnly) { ASSERT_NO_THROW(( [&](){ ClockSet *clks = nullptr; InstanceSet regs = sta_->findRegisterInstances(clks, RiseFallBoth::riseFall(), true, false); (void)regs; }() )); } // --- FindRegister: latches only --- TEST_F(StaDesignTest, FindRegisterLatchesOnly) { ASSERT_NO_THROW(( [&](){ ClockSet *clks = nullptr; InstanceSet latches = sta_->findRegisterInstances(clks, RiseFallBoth::riseFall(), false, true); (void)latches; }() )); } // --- FindFanin/Fanout: fanin pins --- TEST_F(StaDesignTest, FindFaninPins2) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); if (out) { PinSeq to_pins; to_pins.push_back(out); PinSet fanin = sta_->findFaninPins(&to_pins, false, false, 10, 100, false, false); EXPECT_GT(fanin.size(), 0u); } } // --- FindFanin: fanin instances --- TEST_F(StaDesignTest, FindFaninInstances2) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); if (out) { PinSeq to_pins; to_pins.push_back(out); InstanceSet fanin = sta_->findFaninInstances(&to_pins, false, false, 10, 100, false, false); EXPECT_GT(fanin.size(), 0u); } } // --- FindFanout: fanout pins --- TEST_F(StaDesignTest, FindFanoutPins2) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *in1 = network->findPin(top, "in1"); if (in1) { PinSeq from_pins; from_pins.push_back(in1); PinSet fanout = sta_->findFanoutPins(&from_pins, false, false, 10, 100, false, false); EXPECT_GT(fanout.size(), 0u); } } // --- FindFanout: fanout instances --- TEST_F(StaDesignTest, FindFanoutInstances2) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *in1 = network->findPin(top, "in1"); if (in1) { PinSeq from_pins; from_pins.push_back(in1); InstanceSet fanout = sta_->findFanoutInstances(&from_pins, false, false, 10, 100, false, false); EXPECT_GT(fanout.size(), 0u); } } // --- CmdNamespace: get and set --- TEST_F(StaDesignTest, CmdNamespace2) { CmdNamespace ns = sta_->cmdNamespace(); // Set to STA namespace sta_->setCmdNamespace(CmdNamespace::sta); EXPECT_EQ(sta_->cmdNamespace(), CmdNamespace::sta); // Set to SDC namespace sta_->setCmdNamespace(CmdNamespace::sdc); EXPECT_EQ(sta_->cmdNamespace(), CmdNamespace::sdc); // Restore sta_->setCmdNamespace(ns); } // --- Sta: setSlewLimit on clock --- TEST_F(StaDesignTest, SetSlewLimitClock) { ASSERT_NO_THROW(( [&](){ Sdc *sdc = sta_->sdc(); Clock *clk = sdc->findClock("clk"); if (clk) { sta_->setSlewLimit(clk, RiseFallBoth::riseFall(), PathClkOrData::clk, MinMax::max(), 2.0f); } }() )); } // --- Sta: setSlewLimit on port --- TEST_F(StaDesignTest, SetSlewLimitPort) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); if (out) { Port *port = network->port(out); if (port) { sta_->setSlewLimit(port, MinMax::max(), 3.0f); } } }() )); } // --- Sta: setSlewLimit on cell --- TEST_F(StaDesignTest, SetSlewLimitCell) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); InstanceChildIterator *iter = network->childIterator(top); if (iter->hasNext()) { Instance *inst = iter->next(); Cell *cell = network->cell(inst); if (cell) { sta_->setSlewLimit(cell, MinMax::max(), 4.0f); } } delete iter; }() )); } // --- Sta: setCapacitanceLimit on cell --- TEST_F(StaDesignTest, SetCapacitanceLimitCell) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); InstanceChildIterator *iter = network->childIterator(top); if (iter->hasNext()) { Instance *inst = iter->next(); Cell *cell = network->cell(inst); if (cell) { sta_->setCapacitanceLimit(cell, MinMax::max(), 1.0f); } } delete iter; }() )); } // --- Sta: setCapacitanceLimit on port --- TEST_F(StaDesignTest, SetCapacitanceLimitPort) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); if (out) { Port *port = network->port(out); if (port) { sta_->setCapacitanceLimit(port, MinMax::max(), 0.8f); } } }() )); } // --- Sta: setCapacitanceLimit on pin --- TEST_F(StaDesignTest, SetCapacitanceLimitPin) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); if (out) { sta_->setCapacitanceLimit(out, MinMax::max(), 0.5f); } }() )); } // --- Sta: setFanoutLimit on cell --- TEST_F(StaDesignTest, SetFanoutLimitCell) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); InstanceChildIterator *iter = network->childIterator(top); if (iter->hasNext()) { Instance *inst = iter->next(); Cell *cell = network->cell(inst); if (cell) { sta_->setFanoutLimit(cell, MinMax::max(), 10.0f); } } delete iter; }() )); } // --- Sta: setFanoutLimit on port --- TEST_F(StaDesignTest, SetFanoutLimitPort) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); if (out) { Port *port = network->port(out); if (port) { sta_->setFanoutLimit(port, MinMax::max(), 12.0f); } } }() )); } // --- Sta: setMaxArea --- TEST_F(StaDesignTest, SetMaxArea) { ASSERT_NO_THROW(( [&](){ sta_->setMaxArea(500.0f); }() )); } // --- Sta: setMinPulseWidth on clock --- TEST_F(StaDesignTest, SetMinPulseWidthClock) { ASSERT_NO_THROW(( [&](){ Sdc *sdc = sta_->sdc(); Clock *clk = sdc->findClock("clk"); if (clk) { sta_->setMinPulseWidth(clk, RiseFallBoth::rise(), 0.3f); } }() )); } // --- Sta: MinPeriod checks --- TEST_F(StaDesignTest, MinPeriodSlack3) { ASSERT_NO_THROW(( [&](){ MinPeriodCheck *check = sta_->minPeriodSlack(); if (check) { sta_->reportCheck(check, false); sta_->reportCheck(check, true); } }() )); } TEST_F(StaDesignTest, MinPeriodViolations3) { ASSERT_NO_THROW(( [&](){ MinPeriodCheckSeq &viols = sta_->minPeriodViolations(); if (!viols.empty()) { sta_->reportChecks(&viols, false); sta_->reportChecks(&viols, true); } }() )); } // --- Sta: MaxSkew checks --- TEST_F(StaDesignTest, MaxSkewSlack3) { ASSERT_NO_THROW(( [&](){ MaxSkewCheck *check = sta_->maxSkewSlack(); if (check) { sta_->reportCheck(check, false); sta_->reportCheck(check, true); } }() )); } TEST_F(StaDesignTest, MaxSkewViolations3) { ASSERT_NO_THROW(( [&](){ MaxSkewCheckSeq &viols = sta_->maxSkewViolations(); if (!viols.empty()) { sta_->reportChecks(&viols, false); sta_->reportChecks(&viols, true); } }() )); } // --- Sta: clocks arriving at pin --- TEST_F(StaDesignTest, ClocksAtPin) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *clk1 = network->findPin(top, "clk1"); if (clk1) { ClockSet clks = sta_->clocks(clk1); EXPECT_GT(clks.size(), 0u); } } // --- Sta: isClockSrc --- TEST_F(StaDesignTest, IsClockSrc) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *clk1 = network->findPin(top, "clk1"); Pin *in1 = network->findPin(top, "in1"); if (clk1) { bool is_clk_src = sta_->isClockSrc(clk1); EXPECT_TRUE(is_clk_src); } if (in1) { bool is_clk_src = sta_->isClockSrc(in1); EXPECT_FALSE(is_clk_src); } } // --- Sta: setPvt and pvt --- TEST_F(StaDesignTest, SetPvt2) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); InstanceChildIterator *iter = network->childIterator(top); if (iter->hasNext()) { Instance *inst = iter->next(); const Pvt *pvt = sta_->pvt(inst, MinMax::max()); (void)pvt; } delete iter; }() )); } // --- Property: Library and Cell properties --- TEST_F(StaDesignTest, PropertyLibrary) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Library *library = network->findLibrary("Nangate45"); if (library) { PropertyValue val = sta_->properties().getProperty(library, "name"); (void)val; } }() )); } TEST_F(StaDesignTest, PropertyCell) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); InstanceChildIterator *iter = network->childIterator(top); if (iter->hasNext()) { Instance *inst = iter->next(); Cell *cell = network->cell(inst); if (cell) { PropertyValue val = sta_->properties().getProperty(cell, "name"); (void)val; } } delete iter; }() )); } // --- Property: getProperty on Clock --- TEST_F(StaDesignTest, PropertyClock) { ASSERT_NO_THROW(( [&](){ Sdc *sdc = sta_->sdc(); Clock *clk = sdc->findClock("clk"); if (clk) { PropertyValue val = sta_->properties().getProperty(clk, "name"); (void)val; PropertyValue val2 = sta_->properties().getProperty(clk, "period"); (void)val2; PropertyValue val3 = sta_->properties().getProperty(clk, "sources"); (void)val3; } }() )); } // --- MaxSkewCheck: detailed accessors --- TEST_F(StaDesignTest, MaxSkewCheckDetailedAccessors) { ASSERT_NO_THROW(( [&](){ MaxSkewCheck *check = sta_->maxSkewSlack(); if (check) { const Pin *clk_pin = check->clkPin(sta_); (void)clk_pin; const Pin *ref_pin = check->refPin(sta_); (void)ref_pin; float max_skew = check->maxSkew(sta_); (void)max_skew; float slack = check->slack(sta_); (void)slack; } }() )); } // --- MinPeriodCheck: detailed accessors --- TEST_F(StaDesignTest, MinPeriodCheckDetailedAccessors) { ASSERT_NO_THROW(( [&](){ MinPeriodCheck *check = sta_->minPeriodSlack(); if (check) { float min_period = check->minPeriod(sta_); (void)min_period; float slack = check->slack(sta_); (void)slack; const Pin *pin = check->pin(); (void)pin; Clock *clk = check->clk(); (void)clk; } }() )); } // --- Sta: WriteSdc with various limits --- TEST_F(StaDesignTest, WriteSdcWithSlewLimit) { Sdc *sdc = sta_->sdc(); Clock *clk = sdc->findClock("clk"); if (clk) { sta_->setSlewLimit(clk, RiseFallBoth::riseFall(), PathClkOrData::data, MinMax::max(), 1.5f); } std::string filename = makeUniqueSdcPath("test_write_sdc_r10_slewlimit.sdc"); sta_->writeSdc(filename.c_str(), false, false, 4, false, true); expectSdcFileReadable(filename); } TEST_F(StaDesignTest, WriteSdcWithCapLimit) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); if (out) { Port *port = network->port(out); if (port) { sta_->setCapacitanceLimit(port, MinMax::max(), 1.0f); } } std::string filename = makeUniqueSdcPath("test_write_sdc_r10_caplimit.sdc"); sta_->writeSdc(filename.c_str(), false, false, 4, false, true); expectSdcFileReadable(filename); } TEST_F(StaDesignTest, WriteSdcWithFanoutLimit) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); if (out) { Port *port = network->port(out); if (port) { sta_->setFanoutLimit(port, MinMax::max(), 8.0f); } } std::string filename = makeUniqueSdcPath("test_write_sdc_r10_fanoutlimit.sdc"); sta_->writeSdc(filename.c_str(), false, false, 4, false, true); expectSdcFileReadable(filename); } // --- Sta: makeGeneratedClock and removeAllClocks --- TEST_F(StaDesignTest, MakeGeneratedClock) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *clk2 = network->findPin(top, "clk2"); Sdc *sdc = sta_->sdc(); Clock *clk = sdc->findClock("clk"); if (clk && clk2) { PinSet *gen_pins = new PinSet(network); gen_pins->insert(clk2); IntSeq *divide_by = new IntSeq; divide_by->push_back(2); FloatSeq *edges = nullptr; sta_->makeGeneratedClock("gen_clk", gen_pins, false, clk2, clk, 2, 0, 0.0, false, false, divide_by, edges, nullptr); Clock *gen = sdc->findClock("gen_clk"); EXPECT_NE(gen, nullptr); } } // --- Sta: removeAllClocks --- TEST_F(StaDesignTest, RemoveAllClocks) { Sdc *sdc = sta_->sdc(); Clock *clk = sdc->findClock("clk"); ASSERT_NE(clk, nullptr); sta_->removeClock(clk); clk = sdc->findClock("clk"); EXPECT_EQ(clk, nullptr); } // --- FindFanin: startpoints only --- TEST_F(StaDesignTest, FindFaninStartpoints) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); if (out) { PinSeq to_pins; to_pins.push_back(out); PinSet fanin = sta_->findFaninPins(&to_pins, false, true, 10, 100, false, false); (void)fanin; } }() )); } // --- FindFanout: endpoints only --- TEST_F(StaDesignTest, FindFanoutEndpoints) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *in1 = network->findPin(top, "in1"); if (in1) { PinSeq from_pins; from_pins.push_back(in1); PinSet fanout = sta_->findFanoutPins(&from_pins, false, true, 10, 100, false, false); (void)fanout; } }() )); } // --- Sta: report unconstrained path ends --- TEST_F(StaDesignTest, ReportUnconstrained) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, true, // unconstrained corner, MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (const auto &end : ends) { if (end) { sta_->reportPathEnd(end); } } }() )); } // --- Sta: hold path ends --- TEST_F(StaDesignTest, FindPathEndsHoldVerbose) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::min(), 3, 3, true, false, -INF, INF, false, nullptr, false, true, false, false, false, false); for (const auto &end : ends) { if (end) { sta_->reportPathEnd(end); } } }() )); } // ============================================================ // R10_ Additional Tests - Round 3 (Coverage Deepening) // ============================================================ // --- Sta: checkSlewLimits --- TEST_F(StaDesignTest, CheckSlewLimits) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); if (out) { Port *port = network->port(out); if (port) sta_->setSlewLimit(port, MinMax::max(), 0.001f); // very tight limit to create violations } Corner *corner = sta_->cmdCorner(); PinSeq viols = sta_->checkSlewLimits(nullptr, false, corner, MinMax::max()); for (const Pin *pin : viols) { sta_->reportSlewLimitShort(const_cast(pin), corner, MinMax::max()); sta_->reportSlewLimitVerbose(const_cast(pin), corner, MinMax::max()); } sta_->reportSlewLimitShortHeader(); // Also check maxSlewCheck const Pin *pin_out = nullptr; Slew slew_out; float slack_out, limit_out; sta_->maxSlewCheck(pin_out, slew_out, slack_out, limit_out); }() )); } // --- Sta: checkSlew on specific pin --- TEST_F(StaDesignTest, CheckSlewOnPin) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); if (out) { Port *port = network->port(out); if (port) sta_->setSlewLimit(port, MinMax::max(), 0.001f); Corner *corner = sta_->cmdCorner(); sta_->checkSlewLimitPreamble(); const Corner *corner1 = nullptr; const RiseFall *tr = nullptr; Slew slew; float limit, slack; sta_->checkSlew(out, corner, MinMax::max(), false, corner1, tr, slew, limit, slack); } }() )); } // --- Sta: checkCapacitanceLimits --- TEST_F(StaDesignTest, CheckCapacitanceLimits2) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); if (out) { Port *port = network->port(out); if (port) sta_->setCapacitanceLimit(port, MinMax::max(), 0.0001f); // very tight } Corner *corner = sta_->cmdCorner(); PinSeq viols = sta_->checkCapacitanceLimits(nullptr, false, corner, MinMax::max()); for (const Pin *pin : viols) { sta_->reportCapacitanceLimitShort(const_cast(pin), corner, MinMax::max()); sta_->reportCapacitanceLimitVerbose(const_cast(pin), corner, MinMax::max()); } sta_->reportCapacitanceLimitShortHeader(); // Also check maxCapacitanceCheck const Pin *pin_out = nullptr; float cap_out, slack_out, limit_out; sta_->maxCapacitanceCheck(pin_out, cap_out, slack_out, limit_out); }() )); } // --- Sta: checkCapacitance on specific pin --- TEST_F(StaDesignTest, CheckCapacitanceOnPin) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); if (out) { sta_->setCapacitanceLimit(out, MinMax::max(), 0.0001f); Corner *corner = sta_->cmdCorner(); sta_->checkCapacitanceLimitPreamble(); const Corner *corner1 = nullptr; const RiseFall *tr = nullptr; float cap, limit, slack; sta_->checkCapacitance(out, corner, MinMax::max(), corner1, tr, cap, limit, slack); } }() )); } // --- Sta: checkFanoutLimits --- TEST_F(StaDesignTest, CheckFanoutLimits2) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); if (out) { Port *port = network->port(out); if (port) sta_->setFanoutLimit(port, MinMax::max(), 0.01f); // very tight } PinSeq viols = sta_->checkFanoutLimits(nullptr, false, MinMax::max()); for (const Pin *pin : viols) { sta_->reportFanoutLimitShort(const_cast(pin), MinMax::max()); sta_->reportFanoutLimitVerbose(const_cast(pin), MinMax::max()); } sta_->reportFanoutLimitShortHeader(); // Also check maxFanoutCheck const Pin *pin_out = nullptr; float fanout_out, slack_out, limit_out; sta_->maxFanoutCheck(pin_out, fanout_out, slack_out, limit_out); }() )); } // --- Sta: checkFanout on specific pin --- TEST_F(StaDesignTest, CheckFanoutOnPin) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); if (out) { Port *port = network->port(out); if (port) sta_->setFanoutLimit(port, MinMax::max(), 0.01f); sta_->checkFanoutLimitPreamble(); float fanout, limit, slack; sta_->checkFanout(out, MinMax::max(), fanout, limit, slack); } }() )); } // --- Sta: reportClkSkew --- TEST_F(StaDesignTest, ReportClkSkew2) { ASSERT_NO_THROW(( [&](){ Sdc *sdc = sta_->sdc(); Clock *clk = sdc->findClock("clk"); if (clk) { ConstClockSeq clks; clks.push_back(clk); Corner *corner = sta_->cmdCorner(); sta_->reportClkSkew(clks, corner, MinMax::max(), false, 3); sta_->reportClkSkew(clks, corner, MinMax::min(), false, 3); } }() )); } // --- Sta: findWorstClkSkew --- TEST_F(StaDesignTest, FindWorstClkSkew3) { ASSERT_NO_THROW(( [&](){ float worst = sta_->findWorstClkSkew(MinMax::max(), false); (void)worst; }() )); } // --- Sta: reportClkLatency --- TEST_F(StaDesignTest, ReportClkLatency3) { ASSERT_NO_THROW(( [&](){ Sdc *sdc = sta_->sdc(); Clock *clk = sdc->findClock("clk"); if (clk) { ConstClockSeq clks; clks.push_back(clk); Corner *corner = sta_->cmdCorner(); sta_->reportClkLatency(clks, corner, false, 3); } }() )); } // --- Sta: findSlewLimit --- TEST_F(StaDesignTest, FindSlewLimit2) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); InstanceChildIterator *iter = network->childIterator(top); if (iter->hasNext()) { Instance *inst = iter->next(); LibertyCell *lib_cell = network->libertyCell(inst); if (lib_cell) { LibertyCellPortIterator port_iter(lib_cell); if (port_iter.hasNext()) { LibertyPort *port = port_iter.next(); Corner *corner = sta_->cmdCorner(); float limit; bool exists; sta_->findSlewLimit(port, corner, MinMax::max(), limit, exists); } } } delete iter; }() )); } // --- Sta: MinPulseWidth violations --- TEST_F(StaDesignTest, MpwViolations) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); MinPulseWidthCheckSeq &viols = sta_->minPulseWidthViolations(corner); if (!viols.empty()) { sta_->reportMpwChecks(&viols, false); sta_->reportMpwChecks(&viols, true); } }() )); } // --- Sta: minPulseWidthSlack (all corners) --- TEST_F(StaDesignTest, MpwSlackAllCorners) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); MinPulseWidthCheck *check = sta_->minPulseWidthSlack(corner); if (check) { sta_->reportMpwCheck(check, false); sta_->reportMpwCheck(check, true); } }() )); } // --- Sta: minPulseWidthChecks (all) --- TEST_F(StaDesignTest, MpwChecksAll) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); MinPulseWidthCheckSeq &checks = sta_->minPulseWidthChecks(corner); if (!checks.empty()) { sta_->reportMpwChecks(&checks, false); } }() )); } // --- Sta: WriteSdc with min pulse width + clock latency + all constraints --- TEST_F(StaDesignTest, WriteSdcFullConstraints) { Sdc *sdc = sta_->sdc(); Clock *clk = sdc->findClock("clk"); Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); // Set many constraints if (clk) { sta_->setMinPulseWidth(clk, RiseFallBoth::rise(), 0.2f); sta_->setSlewLimit(clk, RiseFallBoth::riseFall(), PathClkOrData::clk, MinMax::max(), 1.0f); sta_->setSlewLimit(clk, RiseFallBoth::riseFall(), PathClkOrData::data, MinMax::max(), 2.0f); sta_->setClockLatency(clk, nullptr, RiseFallBoth::rise(), MinMaxAll::max(), 0.3f); sta_->setClockLatency(clk, nullptr, RiseFallBoth::fall(), MinMaxAll::min(), 0.1f); } Pin *in1 = network->findPin(top, "in1"); Pin *out = network->findPin(top, "out"); if (in1) { Port *port = network->port(in1); if (port) { sta_->setDriveResistance(port, RiseFallBoth::rise(), MinMaxAll::max(), 200.0f); sta_->setDriveResistance(port, RiseFallBoth::fall(), MinMaxAll::min(), 50.0f); } sta_->setMinPulseWidth(in1, RiseFallBoth::rise(), 0.1f); } if (out) { Port *port = network->port(out); if (port) { sta_->setCapacitanceLimit(port, MinMax::max(), 0.5f); sta_->setFanoutLimit(port, MinMax::max(), 4.0f); sta_->setPortExtPinCap(port, RiseFallBoth::rise(), sta_->cmdCorner(), MinMaxAll::max(), 0.2f); sta_->setPortExtPinCap(port, RiseFallBoth::fall(), sta_->cmdCorner(), MinMaxAll::min(), 0.1f); } } sdc->setMaxArea(5000.0); sdc->setVoltage(MinMax::max(), 1.2); sdc->setVoltage(MinMax::min(), 0.8); // Write comprehensive SDC std::string filename = makeUniqueSdcPath("test_write_sdc_r10_full.sdc"); sta_->writeSdc(filename.c_str(), false, false, 4, false, true); expectSdcFileReadable(filename); } // --- Sta: Property getProperty on edge --- TEST_F(StaDesignTest, PropertyEdge) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Graph *graph = sta_->graph(); Instance *top = network->topInstance(); Pin *pin = network->findPin(top, "r1/D"); if (pin && graph) { Vertex *v = graph->pinLoadVertex(pin); if (v) { VertexInEdgeIterator edge_iter(v, graph); if (edge_iter.hasNext()) { Edge *edge = edge_iter.next(); PropertyValue val = sta_->properties().getProperty(edge, "from_pin"); (void)val; PropertyValue val2 = sta_->properties().getProperty(edge, "sense"); (void)val2; } } } }() )); } // --- Sta: Property getProperty on net --- TEST_F(StaDesignTest, PropertyNet) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); NetIterator *net_iter = network->netIterator(top); if (net_iter->hasNext()) { Net *net = net_iter->next(); PropertyValue val = sta_->properties().getProperty(net, "name"); (void)val; } delete net_iter; }() )); } // --- Sta: Property getProperty on port --- TEST_F(StaDesignTest, PropertyPort) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); if (out) { Port *port = network->port(out); if (port) { PropertyValue val = sta_->properties().getProperty(port, "name"); (void)val; PropertyValue val2 = sta_->properties().getProperty(port, "direction"); (void)val2; } } }() )); } // --- Sta: Property getProperty on LibertyCell --- TEST_F(StaDesignTest, PropertyLibertyCell) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); InstanceChildIterator *iter = network->childIterator(top); if (iter->hasNext()) { Instance *inst = iter->next(); LibertyCell *lib_cell = network->libertyCell(inst); if (lib_cell) { PropertyValue val = sta_->properties().getProperty(lib_cell, "name"); (void)val; PropertyValue val2 = sta_->properties().getProperty(lib_cell, "area"); (void)val2; } } delete iter; }() )); } // --- Sta: Property getProperty on LibertyPort --- TEST_F(StaDesignTest, PropertyLibertyPort) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); InstanceChildIterator *iter = network->childIterator(top); if (iter->hasNext()) { Instance *inst = iter->next(); LibertyCell *lib_cell = network->libertyCell(inst); if (lib_cell) { LibertyCellPortIterator port_iter(lib_cell); if (port_iter.hasNext()) { LibertyPort *port = port_iter.next(); PropertyValue val = sta_->properties().getProperty(port, "name"); (void)val; PropertyValue val2 = sta_->properties().getProperty(port, "direction"); (void)val2; } } } delete iter; }() )); } // --- Sta: Property getProperty on LibertyLibrary --- TEST_F(StaDesignTest, PropertyLibertyLibrary) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); LibertyLibraryIterator *lib_iter = network->libertyLibraryIterator(); if (lib_iter->hasNext()) { LibertyLibrary *lib = lib_iter->next(); PropertyValue val = sta_->properties().getProperty(lib, "name"); (void)val; } delete lib_iter; }() )); } // --- Sta: Property getProperty on instance --- TEST_F(StaDesignTest, PropertyInstance) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); InstanceChildIterator *iter = network->childIterator(top); if (iter->hasNext()) { Instance *inst = iter->next(); PropertyValue val = sta_->properties().getProperty(inst, "name"); (void)val; } delete iter; }() )); } // --- Sta: Property getProperty on TimingArcSet --- TEST_F(StaDesignTest, PropertyTimingArcSet) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); InstanceChildIterator *iter = network->childIterator(top); if (iter->hasNext()) { Instance *inst = iter->next(); LibertyCell *lib_cell = network->libertyCell(inst); if (lib_cell) { for (TimingArcSet *arc_set : lib_cell->timingArcSets()) { PropertyValue val = sta_->properties().getProperty(arc_set, "name"); (void)val; break; // just test one } } } delete iter; }() )); } // --- Sta: Property getProperty on PathEnd --- TEST_F(StaDesignTest, PropertyPathEnd) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (const auto &end : ends) { if (end) { PropertyValue val = sta_->properties().getProperty(end, "startpoint"); (void)val; PropertyValue val2 = sta_->properties().getProperty(end, "endpoint"); (void)val2; PropertyValue val3 = sta_->properties().getProperty(end, "slack"); (void)val3; break; // just test one } } }() )); } // --- Sta: Property getProperty on Path --- TEST_F(StaDesignTest, PropertyPath) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (const auto &end : ends) { if (end) { Path *path = end->path(); if (path) { PropertyValue val = sta_->properties().getProperty(path, "pin"); (void)val; PropertyValue val2 = sta_->properties().getProperty(path, "arrival"); (void)val2; } break; } } }() )); } // ============================================================ // R11_ Search Tests // ============================================================ // --- Properties::getProperty on Pin: arrival, slack, slew --- TEST_F(StaDesignTest, PropertiesGetPropertyPin) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); if (out) { // These trigger pinArrival internally PropertyValue val_arr = sta_->properties().getProperty(out, "arrival_max_rise"); (void)val_arr; PropertyValue val_arr2 = sta_->properties().getProperty(out, "arrival_max_fall"); (void)val_arr2; PropertyValue val_arr3 = sta_->properties().getProperty(out, "arrival_min_rise"); (void)val_arr3; PropertyValue val_arr4 = sta_->properties().getProperty(out, "arrival_min_fall"); (void)val_arr4; // These trigger pinSlack internally PropertyValue val_slk = sta_->properties().getProperty(out, "slack_max"); (void)val_slk; PropertyValue val_slk2 = sta_->properties().getProperty(out, "slack_max_rise"); (void)val_slk2; PropertyValue val_slk3 = sta_->properties().getProperty(out, "slack_max_fall"); (void)val_slk3; PropertyValue val_slk4 = sta_->properties().getProperty(out, "slack_min"); (void)val_slk4; PropertyValue val_slk5 = sta_->properties().getProperty(out, "slack_min_rise"); (void)val_slk5; PropertyValue val_slk6 = sta_->properties().getProperty(out, "slack_min_fall"); (void)val_slk6; // Slew PropertyValue val_slew = sta_->properties().getProperty(out, "slew_max"); (void)val_slew; } }() )); } // --- Properties::getProperty on Cell --- TEST_F(StaDesignTest, PropertiesGetPropertyCell) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); InstanceChildIterator *iter = network->childIterator(top); if (iter->hasNext()) { Instance *inst = iter->next(); Cell *cell = network->cell(inst); if (cell) { PropertyValue val = sta_->properties().getProperty(cell, "name"); (void)val; } } delete iter; }() )); } // --- Properties::getProperty on Library --- TEST_F(StaDesignTest, PropertiesGetPropertyLibrary) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Library *lib = network->findLibrary("Nangate45_typ"); if (lib) { PropertyValue val = sta_->properties().getProperty(lib, "name"); (void)val; } }() )); } // --- PropertyUnknown exception --- TEST_F(StaDesignTest, PropertyUnknown) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); if (out) { try { PropertyValue val = sta_->properties().getProperty(out, "nonexistent_prop"); (void)val; } catch (std::exception &e) { // Expected PropertyUnknown exception (void)e; } } }() )); } // --- Sta::reportClkSkew (triggers clkSkewPreamble) --- TEST_F(StaDesignTest, ReportClkSkew3) { ASSERT_NO_THROW(( [&](){ Clock *clk = sta_->sdc()->findClock("clk"); if (clk) { ConstClockSeq clks; clks.push_back(clk); Corner *corner = sta_->cmdCorner(); sta_->reportClkSkew(clks, corner, MinMax::max(), false, 4); sta_->reportClkSkew(clks, corner, MinMax::min(), false, 4); } }() )); } // --- Sta::findWorstClkSkew --- TEST_F(StaDesignTest, FindWorstClkSkew4) { ASSERT_NO_THROW(( [&](){ float skew = sta_->findWorstClkSkew(MinMax::max(), false); (void)skew; float skew2 = sta_->findWorstClkSkew(MinMax::min(), false); (void)skew2; }() )); } // --- Sta::reportClkLatency --- TEST_F(StaDesignTest, ReportClkLatency4) { ASSERT_NO_THROW(( [&](){ Clock *clk = sta_->sdc()->findClock("clk"); if (clk) { ConstClockSeq clks; clks.push_back(clk); Corner *corner = sta_->cmdCorner(); sta_->reportClkLatency(clks, corner, false, 4); sta_->reportClkLatency(clks, corner, true, 4); } }() )); } // --- Sta: propagated clock detection --- TEST_F(StaDesignTest, PropagatedClockDetection) { ASSERT_NO_THROW(( [&](){ Clock *clk = sta_->sdc()->findClock("clk"); if (clk) { bool prop = clk->isPropagated(); (void)prop; } }() )); } // --- Sta::removeDataCheck --- TEST_F(StaDesignTest, StaRemoveDataCheck) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *from_pin = network->findPin(top, "r1/D"); Pin *to_pin = network->findPin(top, "r1/CK"); if (from_pin && to_pin) { sta_->setDataCheck(from_pin, RiseFallBoth::riseFall(), to_pin, RiseFallBoth::riseFall(), nullptr, MinMaxAll::max(), 1.0f); sta_->removeDataCheck(from_pin, RiseFallBoth::riseFall(), to_pin, RiseFallBoth::riseFall(), nullptr, MinMaxAll::max()); } }() )); } // --- PathEnd methods: targetClk, targetClkArrival, targetClkDelay, // targetClkInsertionDelay, targetClkUncertainty, targetClkMcpAdjustment --- TEST_F(StaDesignTest, PathEndTargetClkMethods2) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (PathEnd *pe : ends) { if (pe) { const Clock *tgt_clk = pe->targetClk(sta_); (void)tgt_clk; Arrival tgt_arr = pe->targetClkArrival(sta_); (void)tgt_arr; Delay tgt_delay = pe->targetClkDelay(sta_); (void)tgt_delay; Arrival tgt_ins = pe->targetClkInsertionDelay(sta_); (void)tgt_ins; float tgt_unc = pe->targetClkUncertainty(sta_); (void)tgt_unc; float tgt_mcp = pe->targetClkMcpAdjustment(sta_); (void)tgt_mcp; float non_inter = pe->targetNonInterClkUncertainty(sta_); (void)non_inter; float inter = pe->interClkUncertainty(sta_); (void)inter; } } }() )); } // --- PathExpanded::pathsIndex --- TEST_F(StaDesignTest, PathExpandedPathsIndex) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (PathEnd *pe : ends) { if (pe) { Path *path = pe->path(); if (path) { PathExpanded expanded(path, sta_); size_t sz = expanded.size(); if (sz > 0) { // Access first and last path const Path *p0 = expanded.path(0); (void)p0; if (sz > 1) { const Path *p1 = expanded.path(sz - 1); (void)p1; } } } } break; } }() )); } // --- Report path end with format full_clock --- TEST_F(StaDesignTest, ReportPathEndFullClock) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); sta_->setReportPathFormat(ReportPathFormat::full_clock); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEndHeader(); sta_->reportPathEnd(ends[0]); sta_->reportPathEndFooter(); } }() )); } // --- Report path end with format full_clock_expanded --- TEST_F(StaDesignTest, ReportPathEndFullClockExpanded) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); sta_->setReportPathFormat(ReportPathFormat::full_clock_expanded); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEndHeader(); sta_->reportPathEnd(ends[0]); sta_->reportPathEndFooter(); } }() )); } // --- Report path end with format end --- TEST_F(StaDesignTest, ReportPathEndEnd) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); sta_->setReportPathFormat(ReportPathFormat::endpoint); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEndHeader(); sta_->reportPathEnd(ends[0]); sta_->reportPathEndFooter(); } }() )); } // --- Report path end with format summary --- TEST_F(StaDesignTest, ReportPathEndSummary2) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); sta_->setReportPathFormat(ReportPathFormat::summary); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEndHeader(); sta_->reportPathEnd(ends[0]); sta_->reportPathEndFooter(); } }() )); } // --- Report path end with format slack_only --- TEST_F(StaDesignTest, ReportPathEndSlackOnly2) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); sta_->setReportPathFormat(ReportPathFormat::slack_only); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEndHeader(); sta_->reportPathEnd(ends[0]); sta_->reportPathEndFooter(); } }() )); } // --- Report multiple path ends --- TEST_F(StaDesignTest, ReportPathEnds3) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); sta_->setReportPathFormat(ReportPathFormat::full); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnds(&ends); } }() )); } // --- Sta: worstSlack --- TEST_F(StaDesignTest, WorstSlack2) { ASSERT_NO_THROW(( [&](){ Slack ws_max = sta_->worstSlack(MinMax::max()); (void)ws_max; Slack ws_min = sta_->worstSlack(MinMax::min()); (void)ws_min; }() )); } // --- Sta: worstSlack with corner --- TEST_F(StaDesignTest, WorstSlackCorner2) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); Slack ws; Vertex *v; sta_->worstSlack(corner, MinMax::max(), ws, v); (void)ws; (void)v; }() )); } // --- Sta: totalNegativeSlack --- TEST_F(StaDesignTest, TotalNegativeSlack2) { ASSERT_NO_THROW(( [&](){ Slack tns = sta_->totalNegativeSlack(MinMax::max()); (void)tns; Slack tns2 = sta_->totalNegativeSlack(MinMax::min()); (void)tns2; }() )); } // --- Sta: totalNegativeSlack with corner --- TEST_F(StaDesignTest, TotalNegativeSlackCorner2) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); Slack tns = sta_->totalNegativeSlack(corner, MinMax::max()); (void)tns; }() )); } // --- WriteSdc with many constraints from search side --- TEST_F(StaDesignTest, WriteSdcComprehensive) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Corner *corner = sta_->cmdCorner(); Clock *clk = sta_->sdc()->findClock("clk"); Pin *in1 = network->findPin(top, "in1"); Pin *in2 = network->findPin(top, "in2"); Pin *out = network->findPin(top, "out"); // Net wire cap NetIterator *net_iter = network->netIterator(top); if (net_iter->hasNext()) { Net *net = net_iter->next(); sta_->setNetWireCap(net, false, corner, MinMaxAll::all(), 0.04f); sta_->setResistance(net, MinMaxAll::all(), 75.0f); } delete net_iter; // Input slew if (in1) { Port *port = network->port(in1); if (port) sta_->setInputSlew(port, RiseFallBoth::riseFall(), MinMaxAll::all(), 0.1f); } // Port loads if (out) { Port *port = network->port(out); if (port && corner) { sta_->setPortExtPinCap(port, RiseFallBoth::riseFall(), corner, MinMaxAll::all(), 0.15f); sta_->setPortExtWireCap(port, false, RiseFallBoth::riseFall(), corner, MinMaxAll::all(), 0.02f); } } // False path with -from and -through net if (in1) { PinSet *from_pins = new PinSet(network); from_pins->insert(in1); ExceptionFrom *from = sta_->makeExceptionFrom(from_pins, nullptr, nullptr, RiseFallBoth::riseFall()); NetIterator *nit = network->netIterator(top); ExceptionThruSeq *thrus = new ExceptionThruSeq; if (nit->hasNext()) { Net *net = nit->next(); NetSet *nets = new NetSet(network); nets->insert(net); ExceptionThru *thru = sta_->makeExceptionThru(nullptr, nets, nullptr, RiseFallBoth::riseFall()); thrus->push_back(thru); } delete nit; sta_->makeFalsePath(from, thrus, nullptr, MinMaxAll::all(), nullptr); } // Max delay if (in2 && out) { PinSet *from_pins = new PinSet(network); from_pins->insert(in2); ExceptionFrom *from = sta_->makeExceptionFrom(from_pins, nullptr, nullptr, RiseFallBoth::riseFall()); PinSet *to_pins = new PinSet(network); to_pins->insert(out); ExceptionTo *to = sta_->makeExceptionTo(to_pins, nullptr, nullptr, RiseFallBoth::riseFall(), RiseFallBoth::riseFall()); sta_->makePathDelay(from, nullptr, to, MinMax::max(), false, false, 7.0f, nullptr); } // Clock groups with actual clocks if (clk) { ClockGroups *cg = sta_->makeClockGroups("search_grp", true, false, false, false, nullptr); ClockSet *g1 = new ClockSet; g1->insert(clk); sta_->makeClockGroup(cg, g1); } // Multicycle sta_->makeMulticyclePath(nullptr, nullptr, nullptr, MinMaxAll::max(), true, 2, nullptr); // Group path sta_->makeGroupPath("search_group", false, nullptr, nullptr, nullptr, nullptr); // Voltage sta_->setVoltage(MinMax::max(), 1.1f); sta_->setVoltage(MinMax::min(), 0.9f); std::string filename = makeUniqueSdcPath("test_search_r11_comprehensive.sdc"); sta_->writeSdc(filename.c_str(), false, false, 4, false, true); expectSdcFileReadable(filename); // Also write native and leaf std::string fn2 = makeUniqueSdcPath("test_search_r11_comprehensive_native.sdc"); sta_->writeSdc(fn2.c_str(), false, true, 4, false, true); expectSdcFileReadable(fn2); std::string fn3 = makeUniqueSdcPath("test_search_r11_comprehensive_leaf.sdc"); sta_->writeSdc(fn3.c_str(), true, false, 4, false, true); expectSdcFileReadable(fn3); } // --- Sta: report path with verbose format --- TEST_F(StaDesignTest, ReportPathVerbose) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); sta_->setReportPathFormat(ReportPathFormat::full); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 3, 3, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (PathEnd *pe : ends) { if (pe) { sta_->reportPathEnd(pe); } } }() )); } // --- Sta: report path for hold (min) --- TEST_F(StaDesignTest, ReportPathHold) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); sta_->setReportPathFormat(ReportPathFormat::full); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::min(), 3, 3, true, false, -INF, INF, false, nullptr, false, true, false, false, false, false); for (PathEnd *pe : ends) { if (pe) { sta_->reportPathEnd(pe); } } }() )); } // --- Sta: max skew checks with report --- TEST_F(StaDesignTest, MaxSkewChecksReport) { ASSERT_NO_THROW(( [&](){ MaxSkewCheckSeq &viols = sta_->maxSkewViolations(); for (auto *check : viols) { sta_->reportCheck(check, true); sta_->reportCheck(check, false); } MaxSkewCheck *slack_check = sta_->maxSkewSlack(); if (slack_check) { sta_->reportCheck(slack_check, true); sta_->reportCheck(slack_check, false); } }() )); } // --- Sta: min period checks with report --- TEST_F(StaDesignTest, MinPeriodChecksReport) { ASSERT_NO_THROW(( [&](){ MinPeriodCheckSeq &viols = sta_->minPeriodViolations(); for (auto *check : viols) { sta_->reportCheck(check, true); sta_->reportCheck(check, false); } MinPeriodCheck *slack_check = sta_->minPeriodSlack(); if (slack_check) { sta_->reportCheck(slack_check, true); sta_->reportCheck(slack_check, false); } }() )); } // --- Sta: MPW slack check --- TEST_F(StaDesignTest, MpwSlackCheck) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); MinPulseWidthCheck *check = sta_->minPulseWidthSlack(corner); if (check) { sta_->reportMpwCheck(check, false); sta_->reportMpwCheck(check, true); } }() )); } // --- Sta: MPW checks on all --- TEST_F(StaDesignTest, MpwChecksAll2) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); MinPulseWidthCheckSeq &checks = sta_->minPulseWidthChecks(corner); sta_->reportMpwChecks(&checks, false); sta_->reportMpwChecks(&checks, true); }() )); } // --- Sta: MPW violations --- TEST_F(StaDesignTest, MpwViolations2) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); MinPulseWidthCheckSeq &viols = sta_->minPulseWidthViolations(corner); if (!viols.empty()) { sta_->reportMpwChecks(&viols, true); } }() )); } // --- Sta: check timing --- TEST_F(StaDesignTest, CheckTiming3) { ASSERT_NO_THROW(( [&](){ CheckErrorSeq &errors = sta_->checkTiming(true, true, true, true, true, true, true); (void)errors; }() )); } // --- Sta: find path ends with output delay --- TEST_F(StaDesignTest, FindPathEndsWithOutputDelay) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *out = network->findPin(top, "out"); Clock *clk = sta_->sdc()->findClock("clk"); if (out && clk) { sta_->setOutputDelay(out, RiseFallBoth::riseFall(), clk, RiseFall::rise(), nullptr, false, false, MinMaxAll::all(), true, 2.0f); sta_->updateTiming(true); Corner *corner = sta_->cmdCorner(); sta_->setReportPathFormat(ReportPathFormat::full); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (PathEnd *pe : ends) { if (pe) { sta_->reportPathEnd(pe); bool is_out_delay = pe->isOutputDelay(); (void)is_out_delay; } } } }() )); } // --- PathEnd: type and typeName --- TEST_F(StaDesignTest, PathEndTypeInfo) { Corner *corner = sta_->cmdCorner(); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (PathEnd *pe : ends) { if (pe) { PathEnd::Type type = pe->type(); (void)type; const char *name = pe->typeName(); EXPECT_NE(name, nullptr); } } } // --- Sta: find path ends unconstrained --- TEST_F(StaDesignTest, FindPathEndsUnconstrained3) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 5, 5, true, false, -INF, INF, true, nullptr, true, false, false, false, false, false); for (PathEnd *pe : ends) { if (pe) { bool unc = pe->isUnconstrained(); (void)unc; if (unc) { Required req = pe->requiredTime(sta_); (void)req; } } } }() )); } // --- Sta: find path ends with group filter --- TEST_F(StaDesignTest, FindPathEndsGroupFilter) { ASSERT_NO_THROW(( [&](){ // Create a group path first sta_->makeGroupPath("r11_grp", false, nullptr, nullptr, nullptr, nullptr); Corner *corner = sta_->cmdCorner(); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); (void)ends; }() )); } // --- Sta: pathGroupNames --- TEST_F(StaDesignTest, PathGroupNames) { sta_->makeGroupPath("test_group_r11", false, nullptr, nullptr, nullptr, nullptr); StdStringSeq names = sta_->pathGroupNames(); bool found = false; for (const auto &name : names) { if (name == "test_group_r11") found = true; } EXPECT_TRUE(found); } // --- Sta: isPathGroupName --- TEST_F(StaDesignTest, IsPathGroupName) { sta_->makeGroupPath("test_pg_r11", false, nullptr, nullptr, nullptr, nullptr); bool is_group = sta_->isPathGroupName("test_pg_r11"); EXPECT_TRUE(is_group); bool not_group = sta_->isPathGroupName("nonexistent_group"); EXPECT_FALSE(not_group); } // --- Sta: report path with max_delay constraint --- TEST_F(StaDesignTest, ReportPathWithMaxDelay) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *in1 = network->findPin(top, "in1"); Pin *out = network->findPin(top, "out"); if (in1 && out) { PinSet *from_pins = new PinSet(network); from_pins->insert(in1); ExceptionFrom *from = sta_->makeExceptionFrom(from_pins, nullptr, nullptr, RiseFallBoth::riseFall()); PinSet *to_pins = new PinSet(network); to_pins->insert(out); ExceptionTo *to = sta_->makeExceptionTo(to_pins, nullptr, nullptr, RiseFallBoth::riseFall(), RiseFallBoth::riseFall()); sta_->makePathDelay(from, nullptr, to, MinMax::max(), false, false, 8.0f, nullptr); sta_->updateTiming(true); Corner *corner = sta_->cmdCorner(); sta_->setReportPathFormat(ReportPathFormat::full); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (PathEnd *pe : ends) { if (pe) { sta_->reportPathEnd(pe); } } } }() )); } // --- ClkInfo accessors via tag on vertex path --- TEST_F(StaDesignTest, ClkInfoAccessors4) { ASSERT_NO_THROW(( [&](){ Vertex *v = findVertex("r1/CK"); if (v) { VertexPathIterator *iter = sta_->vertexPathIterator(v, RiseFall::rise(), MinMax::max()); if (iter && iter->hasNext()) { Path *path = iter->next(); Tag *tag = path->tag(sta_); if (tag) { const ClkInfo *ci = tag->clkInfo(); if (ci) { const ClockEdge *edge = ci->clkEdge(); (void)edge; bool prop = ci->isPropagated(); (void)prop; bool gen = ci->isGenClkSrcPath(); (void)gen; } int ap_idx = tag->pathAPIndex(); (void)ap_idx; } } delete iter; } }() )); } // --- Sta: WriteSdc with clock sense from search --- TEST_F(StaDesignTest, WriteSdcClockSense) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *clk1 = network->findPin(top, "clk1"); Clock *clk = sta_->sdc()->findClock("clk"); if (clk1 && clk) { PinSet *pins = new PinSet(network); pins->insert(clk1); ClockSet *clks = new ClockSet; clks->insert(clk); sta_->setClockSense(pins, clks, ClockSense::positive); } std::string filename = makeUniqueSdcPath("test_search_r11_clksense.sdc"); sta_->writeSdc(filename.c_str(), false, false, 4, false, true); expectSdcFileReadable(filename); } // --- Sta: WriteSdc with driving cell --- TEST_F(StaDesignTest, WriteSdcDrivingCell) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Pin *in1 = network->findPin(top, "in1"); if (in1) { Port *port = network->port(in1); if (port) { LibertyLibrary *lib = lib_; if (lib) { // Find BUF_X1 which is known to exist in nangate45 LibertyCell *buf_cell = lib->findLibertyCell("BUF_X1"); if (buf_cell) { LibertyPort *from_port = buf_cell->findLibertyPort("A"); LibertyPort *to_port = buf_cell->findLibertyPort("Z"); if (from_port && to_port) { float from_slews[2] = {0.03f, 0.03f}; sta_->setDriveCell(lib, buf_cell, port, from_port, from_slews, to_port, RiseFallBoth::riseFall(), MinMaxAll::all()); } } } } } std::string filename = makeUniqueSdcPath("test_search_r11_drivecell.sdc"); sta_->writeSdc(filename.c_str(), false, false, 4, false, true); expectSdcFileReadable(filename); } // --- Sta: report path end with reportPath --- TEST_F(StaDesignTest, ReportPath2) { ASSERT_NO_THROW(( [&](){ Corner *corner = sta_->cmdCorner(); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (PathEnd *pe : ends) { if (pe && pe->path()) { sta_->reportPath(pe->path()); } break; } }() )); } // --- Sta: propagated clock and report --- TEST_F(StaDesignTest, PropagatedClockReport) { ASSERT_NO_THROW(( [&](){ Clock *clk = sta_->sdc()->findClock("clk"); if (clk) { sta_->setPropagatedClock(clk); sta_->updateTiming(true); Corner *corner = sta_->cmdCorner(); sta_->setReportPathFormat(ReportPathFormat::full); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, corner, MinMaxAll::max(), 3, 3, true, false, -INF, INF, false, nullptr, true, false, false, false, false, false); for (PathEnd *pe : ends) { if (pe) { sta_->reportPathEnd(pe); } } // Write SDC with propagated clock std::string filename = makeUniqueSdcPath("test_search_r11_propclk.sdc"); sta_->writeSdc(filename.c_str(), false, false, 4, false, true); expectSdcFileReadable(filename); } }() )); } // --- Sta: setCmdNamespace to STA (covers setCmdNamespace1) --- TEST_F(StaDesignTest, SetCmdNamespace) { CmdNamespace orig = sta_->cmdNamespace(); sta_->setCmdNamespace(CmdNamespace::sta); EXPECT_EQ(sta_->cmdNamespace(), CmdNamespace::sta); sta_->setCmdNamespace(CmdNamespace::sdc); EXPECT_EQ(sta_->cmdNamespace(), CmdNamespace::sdc); sta_->setCmdNamespace(orig); } // --- Sta: endpoints --- TEST_F(StaDesignTest, Endpoints2) { VertexSet *eps = sta_->endpoints(); EXPECT_NE(eps, nullptr); if (eps) EXPECT_GT(eps->size(), 0u); } // --- Sta: worst slack vertex --- TEST_F(StaDesignTest, WorstSlackVertex) { ASSERT_NO_THROW(( [&](){ Slack ws; Vertex *v; sta_->worstSlack(MinMax::max(), ws, v); (void)ws; (void)v; }() )); } } // namespace sta