#include #include #include #include #include #include #include #include "MinMax.hh" #include "Transition.hh" #include "Property.hh" #include "ExceptionPath.hh" #include "TimingRole.hh" #include "Scene.hh" #include "Mode.hh" #include "Sta.hh" #include "Sdc.hh" #include "ReportTcl.hh" #include "RiseFallMinMax.hh" #include "Variables.hh" #include "PocvMode.hh" #include "LibertyClass.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/CheckCapacitances.hh" #include "search/CheckSlews.hh" #include "search/CheckFanouts.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->cmdSdc(), nullptr); EXPECT_FALSE(sta->scenes().empty()); if (!sta->scenes().empty()) EXPECT_GE(sta->scenes().size(), 1); EXPECT_NE(sta->cmdScene(), 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_); Scene *corner = sta_->cmdScene(); 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, "", sta_->cmdMode()); // Set input delays Pin *in1 = network->findPin(top, "in1"); Pin *in2 = network->findPin(top, "in2"); Clock *clk = sta_->cmdSdc()->findClock("clk"); if (in1 && clk) { sta_->setInputDelay(in1, RiseFallBoth::riseFall(), clk, RiseFall::rise(), nullptr, false, false, MinMaxAll::all(), true, 0.0f, sta_->cmdSdc()); } if (in2 && clk) { sta_->setInputDelay(in2, RiseFallBoth::riseFall(), clk, RiseFall::rise(), nullptr, false, false, MinMaxAll::all(), true, 0.0f, sta_->cmdSdc()); } 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; StringSeq group_names; }; 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(); EXPECT_TRUE(seeded); }() )); } TEST_F(StaDesignTest, SearchArrivalsAtEndpoints) { ASSERT_NO_THROW(( [&](){ sta_->findRequireds(); Search *search = sta_->search(); bool exist = search->requiredsExist(); EXPECT_TRUE(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); EXPECT_FALSE(std::isinf(wns)); } }() )); } TEST_F(StaDesignTest, SearchDeratedDelay) { Search *search = sta_->search(); Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); Scene *corner = sta_->cmdScene(); const size_t path_idx = corner->pathIndex(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, MinMax::max(), corner->dcalcAnalysisPtIndex(MinMax::max()), sta_->cmdSdc()); EXPECT_FALSE(std::isinf(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); EXPECT_TRUE(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::genclks() removed Search *search = sta_->search(); (void)search; } 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(sta_->cmdMode()); Pin *clk_pin = findPin("r1/CK"); if (clk_pin) { bool is_clk = sta_->isClock(clk_pin, sta_->cmdMode()); EXPECT_TRUE(is_clk); } }() )); } TEST_F(StaDesignTest, StaIsClockNet) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); sta_->ensureClkNetwork(sta_->cmdMode()); Pin *clk_pin = findPin("r1/CK"); if (clk_pin) { Net *net = network->net(clk_pin); if (net) { bool is_clk = sta_->isClock(net, sta_->cmdMode()); EXPECT_TRUE(is_clk); } } }() )); } TEST_F(StaDesignTest, StaIsIdealClock) { ASSERT_NO_THROW(( [&](){ sta_->ensureClkNetwork(sta_->cmdMode()); Pin *clk_pin = findPin("r1/CK"); if (clk_pin) { bool is_ideal = sta_->isIdealClock(clk_pin, sta_->cmdMode()); EXPECT_TRUE(is_ideal); } }() )); } TEST_F(StaDesignTest, StaIsPropagatedClock) { ASSERT_NO_THROW(( [&](){ sta_->ensureClkNetwork(sta_->cmdMode()); Pin *clk_pin = findPin("r1/CK"); if (clk_pin) { bool is_prop = sta_->isPropagatedClock(clk_pin, sta_->cmdMode()); EXPECT_FALSE(is_prop); } }() )); } TEST_F(StaDesignTest, StaPins) { Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); sta_->ensureClkNetwork(sta_->cmdMode()); const PinSet *pins = sta_->pins(clk, sta_->cmdMode()); EXPECT_NE(pins, nullptr); } TEST_F(StaDesignTest, StaStartpointPins) { // startpointPins() is declared in Sta.hh but not defined - skip } TEST_F(StaDesignTest, StaEndpointPins) { PinSet endpoints = sta_->endpointPins(); EXPECT_GE(endpoints.size(), 1u); } TEST_F(StaDesignTest, StaEndpoints) { VertexSet &endpoints = sta_->endpoints(); // endpoints() returns reference, always valid EXPECT_GE(endpoints.size(), 1u); } TEST_F(StaDesignTest, StaEndpointViolationCount) { ASSERT_NO_THROW(( [&](){ int count = sta_->endpointViolationCount(MinMax::max()); EXPECT_GE(count, 0); }() )); } TEST_F(StaDesignTest, StaTotalNegativeSlack) { ASSERT_NO_THROW(( [&](){ Slack tns = sta_->totalNegativeSlack(MinMax::max()); EXPECT_FALSE(std::isinf(tns)); }() )); } TEST_F(StaDesignTest, StaTotalNegativeSlackCorner) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->cmdScene(); Slack tns = sta_->totalNegativeSlack(corner, MinMax::max()); EXPECT_FALSE(std::isinf(tns)); }() )); } TEST_F(StaDesignTest, StaWorstSlack) { ASSERT_NO_THROW(( [&](){ Slack wns = sta_->worstSlack(MinMax::max()); EXPECT_FALSE(std::isinf(wns)); }() )); } TEST_F(StaDesignTest, StaWorstSlackVertex) { ASSERT_NO_THROW(( [&](){ Slack worst_slack; Vertex *worst_vertex; sta_->worstSlack(MinMax::max(), worst_slack, worst_vertex); EXPECT_FALSE(std::isinf(worst_slack)); EXPECT_NE(worst_vertex, nullptr); }() )); } TEST_F(StaDesignTest, StaWorstSlackCornerVertex) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->cmdScene(); Slack worst_slack; Vertex *worst_vertex; sta_->worstSlack(corner, MinMax::max(), worst_slack, worst_vertex); EXPECT_FALSE(std::isinf(worst_slack)); EXPECT_NE(worst_vertex, nullptr); }() )); } TEST_F(StaDesignTest, StaVertexWorstSlackPath) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstSlackPath(v, MinMax::max()); EXPECT_NE(path, nullptr); } TEST_F(StaDesignTest, StaVertexWorstSlackPathRf) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstSlackPath(v, RiseFall::rise(), MinMax::max()); EXPECT_NE(path, nullptr); } TEST_F(StaDesignTest, StaVertexWorstRequiredPath) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstRequiredPath(v, MinMax::max()); EXPECT_NE(path, nullptr); } TEST_F(StaDesignTest, StaVertexWorstRequiredPathRf) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstRequiredPath(v, RiseFall::rise(), MinMax::max()); EXPECT_NE(path, nullptr); } TEST_F(StaDesignTest, StaVertexWorstArrivalPathRf) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, RiseFall::rise(), MinMax::max()); EXPECT_NE(path, nullptr); } TEST_F(StaDesignTest, StaVertexSlacks) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); sta_->slack(v, MinMax::max()); // slacks should be populated } TEST_F(StaDesignTest, StaVertexSlewRfCorner) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); Scene *corner = sta_->cmdScene(); Slew slew = sta_->slew(v, RiseFallBoth::rise(), sta_->scenes(), MinMax::max()); EXPECT_FALSE(std::isinf(slew)); } TEST_F(StaDesignTest, StaVertexSlewRfMinMax) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); Slew slew = sta_->slew(v, RiseFallBoth::rise(), sta_->scenes(), MinMax::max()); EXPECT_FALSE(std::isinf(slew)); } TEST_F(StaDesignTest, StaVertexRequiredRfPathAP) { Vertex *v = findVertex("r3/D"); ASSERT_NE(v, nullptr); Scene *corner = sta_->cmdScene(); const size_t path_idx = corner->pathIndex(MinMax::max()); Required req = sta_->required(v, RiseFallBoth::rise(), sta_->scenes(), MinMax::max()); EXPECT_FALSE(std::isinf(req)); } TEST_F(StaDesignTest, StaVertexArrivalClkEdge) { // vertexArrival removed; use arrival() instead Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Arrival arr = sta_->arrival(v, RiseFallBoth::rise(), sta_->scenes(), MinMax::max()); EXPECT_FALSE(std::isinf(arr)); } // --- Sta: CheckTiming --- TEST_F(StaDesignTest, CheckTiming2) { ASSERT_NO_THROW(( [&](){ CheckErrorSeq &errors = sta_->checkTiming(sta_->cmdMode(), true, true, true, true, true, true, true); EXPECT_GE(errors.size(), 0u); }() )); } TEST_F(StaDesignTest, CheckTimingNoInputDelay) { ASSERT_NO_THROW(( [&](){ CheckErrorSeq &errors = sta_->checkTiming(sta_->cmdMode(), true, false, false, false, false, false, false); EXPECT_GE(errors.size(), 0u); }() )); } TEST_F(StaDesignTest, CheckTimingNoOutputDelay) { ASSERT_NO_THROW(( [&](){ CheckErrorSeq &errors = sta_->checkTiming(sta_->cmdMode(), false, true, false, false, false, false, false); EXPECT_GE(errors.size(), 0u); }() )); } TEST_F(StaDesignTest, CheckTimingUnconstrained) { ASSERT_NO_THROW(( [&](){ CheckErrorSeq &errors = sta_->checkTiming(sta_->cmdMode(), false, false, false, false, true, false, false); EXPECT_GE(errors.size(), 0u); }() )); } TEST_F(StaDesignTest, CheckTimingLoops) { ASSERT_NO_THROW(( [&](){ CheckErrorSeq &errors = sta_->checkTiming(sta_->cmdMode(), false, false, false, false, false, true, false); EXPECT_GE(errors.size(), 0u); }() )); } // --- Sta: delay calc --- TEST_F(StaDesignTest, ReportDelayCalc2) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); Scene *corner = sta_->cmdScene(); 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(); EXPECT_TRUE(enabled); sta_->setCrprEnabled(true); EXPECT_TRUE(sta_->crprEnabled()); sta_->setCrprEnabled(false); } TEST_F(StaDesignTest, CrprMode) { CrprMode mode = sta_->crprMode(); EXPECT_EQ(mode, CrprMode::same_pin); sta_->setCrprMode(CrprMode::same_pin); EXPECT_EQ(sta_->crprMode(), CrprMode::same_pin); } // --- Sta: propagateGatedClockEnable --- TEST_F(StaDesignTest, PropagateGatedClockEnable) { bool prop = sta_->propagateGatedClockEnable(); EXPECT_TRUE(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(); EXPECT_EQ(ns, CmdNamespace::sdc); }() )); } TEST_F(StaDesignTest, CmdCorner) { Scene *corner = sta_->cmdScene(); EXPECT_NE(corner, nullptr); } TEST_F(StaDesignTest, FindCorner) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->findScene("default"); EXPECT_NE(corner, nullptr); }() )); } TEST_F(StaDesignTest, MultiCorner) { ASSERT_NO_THROW(( [&](){ bool multi = sta_->multiScene(); EXPECT_FALSE(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(); EXPECT_NE(start, nullptr); } } } // --- Sta: Timing derate --- TEST_F(StaDesignTest, SetTimingDerate) { ASSERT_NO_THROW(( [&](){ sta_->setTimingDerate(TimingDerateType::cell_delay, PathClkOrData::clk, RiseFallBoth::riseFall(), EarlyLate::early(), 0.95f, sta_->cmdSdc()); sta_->unsetTimingDerate(sta_->cmdSdc()); }() )); } // --- Sta: setArcDelay --- TEST_F(StaDesignTest, SetArcDelay) { Vertex *v = findVertex("u1/Z"); ASSERT_NE(v, nullptr); Scene *corner = sta_->cmdScene(); 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()); EXPECT_FALSE(std::isinf(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_->cmdMode()); }() )); } // --- 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_->cmdSdc()); } } }() )); } // --- Sta: PVT --- TEST_F(StaDesignTest, GetPvt) { ASSERT_NO_THROW(( [&](){ Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); sta_->pvt(top, MinMax::max(), sta_->cmdSdc()); }() )); } // --- ClkNetwork --- TEST_F(StaDesignTest, ClkNetworkIsClock) { ASSERT_NO_THROW(( [&](){ ClkNetwork *clk_network = sta_->cmdMode()->clkNetwork(); if (clk_network) { Pin *clk_pin = findPin("r1/CK"); if (clk_pin) { bool is_clk = clk_network->isClock(clk_pin); EXPECT_TRUE(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->scene()->index(); EXPECT_GE(idx, 0); } } }() )); } 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) { Tag::cmp(t0, t1, sta_); Tag::matchCmp(t0, t1, true, sta_); } } }() )); } 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_); EXPECT_GT(h, 0u); size_t mh = t->matchHash(true, sta_); EXPECT_GT(mh, 0u); } } }() )); } 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); EXPECT_GT(h0, 0u); EXPECT_GT(h1, 0u); TagMatchEqual eq(true, sta_); bool result = eq(t0, t1); EXPECT_FALSE(result); } } }() )); } // --- ClkInfo operations --- TEST_F(StaDesignTest, ClkInfoAccessors2) { Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path) { Tag *tag = path->tag(sta_); if (tag) { const ClkInfo *clk_info = tag->clkInfo(); if (clk_info) { const ClockEdge *edge = clk_info->clkEdge(); EXPECT_NE(edge, nullptr); bool prop = clk_info->isPropagated(); EXPECT_FALSE(prop); bool gen = clk_info->isGenClkSrcPath(); EXPECT_FALSE(gen); PathAPIndex idx = clk_info->scene()->index(); EXPECT_GE(idx, 0); } } } } // --- Sim --- TEST_F(StaDesignTest, SimLogicValue2) { // Sim access removed from Sta Pin *pin = findPin("r1/D"); if (pin) { LogicValue val = sta_->simLogicValue(pin, sta_->cmdMode()); EXPECT_GE(static_cast(val), 0); } } TEST_F(StaDesignTest, SimLogicZeroOne) { // logicZeroOne removed from API Pin *pin = findPin("r1/D"); EXPECT_NE(pin, nullptr); } TEST_F(StaDesignTest, SimEnsureConstantsPropagated) { Sim *sim = sta_->cmdMode()->sim(); ASSERT_NE(sim, nullptr); sim->ensureConstantsPropagated(); } TEST_F(StaDesignTest, SimFunctionSense) { Sim *sim = sta_->cmdMode()->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); EXPECT_NE(sense, TimingSense::unknown); } } } // --- 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) { Scene *corner = sta_->cmdScene(); // ParasiticAnalysisPt and findParasiticAnalysisPt removed from API // makeParasiticNetwork API changed } } }() )); } // --- 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_); EXPECT_NE(tag, nullptr); Arrival arr = path->arrival(); EXPECT_FALSE(std::isinf(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(); EXPECT_NE(prev, nullptr); TimingArc *prev_arc = path->prevArc(sta_); EXPECT_NE(prev_arc, nullptr); Edge *prev_edge = path->prevEdge(sta_); EXPECT_NE(prev_edge, nullptr); } } // --- PathExpanded: with clk path --- TEST_F(StaDesignTest, PathExpandedWithClk) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, 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); EXPECT_NE(p, nullptr); } } } }() )); } // --- 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, sta_->cmdMode()); EXPECT_FALSE(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()); enables = gc->gatedClkEnables(v, sta_->cmdMode()); EXPECT_GE(enables.size(), 0u); } }() )); } // --- Genclks --- TEST_F(StaDesignTest, GenclksClear) { ASSERT_NO_THROW(( [&](){ // Search::genclks() removed from API // genclks removed from Search API }() )); } // --- Search: visitStartpoints/visitEndpoints --- TEST_F(StaDesignTest, SearchVisitEndpoints2) { PinSet pins = sta_->endpointPins(); EXPECT_GE(pins.size(), 1u); } TEST_F(StaDesignTest, SearchVisitStartpoints2) { // startpointPins() is declared but not defined; use findFaninPins with // startpoints_only=true from an output pin to verify startpoints exist. Pin *out_pin = findPin("out"); ASSERT_NE(out_pin, nullptr); PinSeq to_pins; to_pins.push_back(out_pin); PinSet pins = sta_->findFaninPins(&to_pins, true, true, 10, 10, false, false, sta_->cmdMode()); 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, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { PathGroup *pg = ends[0]->pathGroup(); if (pg) { const std::string &name = pg->name(); EXPECT_FALSE(name.empty()); } } }() )); } TEST_F(StaDesignTest, PathGroups) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); EXPECT_FALSE(ends.empty()); if (ends.empty() == false) { PathGroup *pg = ends[0]->pathGroup(); EXPECT_NE(pg, nullptr); if (pg) { EXPECT_FALSE(pg->name().empty()); } } }() )); } // --- VertexPathIterator with PathAnalysisPt --- TEST_F(StaDesignTest, VertexPathIteratorPathAP) { // vertexPathIterator removed; use vertexWorstArrivalPath instead Vertex *v = findVertex("r1/Q"); ASSERT_NE(v, nullptr); Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path && path->isNull() == false) { EXPECT_NE(path->tag(sta_), nullptr); } } // --- Sta: setOutputDelay and find unconstrained --- TEST_F(StaDesignTest, SetOutputDelayAndCheck) { Pin *out = findPin("out"); ASSERT_NE(out, nullptr); Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); sta_->setOutputDelay(out, RiseFallBoth::riseFall(), clk, RiseFall::rise(), nullptr, false, false, MinMaxAll::all(), true, 2.0f, sta_->cmdSdc()); sta_->updateTiming(true); // Now find paths to output PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 1, false, false, -INF, INF, false, group_names, true, false, false, false, false, false); // Should have paths including output delay EXPECT_GT(ends.size(), 0u); } // --- Sta: unique_edges findPathEnds --- TEST_F(StaDesignTest, FindPathEndsUniqueEdges) { ASSERT_NO_THROW(( [&](){ PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->scenes(), MinMaxAll::max(), 10, 3, false, true, -INF, INF, false, group_names, true, false, false, false, false, false); EXPECT_GE(ends.size(), 0u); }() )); } // --- Sta: corner path analysis pt --- TEST_F(StaDesignTest, CornerPathAnalysisPt) { Scene *corner = sta_->cmdScene(); ASSERT_NE(corner, nullptr); const size_t max_ap = corner->pathIndex(MinMax::max()); EXPECT_GE(max_ap, 0u); const size_t min_ap = corner->pathIndex(MinMax::min()); EXPECT_GE(min_ap, 0u); } // --- Sta: incrementalDelayTolerance --- TEST_F(StaDesignTest, IncrementalDelayTolerance) { ASSERT_NO_THROW(( [&](){ sta_->setIncrementalDelayTolerance(0.01f); }() )); } // --- Sta: pocvMode --- TEST_F(StaDesignTest, PocvMode) { ASSERT_NO_THROW(( [&](){ PocvMode mode = sta_->pocvMode(); EXPECT_EQ(mode, PocvMode::scalar); }() )); } // --- 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_->arrival(v, RiseFallBoth::riseFall(), sta_->scenes(), MinMax::max()); EXPECT_FALSE(std::isinf(arr)); Required req = sta_->required(v, RiseFallBoth::riseFall(), sta_->scenes(), MinMax::max()); EXPECT_FALSE(std::isinf(req)); } // --- Sta: activity --- TEST_F(StaDesignTest, PinActivity) { Pin *pin = findPin("r1/Q"); ASSERT_NE(pin, nullptr); PwrActivity act = sta_->activity(pin, sta_->cmdScene()); EXPECT_GE(act.density(), 0.0f); } // --- 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); EXPECT_TRUE(is_start); } }() )); } TEST_F(StaDesignTest, IsSegmentStart) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Pin *pin = findPin("in1"); if (pin) { // Search::isSegmentStart removed from API bool is_seg = false; EXPECT_FALSE(is_seg); } }() )); } // --- Search: clockInsertion --- TEST_F(StaDesignTest, ClockInsertion) { Search *search = sta_->search(); Clock *clk = sta_->cmdSdc()->findClock("clk"); ASSERT_NE(clk, nullptr); Pin *pin = findPin("r1/CK"); if (pin) { Scene *corner = sta_->cmdScene(); const size_t path_idx = corner->pathIndex(MinMax::max()); Arrival ins = search->clockInsertion(clk, pin, RiseFall::rise(), MinMax::max(), EarlyLate::late(), sta_->cmdMode()); EXPECT_FALSE(std::isinf(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(); EXPECT_GE(endpoints.size(), 0u); }() )); } // --- 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, sta_->cmdMode()); EXPECT_GE(fanout.size(), 1u); } // --- Sta: search endpointsInvalid --- TEST_F(StaDesignTest, EndpointsInvalid2) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); search->endpointsInvalid(); }() )); } // --- Sta: delaysInvalid (constraintsChanged was removed) --- TEST_F(StaDesignTest, DelaysInvalid3) { ASSERT_NO_THROW(( [&](){ sta_->delaysInvalid(); }() )); } // --- Sta: networkChanged --- TEST_F(StaDesignTest, NetworkChanged2) { ASSERT_NO_THROW(( [&](){ sta_->networkChanged(); }() )); } // --- Sta: clkPinsInvalid --- TEST_F(StaDesignTest, ClkPinsInvalid) { ASSERT_NO_THROW(( [&](){ sta_->clkPinsInvalid(sta_->cmdMode()); }() )); } // --- PropertyValue constructors and types --- TEST_F(StaDesignTest, PropertyValueConstructors) { PropertyValue pv1; EXPECT_EQ(pv1.type(), PropertyValue::Type::none); PropertyValue pv2(std::string("test")); EXPECT_EQ(pv2.type(), PropertyValue::Type::string); EXPECT_EQ(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, sta_->cmdSdc()); const Pvt *pvt = sta_->pvt(top, MinMax::max(), sta_->cmdSdc()); EXPECT_NE(pvt, nullptr); }() )); } // --- Search: propagateClkSense --- TEST_F(StaDesignTest, SearchClkPathArrival2) { ASSERT_NO_THROW(( [&](){ Search *search = sta_->search(); Vertex *v = findVertex("r1/CK"); if (v) { Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path) { Arrival arr = search->clkPathArrival(path); EXPECT_FALSE(std::isinf(arr)); } } }() )); } // ============================================================ // 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"); EXPECT_NE(pv.type(), PropertyValue::Type::none); PropertyValue pv2 = props.getProperty(pin, "arrival_max_fall"); EXPECT_NE(pv2.type(), PropertyValue::Type::none); } }() )); } 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"); EXPECT_NE(pv.type(), PropertyValue::Type::none); PropertyValue pv2 = props.getProperty(pin, "slack_min"); EXPECT_NE(pv2.type(), PropertyValue::Type::none); } }() )); } 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"); EXPECT_NE(pv.type(), PropertyValue::Type::none); PropertyValue pv2 = props.getProperty(pin, "slack_min_fall"); EXPECT_NE(pv2.type(), PropertyValue::Type::none); } }() )); } 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"); EXPECT_NE(pv.type(), PropertyValue::Type::none); } } }() )); } 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"); EXPECT_NE(pv.type(), PropertyValue::Type::none); } LibertyLibrary *lib = network->defaultLibertyLibrary(); if (lib) { PropertyValue pv = props.getProperty(lib, "name"); EXPECT_NE(pv.type(), PropertyValue::Type::none); } }() )); } 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"); EXPECT_EQ(pv.type(), PropertyValue::Type::none); } 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(std::string("test_string")); EXPECT_EQ(pv.type(), PropertyValue::Type::string); try { float val = pv.floatValue(); EXPECT_GE(val, 0.0f); } 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(sta_->cmdMode(), true, true, true, true, true, true, true); EXPECT_GE(errors.size(), 0u); CheckErrorSeq &errors2 = sta_->checkTiming(sta_->cmdMode(), true, true, true, true, true, true, true); EXPECT_GE(errors2.size(), 0u); }() )); } // --- 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(); EXPECT_NE(vert, nullptr); 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) { Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path) { Tag *tag = path->tag(sta_); if (tag) { const ClkInfo *clk_info = tag->clkInfo(); if (clk_info) { const ClockEdge *edge = clk_info->clkEdge(); EXPECT_NE(edge, nullptr); bool prop = clk_info->isPropagated(); EXPECT_FALSE(prop); bool gen = clk_info->isGenClkSrcPath(); EXPECT_FALSE(gen); } } } } } }() )); } // --- Tag: pathAPIndex --- TEST_F(StaDesignTest, TagPathAPIndex2) { Vertex *v = findVertex("r1/D"); if (v) { Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path) { Tag *tag = path->tag(sta_); if (tag) { int ap_idx = tag->scene()->index(); EXPECT_GE(ap_idx, 0); } } } } // --- Path: tagIndex, prevVertex --- TEST_F(StaDesignTest, PathAccessors) { ASSERT_NO_THROW(( [&](){ Vertex *v = findVertex("r1/D"); if (v) { Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path) { TagIndex ti = path->tagIndex(sta_); EXPECT_GE(ti, 0); Vertex *prev = path->prevVertex(sta_); EXPECT_NE(prev, nullptr); } } }() )); } // --- PathGroup constructor --- TEST_F(StaDesignTest, PathGroupConstructor) { // Search::findPathGroup removed from API Search *search = sta_->search(); EXPECT_NE(search, nullptr); } // --- PathLess --- TEST_F(StaDesignTest, PathLessComparator) { Vertex *v = findVertex("r1/D"); if (v) { Path *wpath = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (wpath && wpath->isNull() == false) { PathLess less(sta_); bool result = less(wpath, wpath); EXPECT_FALSE(result); } } } // --- PathEnd methods on real path ends --- TEST_F(StaDesignTest, PathEndTargetClkMethods) { ASSERT_NO_THROW(( [&](){ const SceneSeq &corners = sta_->scenes(); Scene *corner = corners[0]; PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (PathEnd *pe : ends) { const Clock *tgt_clk = pe->targetClk(sta_); EXPECT_NE(tgt_clk, nullptr); Arrival tgt_arr = pe->targetClkArrival(sta_); EXPECT_FALSE(std::isinf(tgt_arr)); Delay tgt_delay = pe->targetClkDelay(sta_); EXPECT_FALSE(std::isinf(tgt_delay)); Delay tgt_ins = pe->targetClkInsertionDelay(sta_); EXPECT_FALSE(std::isinf(tgt_ins)); float non_inter = pe->targetNonInterClkUncertainty(sta_); EXPECT_FALSE(std::isinf(non_inter)); float inter = pe->interClkUncertainty(sta_); EXPECT_FALSE(std::isinf(inter)); float tgt_unc = pe->targetClkUncertainty(sta_); EXPECT_FALSE(std::isinf(tgt_unc)); float mcp_adj = pe->targetClkMcpAdjustment(sta_); EXPECT_FALSE(std::isinf(mcp_adj)); } }() )); } TEST_F(StaDesignTest, PathEndUnconstrainedMethods) { ASSERT_NO_THROW(( [&](){ const SceneSeq &corners = sta_->scenes(); Scene *corner = corners[0]; PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, true, corners, MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (PathEnd *pe : ends) { if (pe->isUnconstrained()) { Required req = pe->requiredTime(sta_); EXPECT_FALSE(std::isinf(req)); break; } } }() )); } // --- PathEndPathDelay methods --- TEST_F(StaDesignTest, PathEndPathDelay) { sta_->makePathDelay(nullptr, nullptr, nullptr, MinMax::max(), false, false, 5.0, "", sta_->cmdSdc()); sta_->updateTiming(true); const SceneSeq &corners = sta_->scenes(); Scene *corner = corners[0]; PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 10, 10, true, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (PathEnd *pe : ends) { if (pe->isPathDelay()) { EXPECT_EQ(pe->type(), PathEnd::Type::path_delay); const char *tn = pe->typeName(); EXPECT_NE(tn, nullptr); float tgt_time = pe->targetClkTime(sta_); EXPECT_FALSE(std::isinf(tgt_time)); float tgt_off = pe->targetClkOffset(sta_); EXPECT_FALSE(std::isinf(tgt_off)); break; } } } // --- ReportPath methods via sta_ calls --- TEST_F(StaDesignTest, ReportPathShortMinPeriod2) { ASSERT_NO_THROW(( [&](){ // minPeriodViolations/reportCheck removed; just report checks sta_->reportMinPeriodChecks(nullptr, 10, false, false, sta_->scenes()); sta_->reportMinPeriodChecks(nullptr, 10, true, false, sta_->scenes()); }() )); } TEST_F(StaDesignTest, ReportPathCheckMaxSkew2) { ASSERT_NO_THROW(( [&](){ // maxSkewViolations/reportCheck removed; just report checks sta_->reportMaxSkewChecks(nullptr, 10, false, false, sta_->scenes()); sta_->reportMaxSkewChecks(nullptr, 10, true, false, sta_->scenes()); }() )); } // --- ReportPath full report --- TEST_F(StaDesignTest, ReportPathFullReport) { ASSERT_NO_THROW(( [&](){ const SceneSeq &corners = sta_->scenes(); Scene *corner = corners[0]; sta_->setReportPathFormat(ReportPathFormat::full); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { PathEnd *pe = ends[0]; sta_->reportPathEnd(pe); } }() )); } TEST_F(StaDesignTest, ReportPathFullClkExpanded) { ASSERT_NO_THROW(( [&](){ const SceneSeq &corners = sta_->scenes(); Scene *corner = corners[0]; sta_->setReportPathFormat(ReportPathFormat::full_clock_expanded); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, group_names, 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); const SceneSeq &corners = sta_->scenes(); Scene *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(( [&](){ const SceneSeq &corners = sta_->scenes(); Scene *corner = corners[0]; PathAPIndex path_idx = corner->pathIndex(MinMax::max()); { WnsSlackLess less(path_idx, sta_); Vertex *v1 = findVertex("r1/D"); Vertex *v2 = findVertex("r2/D"); if (v1 && v2) { less(v1, v2); } } }() )); } // --- 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) { Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path) { Arrival arr = search->pathClkPathArrival(path); EXPECT_FALSE(std::isinf(arr)); } } }() )); } // --- 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 access removed from Sta LogicValue val = sta_->simLogicValue(pin, sta_->cmdMode()); EXPECT_GE(static_cast(val), 0); } }() )); } // --- 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_->cmdSdc()->findClock("clk"); if (clk) { clks.push_back(clk); const SceneSeq &corners = sta_->scenes(); Scene *corner = corners[0]; sta_->reportClkSkew(clks, sta_->scenes(), 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_->cmdSdc()->findClock("clk"); if (clk) { clks.push_back(clk); const SceneSeq &corners = sta_->scenes(); Scene *corner = corners[0]; sta_->reportClkSkew(clks, sta_->scenes(), MinMax::max(), true, 3); } }() )); } // --- MaxSkewCheck accessors --- TEST_F(StaDesignTest, MaxSkewCheckAccessors) { // maxSkewViolations removed; verify MaxSkewCheck default constructor MaxSkewCheck check; EXPECT_TRUE(check.isNull()); MaxSkewSlackLess less(sta_); } // --- MinPeriodSlackLess --- TEST_F(StaDesignTest, MinPeriodCheckAccessors) { // minPeriodViolations removed; verify MinPeriodSlackLess constructor MinPeriodSlackLess less(sta_); sta_->reportMinPeriodChecks(nullptr, 10, false, false, sta_->scenes()); } // --- MinPulseWidthCheck: corner --- TEST_F(StaDesignTest, MinPulseWidthCheckCorner) { // minPulseWidthChecks removed; test reportMinPulseWidthChecks sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes()); } TEST_F(StaDesignTest, MinPulseWidthSlack3) { // minPulseWidthSlack removed; test reportMinPulseWidthChecks sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes()); } // --- 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_->cmdSdc()); sta_->removeDataCheck(from_pin, RiseFallBoth::riseFall(), to_pin, RiseFallBoth::riseFall(), nullptr, MinMaxAll::max(), sta_->cmdSdc()); } }() )); } // --- PathEnum via multiple path ends --- TEST_F(StaDesignTest, PathEnum) { const SceneSeq &corners = sta_->scenes(); Scene *corner = corners[0]; PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 3, 3, true, false, -INF, INF, false, group_names, 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()); EXPECT_FALSE(std::isinf(tns_max)); Slack tns_min = sta_->totalNegativeSlack(MinMax::min()); EXPECT_FALSE(std::isinf(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_->cmdSdc()->findClock("clk"); if (out && clk) { sta_->setOutputDelay(out, RiseFallBoth::riseFall(), clk, RiseFall::rise(), nullptr, false, false, MinMaxAll::all(), true, 2.0f, sta_->cmdSdc()); sta_->updateTiming(true); const SceneSeq &corners = sta_->scenes(); Scene *corner = corners[0]; PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, group_names, 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(sta_->cmdSdc(), 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_->cmdSdc()->findClock("clk"); if (out && clk) { sta_->setOutputDelay(out, RiseFallBoth::riseFall(), clk, RiseFall::rise(), nullptr, false, false, MinMaxAll::all(), true, 2.0f, sta_->cmdSdc()); } sta_->makeFalsePath(nullptr, nullptr, nullptr, MinMaxAll::all(), "", sta_->cmdSdc()); if (out) { Port *port = network->port(out); if (port) sta_->setPortExtPinCap(port, RiseFallBoth::riseFall(), MinMaxAll::all(), 0.5f, sta_->cmdSdc()); } std::string filename = makeUniqueSdcPath("test_write_sdc_r10_constrained.sdc"); sta_->writeSdc(sta_->cmdSdc(), 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(sta_->cmdSdc(), 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(sta_->cmdSdc(), filename.c_str(), true, false, 4, false, true); expectSdcFileReadable(filename); } // --- Path ends with sorting --- TEST_F(StaDesignTest, SaveEnumPath) { ASSERT_NO_THROW(( [&](){ const SceneSeq &corners = sta_->scenes(); Scene *corner = corners[0]; PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, group_names, true, false, false, false, false, false); EXPECT_GE(ends.size(), 0u); }() )); } TEST_F(StaDesignTest, ReportPathLess) { ASSERT_NO_THROW(( [&](){ const SceneSeq &corners = sta_->scenes(); Scene *corner = corners[0]; PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, group_names, true, false, false, false, false, false); EXPECT_GE(ends.size(), 0u); }() )); } // --- ClkDelays --- TEST_F(StaDesignTest, ClkDelaysDelay) { ASSERT_NO_THROW(( [&](){ Clock *clk = sta_->cmdSdc()->findClock("clk"); if (clk) { const SceneSeq &corners = sta_->scenes(); Scene *corner = corners[0]; float min_period = sta_->findClkMinPeriod(clk, corner); EXPECT_FALSE(std::isinf(min_period)); } }() )); } // --- Sta WriteSdc with Derating --- TEST_F(StaDesignTest, WriteSdcDerating) { sta_->setTimingDerate(TimingDerateType::cell_delay, PathClkOrData::data, RiseFallBoth::riseFall(), EarlyLate::early(), 0.95, sta_->cmdSdc()); sta_->setTimingDerate(TimingDerateType::net_delay, PathClkOrData::data, RiseFallBoth::riseFall(), EarlyLate::late(), 1.05, sta_->cmdSdc()); std::string filename = makeUniqueSdcPath("test_write_sdc_r10_derate.sdc"); sta_->writeSdc(sta_->cmdSdc(), 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, sta_->cmdSdc()); } } std::string filename = makeUniqueSdcPath("test_write_sdc_r10_disable.sdc"); sta_->writeSdc(sta_->cmdSdc(), filename.c_str(), false, false, 4, false, true); expectSdcFileReadable(filename); } // --- ClkInfoHash, ClkInfoEqual --- TEST_F(StaDesignTest, ClkInfoHashEqual) { Vertex *v = findVertex("r1/CK"); if (v) { Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path) { Tag *tag = path->tag(sta_); if (tag) { const ClkInfo *ci = tag->clkInfo(); if (ci) { ClkInfoHash hasher; size_t h = hasher(ci); EXPECT_GT(h, 0u); ClkInfoEqual eq(sta_); bool e = eq(ci, ci); EXPECT_TRUE(e); } } } } } // --- Report MPW checks --- TEST_F(StaDesignTest, ReportMpwChecksAll) { // minPulseWidthChecks removed; test reportMinPulseWidthChecks sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes()); } // --- Report min period checks --- TEST_F(StaDesignTest, ReportMinPeriodChecks) { // minPeriodViolations/reportCheck removed sta_->reportMinPeriodChecks(nullptr, 10, false, false, sta_->scenes()); } // --- Endpoints hold --- TEST_F(StaDesignTest, FindPathEndsHold3) { ASSERT_NO_THROW(( [&](){ const SceneSeq &corners = sta_->scenes(); Scene *corner = corners[0]; PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::min(), 5, 5, true, false, -INF, INF, false, group_names, false, true, false, false, false, false); for (PathEnd *pe : ends) { Required req = pe->requiredTime(sta_); EXPECT_FALSE(std::isinf(req)); Slack slack = pe->slack(sta_); EXPECT_FALSE(std::isinf(slack)); } }() )); } // --- Report path end as JSON --- TEST_F(StaDesignTest, ReportPathEndJson2) { ASSERT_NO_THROW(( [&](){ const SceneSeq &corners = sta_->scenes(); Scene *corner = corners[0]; sta_->setReportPathFormat(ReportPathFormat::json); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } // --- Report path end shorter --- TEST_F(StaDesignTest, ReportPathEndShorter) { ASSERT_NO_THROW(( [&](){ const SceneSeq &corners = sta_->scenes(); Scene *corner = corners[0]; sta_->setReportPathFormat(ReportPathFormat::shorter); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } // --- WriteSdc with clock groups --- TEST_F(StaDesignTest, WriteSdcWithClockGroups) { Clock *clk = sta_->cmdSdc()->findClock("clk"); if (clk) { ClockGroups *cg = sta_->makeClockGroups("test_group", true, false, false, false, "", sta_->cmdSdc()); EXPECT_NE(cg, nullptr); sta_->updateTiming(true); std::string filename = makeUniqueSdcPath("test_write_sdc_r10_clkgrp.sdc"); sta_->writeSdc(sta_->cmdSdc(), filename.c_str(), false, false, 4, false, true); expectSdcFileReadable(filename); } } // --- WriteSdc with inter-clock uncertainty --- TEST_F(StaDesignTest, WriteSdcInterClkUncertainty) { Clock *clk = sta_->cmdSdc()->findClock("clk"); if (clk) { sta_->setClockUncertainty(clk, RiseFallBoth::riseFall(), clk, RiseFallBoth::riseFall(), MinMaxAll::max(), 0.1f, sta_->cmdSdc()); std::string filename = makeUniqueSdcPath("test_write_sdc_r10_interclk.sdc"); sta_->writeSdc(sta_->cmdSdc(), filename.c_str(), false, false, 4, false, true); expectSdcFileReadable(filename); } } // --- WriteSdc with clock latency --- TEST_F(StaDesignTest, WriteSdcClockLatency) { Clock *clk = sta_->cmdSdc()->findClock("clk"); if (clk) { sta_->setClockLatency(clk, nullptr, RiseFallBoth::riseFall(), MinMaxAll::all(), 0.5f, sta_->cmdSdc()); std::string filename = makeUniqueSdcPath("test_write_sdc_r10_clklat.sdc"); sta_->writeSdc(sta_->cmdSdc(), 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, sta_->cmdMode()); // 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, sta_->cmdMode()); 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, sta_->cmdMode()); 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, sta_->cmdMode()); // May be empty if no async pins in the design EXPECT_GE(async_pins.size(), 0u); }() )); } // --- FindRegister: output pins --- TEST_F(StaDesignTest, FindRegisterOutputPins2) { ClockSet *clks = nullptr; PinSet out_pins = sta_->findRegisterOutputPins(clks, RiseFallBoth::riseFall(), true, true, sta_->cmdMode()); EXPECT_GT(out_pins.size(), 0u); } // --- FindRegister: with specific clock --- TEST_F(StaDesignTest, FindRegisterWithClock) { Sdc *sdc = sta_->cmdSdc(); 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, sta_->cmdMode()); // registers clocked by rise edge of "clk" EXPECT_GT(regs.size(), 0u); 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, sta_->cmdMode()); EXPECT_GT(regs.size(), 0u); }() )); } // --- FindRegister: latches only --- TEST_F(StaDesignTest, FindRegisterLatchesOnly) { ASSERT_NO_THROW(( [&](){ ClockSet *clks = nullptr; InstanceSet latches = sta_->findRegisterInstances(clks, RiseFallBoth::riseFall(), false, true, sta_->cmdMode()); EXPECT_GE(latches.size(), 0u); }() )); } // --- 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, sta_->cmdMode()); 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, sta_->cmdMode()); 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, sta_->cmdMode()); 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, sta_->cmdMode()); 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_->cmdSdc(); Clock *clk = sdc->findClock("clk"); if (clk) { sta_->setSlewLimit(clk, RiseFallBoth::riseFall(), PathClkOrData::clk, MinMax::max(), 2.0f, sta_->cmdSdc()); } }() )); } // --- 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_->cmdSdc()); } } }() )); } // --- 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, sta_->cmdSdc()); } } }() )); } // --- 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, sta_->cmdSdc()); } } }() )); } // --- 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_->cmdSdc()); } } }() )); } // --- 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_->cmdSdc()); } }() )); } // --- 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, sta_->cmdSdc()); } } }() )); } // --- 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_->cmdSdc()); } } }() )); } // --- Sta: setMaxArea --- TEST_F(StaDesignTest, SetMaxArea) { ASSERT_NO_THROW(( [&](){ sta_->setMaxArea(500.0f, sta_->cmdSdc()); }() )); } // --- Sta: setMinPulseWidth on clock --- TEST_F(StaDesignTest, SetMinPulseWidthClock) { ASSERT_NO_THROW(( [&](){ Sdc *sdc = sta_->cmdSdc(); Clock *clk = sdc->findClock("clk"); if (clk) { sta_->setMinPulseWidth(clk, RiseFallBoth::rise(), 0.3f, sta_->cmdSdc()); } }() )); } // --- Sta: MinPeriod checks --- TEST_F(StaDesignTest, MinPeriodSlack3) { ASSERT_NO_THROW(( [&](){ // minPeriodSlack removed // check variable removed // reportCheck removed // reportCheck removed }() )); } TEST_F(StaDesignTest, MinPeriodViolations3) { ASSERT_NO_THROW(( [&](){ // minPeriodViolations removed; just report checks sta_->reportMinPeriodChecks(nullptr, 10, true, false, sta_->scenes()); }() )); } // --- Sta: MaxSkew checks --- TEST_F(StaDesignTest, MaxSkewSlack3) { // maxSkewSlack/reportCheck removed sta_->reportMaxSkewChecks(nullptr, 10, false, false, sta_->scenes()); } TEST_F(StaDesignTest, MaxSkewViolations3) { ASSERT_NO_THROW(( [&](){ // maxSkewViolations removed; just report checks sta_->reportMaxSkewChecks(nullptr, 10, true, false, sta_->scenes()); }() )); } // --- 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, sta_->cmdMode()); 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, sta_->cmdSdc()); EXPECT_TRUE(is_clk_src); } if (in1) { bool is_clk_src = sta_->isClockSrc(in1, sta_->cmdSdc()); 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(); sta_->pvt(inst, MinMax::max(), sta_->cmdSdc()); } }() )); } // --- 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"); EXPECT_NE(val.type(), PropertyValue::Type::none); } }() )); } 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"); EXPECT_NE(val.type(), PropertyValue::Type::none); } } }() )); } // --- Property: getProperty on Clock --- TEST_F(StaDesignTest, PropertyClock) { ASSERT_NO_THROW(( [&](){ Sdc *sdc = sta_->cmdSdc(); Clock *clk = sdc->findClock("clk"); if (clk) { PropertyValue val = sta_->properties().getProperty(clk, "name"); EXPECT_NE(val.type(), PropertyValue::Type::none); PropertyValue val2 = sta_->properties().getProperty(clk, "period"); EXPECT_NE(val2.type(), PropertyValue::Type::none); PropertyValue val3 = sta_->properties().getProperty(clk, "sources"); EXPECT_NE(val3.type(), PropertyValue::Type::none); } }() )); } // --- MaxSkewCheck: detailed accessors --- TEST_F(StaDesignTest, MaxSkewCheckDetailedAccessors) { // maxSkewSlack/check removed; just report checks sta_->reportMaxSkewChecks(nullptr, 10, false, true, sta_->scenes()); } // --- MinPeriodCheck: detailed accessors --- TEST_F(StaDesignTest, MinPeriodCheckDetailedAccessors) { // minPeriodSlack/check removed; just report checks sta_->reportMinPeriodChecks(nullptr, 10, false, true, sta_->scenes()); } // --- Sta: WriteSdc with various limits --- TEST_F(StaDesignTest, WriteSdcWithSlewLimit) { Sdc *sdc = sta_->cmdSdc(); Clock *clk = sdc->findClock("clk"); if (clk) { sta_->setSlewLimit(clk, RiseFallBoth::riseFall(), PathClkOrData::data, MinMax::max(), 1.5f, sta_->cmdSdc()); } std::string filename = makeUniqueSdcPath("test_write_sdc_r10_slewlimit.sdc"); sta_->writeSdc(sta_->cmdSdc(), 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, sta_->cmdSdc()); } } std::string filename = makeUniqueSdcPath("test_write_sdc_r10_caplimit.sdc"); sta_->writeSdc(sta_->cmdSdc(), 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, sta_->cmdSdc()); } } std::string filename = makeUniqueSdcPath("test_write_sdc_r10_fanoutlimit.sdc"); sta_->writeSdc(sta_->cmdSdc(), 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_->cmdSdc(); 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, "", sta_->cmdMode()); Clock *gen = sdc->findClock("gen_clk"); EXPECT_NE(gen, nullptr); } } // --- Sta: removeAllClocks --- TEST_F(StaDesignTest, RemoveAllClocks) { Sdc *sdc = sta_->cmdSdc(); Clock *clk = sdc->findClock("clk"); ASSERT_NE(clk, nullptr); sta_->removeClock(clk, sta_->cmdSdc()); 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, sta_->cmdMode()); EXPECT_GE(fanin.size(), 0u); } }() )); } // --- 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, sta_->cmdMode()); EXPECT_GE(fanout.size(), 0u); } }() )); } // --- Sta: report unconstrained path ends --- TEST_F(StaDesignTest, ReportUnconstrained) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->cmdScene(); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, true, // unconstrained sta_->makeSceneSeq(corner), MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, group_names, 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(( [&](){ Scene *corner = sta_->cmdScene(); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::min(), 3, 3, true, false, -INF, INF, false, group_names, 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, sta_->cmdSdc()); // very tight limit to create violations } // checkSlewLimits renamed to reportSlewChecks sta_->reportSlewChecks(nullptr, 10, false, false, sta_->scenes(), MinMax::max()); // 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, sta_->cmdSdc()); sta_->checkSlewsPreamble(); const RiseFall *tr = nullptr; const Scene *scene_out = nullptr; Slew slew; float limit, slack; sta_->checkSlew(out, sta_->scenes(), MinMax::max(), false, slew, limit, slack, tr, scene_out); } }() )); } // --- 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, sta_->cmdSdc()); // very tight } // checkCapacitanceLimits renamed to reportCapacitanceChecks sta_->reportCapacitanceChecks(nullptr, 10, false, false, sta_->scenes(), MinMax::max()); // 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, sta_->cmdSdc()); sta_->checkCapacitancesPreamble(sta_->scenes()); const RiseFall *tr = nullptr; const Scene *scene_out = nullptr; float cap, limit, slack; sta_->checkCapacitance(out, sta_->scenes(), MinMax::max(), cap, limit, slack, tr, scene_out); } }() )); } // --- 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, sta_->cmdSdc()); // very tight } // checkFanoutLimits renamed to reportFanoutChecks sta_->reportFanoutChecks(nullptr, 10, false, false, sta_->scenes(), MinMax::max()); }() )); } // --- 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_->cmdSdc()); sta_->checkFanoutPreamble(); float fanout, limit, slack; sta_->checkFanout(out, sta_->cmdMode(), MinMax::max(), fanout, limit, slack); } }() )); } // --- Sta: reportClkSkew --- TEST_F(StaDesignTest, ReportClkSkew2) { ASSERT_NO_THROW(( [&](){ Sdc *sdc = sta_->cmdSdc(); Clock *clk = sdc->findClock("clk"); if (clk) { ConstClockSeq clks; clks.push_back(clk); Scene *corner = sta_->cmdScene(); sta_->reportClkSkew(clks, sta_->scenes(), MinMax::max(), false, 3); sta_->reportClkSkew(clks, sta_->scenes(), MinMax::min(), false, 3); } }() )); } // --- Sta: findWorstClkSkew --- TEST_F(StaDesignTest, FindWorstClkSkew3) { ASSERT_NO_THROW(( [&](){ float worst = sta_->findWorstClkSkew(MinMax::max(), false); EXPECT_FALSE(std::isinf(worst)); }() )); } // --- Sta: reportClkLatency --- TEST_F(StaDesignTest, ReportClkLatency3) { ASSERT_NO_THROW(( [&](){ Sdc *sdc = sta_->cmdSdc(); Clock *clk = sdc->findClock("clk"); if (clk) { ConstClockSeq clks; clks.push_back(clk); Scene *corner = sta_->cmdScene(); sta_->reportClkLatency(clks, sta_->scenes(), 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(); Scene *corner = sta_->cmdScene(); float limit; bool exists; sta_->findSlewLimit(port, corner, MinMax::max(), limit, exists); } } } }() )); } // --- Sta: MinPulseWidth violations --- TEST_F(StaDesignTest, MpwViolations) { // minPulseWidthViolations removed; test reportMinPulseWidthChecks sta_->reportMinPulseWidthChecks(nullptr, 10, true, false, sta_->scenes()); } // --- Sta: minPulseWidthSlack (all corners) --- TEST_F(StaDesignTest, MpwSlackAllCorners) { // minPulseWidthSlack removed; test reportMinPulseWidthChecks sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes()); } // --- Sta: minPulseWidthChecks (all) --- TEST_F(StaDesignTest, MpwChecksAll) { // minPulseWidthChecks removed; test reportMinPulseWidthChecks sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes()); } // --- Sta: WriteSdc with min pulse width + clock latency + all constraints --- TEST_F(StaDesignTest, WriteSdcFullConstraints) { Sdc *sdc = sta_->cmdSdc(); 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_->cmdSdc()); sta_->setSlewLimit(clk, RiseFallBoth::riseFall(), PathClkOrData::clk, MinMax::max(), 1.0f, sta_->cmdSdc()); sta_->setSlewLimit(clk, RiseFallBoth::riseFall(), PathClkOrData::data, MinMax::max(), 2.0f, sta_->cmdSdc()); sta_->setClockLatency(clk, nullptr, RiseFallBoth::rise(), MinMaxAll::max(), 0.3f, sta_->cmdSdc()); sta_->setClockLatency(clk, nullptr, RiseFallBoth::fall(), MinMaxAll::min(), 0.1f, sta_->cmdSdc()); } 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_->cmdSdc()); sta_->setDriveResistance(port, RiseFallBoth::fall(), MinMaxAll::min(), 50.0f, sta_->cmdSdc()); } sta_->setMinPulseWidth(in1, RiseFallBoth::rise(), 0.1f, sta_->cmdSdc()); } if (out) { Port *port = network->port(out); if (port) { sta_->setCapacitanceLimit(port, MinMax::max(), 0.5f, sta_->cmdSdc()); sta_->setFanoutLimit(port, MinMax::max(), 4.0f, sta_->cmdSdc()); sta_->setPortExtPinCap(port, RiseFallBoth::rise(), MinMaxAll::max(), 0.2f, sta_->cmdSdc()); sta_->setPortExtPinCap(port, RiseFallBoth::fall(), MinMaxAll::min(), 0.1f, sta_->cmdSdc()); } } 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(sta_->cmdSdc(), 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"); EXPECT_NE(val.type(), PropertyValue::Type::none); PropertyValue val2 = sta_->properties().getProperty(edge, "sense"); EXPECT_NE(val2.type(), PropertyValue::Type::none); } } } }() )); } // --- 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"); EXPECT_NE(val.type(), PropertyValue::Type::none); } 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"); EXPECT_NE(val.type(), PropertyValue::Type::none); PropertyValue val2 = sta_->properties().getProperty(port, "direction"); EXPECT_NE(val2.type(), PropertyValue::Type::none); } } }() )); } // --- 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"); EXPECT_NE(val.type(), PropertyValue::Type::none); PropertyValue val2 = sta_->properties().getProperty(lib_cell, "area"); EXPECT_NE(val2.type(), PropertyValue::Type::none); } } }() )); } // --- 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"); EXPECT_NE(val.type(), PropertyValue::Type::none); PropertyValue val2 = sta_->properties().getProperty(port, "direction"); EXPECT_NE(val2.type(), PropertyValue::Type::none); } } } }() )); } // --- 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"); EXPECT_NE(val.type(), PropertyValue::Type::none); } 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"); EXPECT_NE(val.type(), PropertyValue::Type::none); } }() )); } // --- 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"); EXPECT_NE(val.type(), PropertyValue::Type::none); break; // just test one } } } }() )); } // --- Sta: Property getProperty on PathEnd --- TEST_F(StaDesignTest, PropertyPathEnd) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->cmdScene(); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (const auto &end : ends) { if (end) { PropertyValue val = sta_->properties().getProperty(end, "startpoint"); EXPECT_NE(val.type(), PropertyValue::Type::none); PropertyValue val2 = sta_->properties().getProperty(end, "endpoint"); EXPECT_NE(val2.type(), PropertyValue::Type::none); PropertyValue val3 = sta_->properties().getProperty(end, "slack"); EXPECT_NE(val3.type(), PropertyValue::Type::none); break; // just test one } } }() )); } // --- Sta: Property getProperty on Path --- TEST_F(StaDesignTest, PropertyPath) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->cmdScene(); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, group_names, 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"); EXPECT_NE(val.type(), PropertyValue::Type::none); PropertyValue val2 = sta_->properties().getProperty(path, "arrival"); EXPECT_NE(val2.type(), PropertyValue::Type::none); } 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"); EXPECT_NE(val_arr.type(), PropertyValue::Type::none); PropertyValue val_arr2 = sta_->properties().getProperty(out, "arrival_max_fall"); EXPECT_NE(val_arr2.type(), PropertyValue::Type::none); PropertyValue val_arr3 = sta_->properties().getProperty(out, "arrival_min_rise"); EXPECT_NE(val_arr3.type(), PropertyValue::Type::none); PropertyValue val_arr4 = sta_->properties().getProperty(out, "arrival_min_fall"); EXPECT_NE(val_arr4.type(), PropertyValue::Type::none); // These trigger pinSlack internally PropertyValue val_slk = sta_->properties().getProperty(out, "slack_max"); EXPECT_NE(val_slk.type(), PropertyValue::Type::none); PropertyValue val_slk2 = sta_->properties().getProperty(out, "slack_max_rise"); EXPECT_NE(val_slk2.type(), PropertyValue::Type::none); PropertyValue val_slk3 = sta_->properties().getProperty(out, "slack_max_fall"); EXPECT_NE(val_slk3.type(), PropertyValue::Type::none); PropertyValue val_slk4 = sta_->properties().getProperty(out, "slack_min"); EXPECT_NE(val_slk4.type(), PropertyValue::Type::none); PropertyValue val_slk5 = sta_->properties().getProperty(out, "slack_min_rise"); EXPECT_NE(val_slk5.type(), PropertyValue::Type::none); PropertyValue val_slk6 = sta_->properties().getProperty(out, "slack_min_fall"); EXPECT_NE(val_slk6.type(), PropertyValue::Type::none); // Slew PropertyValue val_slew = sta_->properties().getProperty(out, "slew_max"); EXPECT_NE(val_slew.type(), PropertyValue::Type::none); } }() )); } // --- 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"); EXPECT_NE(val.type(), PropertyValue::Type::none); } } }() )); } // --- 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"); EXPECT_NE(val.type(), PropertyValue::Type::none); } }() )); } // --- 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"); EXPECT_EQ(val.type(), PropertyValue::Type::none); } catch (std::exception &e) { // Expected PropertyUnknown exception EXPECT_NE(e.what(), nullptr); } } }() )); } // --- Sta::reportClkSkew (triggers clkSkewPreamble) --- TEST_F(StaDesignTest, ReportClkSkew3) { ASSERT_NO_THROW(( [&](){ Clock *clk = sta_->cmdSdc()->findClock("clk"); if (clk) { ConstClockSeq clks; clks.push_back(clk); Scene *corner = sta_->cmdScene(); sta_->reportClkSkew(clks, sta_->scenes(), MinMax::max(), false, 4); sta_->reportClkSkew(clks, sta_->scenes(), MinMax::min(), false, 4); } }() )); } // --- Sta::findWorstClkSkew --- TEST_F(StaDesignTest, FindWorstClkSkew4) { ASSERT_NO_THROW(( [&](){ float skew = sta_->findWorstClkSkew(MinMax::max(), false); EXPECT_FALSE(std::isinf(skew)); float skew2 = sta_->findWorstClkSkew(MinMax::min(), false); EXPECT_FALSE(std::isinf(skew2)); }() )); } // --- Sta::reportClkLatency --- TEST_F(StaDesignTest, ReportClkLatency4) { ASSERT_NO_THROW(( [&](){ Clock *clk = sta_->cmdSdc()->findClock("clk"); if (clk) { ConstClockSeq clks; clks.push_back(clk); Scene *corner = sta_->cmdScene(); sta_->reportClkLatency(clks, sta_->scenes(), false, 4); sta_->reportClkLatency(clks, sta_->scenes(), true, 4); } }() )); } // --- Sta: propagated clock detection --- TEST_F(StaDesignTest, PropagatedClockDetection) { ASSERT_NO_THROW(( [&](){ Clock *clk = sta_->cmdSdc()->findClock("clk"); if (clk) { bool prop = clk->isPropagated(); EXPECT_FALSE(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_->cmdSdc()); sta_->removeDataCheck(from_pin, RiseFallBoth::riseFall(), to_pin, RiseFallBoth::riseFall(), nullptr, MinMaxAll::max(), sta_->cmdSdc()); } }() )); } // --- PathEnd methods: targetClk, targetClkArrival, targetClkDelay, // targetClkInsertionDelay, targetClkUncertainty, targetClkMcpAdjustment --- TEST_F(StaDesignTest, PathEndTargetClkMethods2) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->cmdScene(); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (PathEnd *pe : ends) { if (pe) { const Clock *tgt_clk = pe->targetClk(sta_); EXPECT_NE(tgt_clk, nullptr); Arrival tgt_arr = pe->targetClkArrival(sta_); EXPECT_FALSE(std::isinf(tgt_arr)); Delay tgt_delay = pe->targetClkDelay(sta_); EXPECT_FALSE(std::isinf(tgt_delay)); Arrival tgt_ins = pe->targetClkInsertionDelay(sta_); EXPECT_FALSE(std::isinf(tgt_ins)); float tgt_unc = pe->targetClkUncertainty(sta_); EXPECT_FALSE(std::isinf(tgt_unc)); float tgt_mcp = pe->targetClkMcpAdjustment(sta_); EXPECT_FALSE(std::isinf(tgt_mcp)); float non_inter = pe->targetNonInterClkUncertainty(sta_); EXPECT_FALSE(std::isinf(non_inter)); float inter = pe->interClkUncertainty(sta_); EXPECT_FALSE(std::isinf(inter)); } } }() )); } // --- PathExpanded::pathsIndex --- TEST_F(StaDesignTest, PathExpandedPathsIndex) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->cmdScene(); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, group_names, 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); EXPECT_NE(p0, nullptr); if (sz > 1) { const Path *p1 = expanded.path(sz - 1); EXPECT_NE(p1, nullptr); } } } } break; } }() )); } // --- Report path end with format full_clock --- TEST_F(StaDesignTest, ReportPathEndFullClock) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->cmdScene(); sta_->setReportPathFormat(ReportPathFormat::full_clock); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } // --- Report path end with format full_clock_expanded --- TEST_F(StaDesignTest, ReportPathEndFullClockExpanded) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->cmdScene(); sta_->setReportPathFormat(ReportPathFormat::full_clock_expanded); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } // --- Report path end with format end --- TEST_F(StaDesignTest, ReportPathEndEnd) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->cmdScene(); sta_->setReportPathFormat(ReportPathFormat::endpoint); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } // --- Report path end with format summary --- TEST_F(StaDesignTest, ReportPathEndSummary2) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->cmdScene(); sta_->setReportPathFormat(ReportPathFormat::summary); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } // --- Report path end with format slack_only --- TEST_F(StaDesignTest, ReportPathEndSlackOnly2) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->cmdScene(); sta_->setReportPathFormat(ReportPathFormat::slack_only); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, group_names, true, false, false, false, false, false); if (!ends.empty()) { sta_->reportPathEnd(ends[0]); } }() )); } // --- Report multiple path ends --- TEST_F(StaDesignTest, ReportPathEnds3) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->cmdScene(); sta_->setReportPathFormat(ReportPathFormat::full); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, group_names, 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()); EXPECT_FALSE(std::isinf(ws_max)); Slack ws_min = sta_->worstSlack(MinMax::min()); EXPECT_FALSE(std::isinf(ws_min)); }() )); } // --- Sta: worstSlack with corner --- TEST_F(StaDesignTest, WorstSlackCorner2) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->cmdScene(); Slack ws; Vertex *v; sta_->worstSlack(corner, MinMax::max(), ws, v); EXPECT_FALSE(std::isinf(ws)); EXPECT_NE(v, nullptr); }() )); } // --- Sta: totalNegativeSlack --- TEST_F(StaDesignTest, TotalNegativeSlack2) { ASSERT_NO_THROW(( [&](){ Slack tns = sta_->totalNegativeSlack(MinMax::max()); EXPECT_FALSE(std::isinf(tns)); Slack tns2 = sta_->totalNegativeSlack(MinMax::min()); EXPECT_FALSE(std::isinf(tns2)); }() )); } // --- Sta: totalNegativeSlack with corner --- TEST_F(StaDesignTest, TotalNegativeSlackCorner2) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->cmdScene(); Slack tns = sta_->totalNegativeSlack(corner, MinMax::max()); EXPECT_FALSE(std::isinf(tns)); }() )); } // --- WriteSdc with many constraints from search side --- TEST_F(StaDesignTest, WriteSdcComprehensive) { Network *network = sta_->cmdNetwork(); Instance *top = network->topInstance(); Scene *corner = sta_->cmdScene(); Clock *clk = sta_->cmdSdc()->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, MinMaxAll::all(), 0.04f, sta_->cmdSdc()); sta_->setResistance(net, MinMaxAll::all(), 75.0f, sta_->cmdSdc()); } delete net_iter; // Input slew if (in1) { Port *port = network->port(in1); if (port) sta_->setInputSlew(port, RiseFallBoth::riseFall(), MinMaxAll::all(), 0.1f, sta_->cmdSdc()); } // Port loads if (out) { Port *port = network->port(out); if (port) { sta_->setPortExtPinCap(port, RiseFallBoth::riseFall(), MinMaxAll::all(), 0.15f, sta_->cmdSdc()); sta_->setPortExtWireCap(port, RiseFallBoth::riseFall(), MinMaxAll::all(), 0.02f, sta_->cmdSdc()); } } // 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(), sta_->cmdSdc()); 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(), sta_->cmdSdc()); thrus->push_back(thru); } delete nit; sta_->makeFalsePath(from, thrus, nullptr, MinMaxAll::all(), "", sta_->cmdSdc()); } // 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(), sta_->cmdSdc()); PinSet *to_pins = new PinSet(network); to_pins->insert(out); ExceptionTo *to = sta_->makeExceptionTo(to_pins, nullptr, nullptr, RiseFallBoth::riseFall(), RiseFallBoth::riseFall(), sta_->cmdSdc()); sta_->makePathDelay(from, nullptr, to, MinMax::max(), false, false, 7.0f, "", sta_->cmdSdc()); } // Clock groups with actual clocks if (clk) { ClockGroups *cg = sta_->makeClockGroups("search_grp", true, false, false, false, "", sta_->cmdSdc()); ClockSet *g1 = new ClockSet; g1->insert(clk); sta_->makeClockGroup(cg, g1, sta_->cmdSdc()); } // Multicycle sta_->makeMulticyclePath(nullptr, nullptr, nullptr, MinMaxAll::max(), true, 2, "", sta_->cmdSdc()); // Group path sta_->makeGroupPath("search_group", false, nullptr, nullptr, nullptr, "", sta_->cmdSdc()); // Voltage sta_->setVoltage(MinMax::max(), 1.1f, sta_->cmdSdc()); sta_->setVoltage(MinMax::min(), 0.9f, sta_->cmdSdc()); std::string filename = makeUniqueSdcPath("test_search_r11_comprehensive.sdc"); sta_->writeSdc(sta_->cmdSdc(), 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(sta_->cmdSdc(), fn2.c_str(), false, true, 4, false, true); expectSdcFileReadable(fn2); std::string fn3 = makeUniqueSdcPath("test_search_r11_comprehensive_leaf.sdc"); sta_->writeSdc(sta_->cmdSdc(), fn3.c_str(), true, false, 4, false, true); expectSdcFileReadable(fn3); } // --- Sta: report path with verbose format --- TEST_F(StaDesignTest, ReportPathVerbose) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->cmdScene(); sta_->setReportPathFormat(ReportPathFormat::full); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 3, 3, true, false, -INF, INF, false, group_names, 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(( [&](){ Scene *corner = sta_->cmdScene(); sta_->setReportPathFormat(ReportPathFormat::full); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::min(), 3, 3, true, false, -INF, INF, false, group_names, 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) { // maxSkewViolations/reportCheck removed; test reportMaxSkewChecks sta_->reportMaxSkewChecks(nullptr, 10, false, false, sta_->scenes()); } // --- Sta: min period checks with report --- TEST_F(StaDesignTest, MinPeriodChecksReport) { // minPeriodViolations/reportCheck removed; test reportMinPeriodChecks sta_->reportMinPeriodChecks(nullptr, 10, false, false, sta_->scenes()); } // --- Sta: MPW slack check --- TEST_F(StaDesignTest, MpwSlackCheck) { // minPulseWidthSlack removed; test reportMinPulseWidthChecks sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes()); } // --- Sta: MPW checks on all --- TEST_F(StaDesignTest, MpwChecksAll2) { // minPulseWidthChecks removed; test reportMinPulseWidthChecks sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes()); } // --- Sta: MPW violations --- TEST_F(StaDesignTest, MpwViolations2) { // minPulseWidthViolations removed; test reportMinPulseWidthChecks sta_->reportMinPulseWidthChecks(nullptr, 10, true, false, sta_->scenes()); } // --- Sta: check timing --- TEST_F(StaDesignTest, CheckTiming3) { ASSERT_NO_THROW(( [&](){ CheckErrorSeq &errors = sta_->checkTiming(sta_->cmdMode(), true, true, true, true, true, true, true); EXPECT_GE(errors.size(), 0u); }() )); } // --- 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_->cmdSdc()->findClock("clk"); if (out && clk) { sta_->setOutputDelay(out, RiseFallBoth::riseFall(), clk, RiseFall::rise(), nullptr, false, false, MinMaxAll::all(), true, 2.0f, sta_->cmdSdc()); sta_->updateTiming(true); Scene *corner = sta_->cmdScene(); sta_->setReportPathFormat(ReportPathFormat::full); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (PathEnd *pe : ends) { if (pe) { sta_->reportPathEnd(pe); pe->isOutputDelay(); } } } }() )); } // --- PathEnd: type and typeName --- TEST_F(StaDesignTest, PathEndTypeInfo) { Scene *corner = sta_->cmdScene(); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, group_names, true, false, false, false, false, false); for (PathEnd *pe : ends) { if (pe) { PathEnd::Type type = pe->type(); EXPECT_GE(static_cast(type), 0); const char *name = pe->typeName(); EXPECT_NE(name, nullptr); } } } // --- Sta: find path ends unconstrained --- TEST_F(StaDesignTest, FindPathEndsUnconstrained3) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->cmdScene(); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 5, 5, true, false, -INF, INF, true, group_names, true, false, false, false, false, false); for (PathEnd *pe : ends) { if (pe) { bool unc = pe->isUnconstrained(); // unc can be true or false if (unc) { Required req = pe->requiredTime(sta_); EXPECT_FALSE(std::isinf(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, "", sta_->cmdSdc()); Scene *corner = sta_->cmdScene(); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, group_names, true, false, false, false, false, false); EXPECT_GE(ends.size(), 0u); }() )); } // --- Sta: pathGroupNames --- TEST_F(StaDesignTest, PathGroupNames) { sta_->makeGroupPath("test_group_r11", false, nullptr, nullptr, nullptr, "", sta_->cmdSdc()); StringSeq names = sta_->pathGroupNames(sta_->cmdSdc()); 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, "", sta_->cmdSdc()); bool is_group = sta_->isPathGroupName("test_pg_r11", sta_->cmdSdc()); EXPECT_TRUE(is_group); bool not_group = sta_->isPathGroupName("nonexistent_group", sta_->cmdSdc()); 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(), sta_->cmdSdc()); PinSet *to_pins = new PinSet(network); to_pins->insert(out); ExceptionTo *to = sta_->makeExceptionTo(to_pins, nullptr, nullptr, RiseFallBoth::riseFall(), RiseFallBoth::riseFall(), sta_->cmdSdc()); sta_->makePathDelay(from, nullptr, to, MinMax::max(), false, false, 8.0f, "", sta_->cmdSdc()); sta_->updateTiming(true); Scene *corner = sta_->cmdScene(); sta_->setReportPathFormat(ReportPathFormat::full); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 5, 5, true, false, -INF, INF, false, group_names, 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) { Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max()); if (path) { Tag *tag = path->tag(sta_); if (tag) { const ClkInfo *ci = tag->clkInfo(); if (ci) { const ClockEdge *edge = ci->clkEdge(); EXPECT_NE(edge, nullptr); bool prop = ci->isPropagated(); EXPECT_FALSE(prop); bool gen = ci->isGenClkSrcPath(); EXPECT_FALSE(gen); } int ap_idx = tag->scene()->index(); EXPECT_GE(ap_idx, 0); } } } }() )); } // --- 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_->cmdSdc()->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, sta_->cmdSdc()); } std::string filename = makeUniqueSdcPath("test_search_r11_clksense.sdc"); sta_->writeSdc(sta_->cmdSdc(), 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(), sta_->cmdSdc()); } } } } } std::string filename = makeUniqueSdcPath("test_search_r11_drivecell.sdc"); sta_->writeSdc(sta_->cmdSdc(), filename.c_str(), false, false, 4, false, true); expectSdcFileReadable(filename); } // --- Sta: report path end with reportPath --- TEST_F(StaDesignTest, ReportPath2) { ASSERT_NO_THROW(( [&](){ Scene *corner = sta_->cmdScene(); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 1, 1, true, false, -INF, INF, false, group_names, 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_->cmdSdc()->findClock("clk"); if (clk) { sta_->setPropagatedClock(clk, sta_->cmdMode()); sta_->updateTiming(true); Scene *corner = sta_->cmdScene(); sta_->setReportPathFormat(ReportPathFormat::full); PathEndSeq ends = sta_->findPathEnds( nullptr, nullptr, nullptr, false, sta_->makeSceneSeq(corner), MinMaxAll::max(), 3, 3, true, false, -INF, INF, false, group_names, 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(sta_->cmdSdc(), 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(); // endpoints() returns reference, always valid EXPECT_GE(eps.size(), 0u); } // --- Sta: worst slack vertex --- TEST_F(StaDesignTest, WorstSlackVertex) { ASSERT_NO_THROW(( [&](){ Slack ws; Vertex *v; sta_->worstSlack(MinMax::max(), ws, v); EXPECT_FALSE(std::isinf(ws)); EXPECT_NE(v, nullptr); }() )); } } // namespace sta