OpenSTA/search/test/cpp/TestSearchStaDesignB.cc

4436 lines
124 KiB
C++
Raw Normal View History

#include <gtest/gtest.h>
#include <type_traits>
#include <atomic>
#include <cmath>
#include <string>
#include <tcl.h>
#include <unistd.h>
#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 <typename FnPtr>
static void expectCallablePointerUsable(FnPtr fn) {
ASSERT_NE(fn, nullptr);
EXPECT_TRUE((std::is_pointer_v<FnPtr> || std::is_member_function_pointer_v<FnPtr>));
EXPECT_TRUE(std::is_copy_constructible_v<FnPtr>);
EXPECT_TRUE(std::is_copy_assignable_v<FnPtr>);
FnPtr fn_copy = fn;
EXPECT_EQ(fn_copy, fn);
}
static std::string makeUniqueSdcPath(const char *tag)
{
static std::atomic<int> counter{0};
char buf[256];
snprintf(buf, sizeof(buf), "%s_%d_%d.sdc",
tag, static_cast<int>(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<ReportTcl*>(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());
(void)path_idx;
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();
(void)corner;
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());
(void)path_idx;
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<int>(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();
(void)corner;
// 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();
(void)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();
(void)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());
(void)path_idx;
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<Cell*>::getProperty, PropertyRegistry<Library*>::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];
(void)corner;
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<int>(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];
(void)corner;
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];
(void)corner;
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();
(void)corner;
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();
(void)corner;
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();
(void)corner;
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();
(void)corner;
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();
(void)corner;
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<int>(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