4185 lines
106 KiB
C++
4185 lines
106 KiB
C++
#include <gtest/gtest.h>
|
|
#include <type_traits>
|
|
#include <atomic>
|
|
#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 "Sta.hh"
|
|
#include "Sdc.hh"
|
|
#include "ReportTcl.hh"
|
|
#include "RiseFallMinMax.hh"
|
|
#include "Variables.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 "Mode.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 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;
|
|
};
|
|
|
|
// ============================================================
|
|
// R8_ tests: Sta.cc methods with loaded design
|
|
// ============================================================
|
|
|
|
// --- vertexArrival overloads ---
|
|
|
|
TEST_F(StaDesignTest, VertexArrivalMinMax) {
|
|
Vertex *v = findVertex("r1/Q");
|
|
ASSERT_NE(v, nullptr);
|
|
sta_->arrival(v, RiseFallBoth::riseFall(), sta_->scenes(), MinMax::max());
|
|
}
|
|
|
|
TEST_F(StaDesignTest, VertexArrivalRfPathAP) {
|
|
Vertex *v = findVertex("r1/Q");
|
|
ASSERT_NE(v, nullptr);
|
|
Scene *corner = sta_->cmdScene();
|
|
const size_t path_idx = corner->pathIndex(MinMax::max());
|
|
(void)path_idx;
|
|
sta_->arrival(v, RiseFallBoth::rise(), sta_->scenes(), MinMax::max());
|
|
}
|
|
|
|
// --- vertexRequired overloads ---
|
|
|
|
TEST_F(StaDesignTest, VertexRequiredMinMax) {
|
|
Vertex *v = findVertex("r3/D");
|
|
ASSERT_NE(v, nullptr);
|
|
sta_->required(v, RiseFallBoth::riseFall(), sta_->scenes(), MinMax::max());
|
|
}
|
|
|
|
TEST_F(StaDesignTest, VertexRequiredRfMinMax) {
|
|
Vertex *v = findVertex("r3/D");
|
|
ASSERT_NE(v, nullptr);
|
|
sta_->required(v, RiseFallBoth::rise(), sta_->scenes(), MinMax::max());
|
|
}
|
|
|
|
TEST_F(StaDesignTest, VertexRequiredRfPathAP) {
|
|
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;
|
|
sta_->required(v, RiseFallBoth::rise(), sta_->scenes(), MinMax::max());
|
|
}
|
|
|
|
// --- vertexSlack overloads ---
|
|
|
|
TEST_F(StaDesignTest, VertexSlackMinMax) {
|
|
Vertex *v = findVertex("r3/D");
|
|
ASSERT_NE(v, nullptr);
|
|
sta_->slack(v, MinMax::max());
|
|
}
|
|
|
|
TEST_F(StaDesignTest, VertexSlackRfPathAP) {
|
|
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;
|
|
sta_->slack(v, RiseFallBoth::rise(), sta_->scenes(), MinMax::max());
|
|
}
|
|
|
|
// --- vertexSlacks ---
|
|
|
|
TEST_F(StaDesignTest, VertexSlacks) {
|
|
Vertex *v = findVertex("r3/D");
|
|
ASSERT_NE(v, nullptr);
|
|
sta_->slack(v, MinMax::max());
|
|
// Just verify it doesn't crash; values depend on timing
|
|
}
|
|
|
|
// --- vertexSlew overloads ---
|
|
|
|
TEST_F(StaDesignTest, VertexSlewRfCornerMinMax) {
|
|
Vertex *v = findVertex("u1/Z");
|
|
ASSERT_NE(v, nullptr);
|
|
Scene *corner = sta_->cmdScene();
|
|
(void)corner;
|
|
sta_->slew(v, RiseFallBoth::rise(), sta_->scenes(), MinMax::max());
|
|
}
|
|
|
|
TEST_F(StaDesignTest, VertexSlewRfDcalcAP) {
|
|
Vertex *v = findVertex("u1/Z");
|
|
ASSERT_NE(v, nullptr);
|
|
Scene *corner = sta_->cmdScene();
|
|
const DcalcAPIndex dcalc_idx = corner->dcalcAnalysisPtIndex(MinMax::max());
|
|
(void)dcalc_idx;
|
|
sta_->slew(v, RiseFallBoth::rise(), sta_->scenes(), MinMax::max());
|
|
}
|
|
|
|
// --- vertexWorstRequiredPath ---
|
|
|
|
TEST_F(StaDesignTest, VertexWorstRequiredPath) {
|
|
Vertex *v = findVertex("r3/D");
|
|
ASSERT_NE(v, nullptr);
|
|
sta_->vertexWorstRequiredPath(v, MinMax::max());
|
|
// May be nullptr if no required; just check it doesn't crash
|
|
}
|
|
|
|
TEST_F(StaDesignTest, VertexWorstRequiredPathRf) {
|
|
Vertex *v = findVertex("r3/D");
|
|
ASSERT_NE(v, nullptr);
|
|
Path *path = sta_->vertexWorstRequiredPath(v, RiseFall::rise(), MinMax::max());
|
|
EXPECT_NE(path, nullptr);
|
|
}
|
|
|
|
// --- vertexPathIterator ---
|
|
|
|
TEST_F(StaDesignTest, VertexPathIteratorRfPathAP) {
|
|
Vertex *v = findVertex("r1/Q");
|
|
ASSERT_NE(v, nullptr);
|
|
// vertexPathIterator removed; using vertexWorstArrivalPath instead
|
|
Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max());
|
|
(void)path;
|
|
}
|
|
|
|
// --- checkSlewLimits ---
|
|
|
|
TEST_F(StaDesignTest, CheckSlewLimitPreambleAndLimits) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->checkSlewsPreamble();
|
|
sta_->reportSlewChecks(nullptr, 10, false, false, sta_->scenes(), MinMax::max());
|
|
// May be empty; just check no crash
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, CheckSlewViolators) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->checkSlewsPreamble();
|
|
sta_->reportSlewChecks(nullptr, 10, false, false, sta_->scenes(), MinMax::max());
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- checkSlew (single pin) ---
|
|
|
|
TEST_F(StaDesignTest, CheckSlew) {
|
|
sta_->checkSlewsPreamble();
|
|
Pin *pin = findPin("u1/Z");
|
|
ASSERT_NE(pin, nullptr);
|
|
const Scene *corner1 = nullptr;
|
|
const RiseFall *tr = nullptr;
|
|
Slew slew;
|
|
float limit, slack;
|
|
sta_->checkSlew(pin, sta_->scenes(), MinMax::max(), false,
|
|
slew, limit, slack, tr, corner1);
|
|
}
|
|
|
|
// --- findSlewLimit ---
|
|
|
|
TEST_F(StaDesignTest, FindSlewLimit) {
|
|
sta_->checkSlewsPreamble();
|
|
LibertyCell *buf = lib_->findLibertyCell("BUF_X1");
|
|
ASSERT_NE(buf, nullptr);
|
|
LibertyPort *port_z = buf->findLibertyPort("Z");
|
|
ASSERT_NE(port_z, nullptr);
|
|
float limit = 0.0f;
|
|
bool exists = false;
|
|
sta_->findSlewLimit(port_z, sta_->cmdScene(), MinMax::max(),
|
|
limit, exists);
|
|
}
|
|
|
|
// --- checkFanoutLimits ---
|
|
|
|
TEST_F(StaDesignTest, CheckFanoutLimits) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->checkFanoutPreamble();
|
|
sta_->reportFanoutChecks(nullptr, 10, false, false, sta_->scenes(), MinMax::max());
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, CheckFanoutViolators) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->checkFanoutPreamble();
|
|
sta_->reportFanoutChecks(nullptr, 10, false, false, sta_->scenes(), MinMax::max());
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- checkFanout (single pin) ---
|
|
|
|
TEST_F(StaDesignTest, CheckFanout) {
|
|
sta_->checkFanoutPreamble();
|
|
Pin *pin = findPin("u1/Z");
|
|
ASSERT_NE(pin, nullptr);
|
|
float fanout, limit, slack;
|
|
sta_->checkFanout(pin, sta_->cmdMode(), MinMax::max(), fanout, limit, slack);
|
|
}
|
|
|
|
// --- checkCapacitanceLimits ---
|
|
|
|
TEST_F(StaDesignTest, CheckCapacitanceLimits) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->checkCapacitancesPreamble(sta_->scenes());
|
|
|
|
sta_->reportCapacitanceChecks(nullptr, 10, false, false, sta_->scenes(), MinMax::max());
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, CheckCapacitanceViolators) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->checkCapacitancesPreamble(sta_->scenes());
|
|
|
|
sta_->reportCapacitanceChecks(nullptr, 10, false, false, sta_->scenes(), MinMax::max());
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- checkCapacitance (single pin) ---
|
|
|
|
TEST_F(StaDesignTest, CheckCapacitance) {
|
|
sta_->checkCapacitancesPreamble(sta_->scenes());
|
|
Pin *pin = findPin("u1/Z");
|
|
ASSERT_NE(pin, nullptr);
|
|
const Scene *corner1 = nullptr;
|
|
const RiseFall *tr = nullptr;
|
|
float cap, limit, slack;
|
|
sta_->checkCapacitance(pin, sta_->scenes(), MinMax::max(),
|
|
cap, limit, slack, tr, corner1);
|
|
}
|
|
|
|
// --- minPulseWidthSlack ---
|
|
|
|
TEST_F(StaDesignTest, MinPulseWidthSlack) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes());
|
|
|
|
// May be nullptr; just don't crash
|
|
}() ));
|
|
}
|
|
|
|
// --- minPulseWidthViolations ---
|
|
|
|
TEST_F(StaDesignTest, MinPulseWidthViolations) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->reportMinPulseWidthChecks(nullptr, 10, true, false, sta_->scenes());
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- minPulseWidthChecks (all) ---
|
|
|
|
TEST_F(StaDesignTest, MinPulseWidthChecksAll) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes());
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- minPeriodSlack ---
|
|
|
|
TEST_F(StaDesignTest, MinPeriodSlack) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->reportMinPeriodChecks(nullptr, 10, false, false, sta_->scenes());
|
|
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- minPeriodViolations ---
|
|
|
|
TEST_F(StaDesignTest, MinPeriodViolations) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->reportMinPeriodChecks(nullptr, 10, true, false, sta_->scenes());
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- maxSkewSlack ---
|
|
|
|
TEST_F(StaDesignTest, MaxSkewSlack) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->reportMaxSkewChecks(nullptr, 10, false, false, sta_->scenes());
|
|
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- maxSkewViolations ---
|
|
|
|
TEST_F(StaDesignTest, MaxSkewViolations) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->reportMaxSkewChecks(nullptr, 10, true, false, sta_->scenes());
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- reportCheck (MaxSkewCheck) ---
|
|
|
|
TEST_F(StaDesignTest, ReportCheckMaxSkew) {
|
|
// maxSkewSlack/reportCheck removed; testing reportMaxSkewChecks instead
|
|
sta_->reportMaxSkewChecks(nullptr, 10, false, false, sta_->scenes());
|
|
}
|
|
|
|
// --- reportCheck (MinPeriodCheck) ---
|
|
|
|
TEST_F(StaDesignTest, ReportCheckMinPeriod) {
|
|
// minPeriodSlack/reportCheck removed; testing reportMinPeriodChecks instead
|
|
sta_->reportMinPeriodChecks(nullptr, 10, false, false, sta_->scenes());
|
|
}
|
|
|
|
// --- reportMpwCheck ---
|
|
|
|
TEST_F(StaDesignTest, ReportMpwCheck) {
|
|
// minPulseWidthSlack/reportMpwCheck removed; testing reportMinPulseWidthChecks instead
|
|
sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes());
|
|
}
|
|
|
|
// --- findPathEnds ---
|
|
|
|
TEST_F(StaDesignTest, FindPathEnds) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, // group_path_count
|
|
1, // endpoint_path_count
|
|
false, // unique_pins
|
|
false, // unique_edges
|
|
-INF, // slack_min
|
|
INF, // slack_max
|
|
false, // sort_by_slack
|
|
group_names, // group_names (empty = all)
|
|
true, // setup
|
|
false, // hold
|
|
false, // recovery
|
|
false, // removal
|
|
false, // clk_gating_setup
|
|
false); // clk_gating_hold
|
|
// Should find some path ends in this design
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- reportPathEndHeader / Footer ---
|
|
|
|
TEST_F(StaDesignTest, ReportPathEndHeaderFooter) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathFormat(ReportPathFormat::full);
|
|
|
|
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- reportPathEnd ---
|
|
|
|
TEST_F(StaDesignTest, ReportPathEnd) {
|
|
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()) {
|
|
sta_->reportPathEnd(ends[0]);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- reportPathEnds ---
|
|
|
|
TEST_F(StaDesignTest, ReportPathEnds) {
|
|
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);
|
|
sta_->reportPathEnds(&ends);
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- reportClkSkew ---
|
|
|
|
TEST_F(StaDesignTest, ReportClkSkew) {
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
ConstClockSeq clks;
|
|
clks.push_back(clk);
|
|
sta_->reportClkSkew(clks, sta_->scenes(), SetupHold::max(), false, 4);
|
|
}
|
|
|
|
// --- isClock(Net*) ---
|
|
|
|
TEST_F(StaDesignTest, IsClockNet) {
|
|
sta_->ensureClkNetwork(sta_->cmdMode());
|
|
Network *network = sta_->cmdNetwork();
|
|
Pin *clk1_pin = findPin("clk1");
|
|
ASSERT_NE(clk1_pin, nullptr);
|
|
Net *clk_net = network->net(clk1_pin);
|
|
if (clk_net) {
|
|
bool is_clk = sta_->isClock(clk_net, sta_->cmdMode());
|
|
EXPECT_TRUE(is_clk);
|
|
}
|
|
}
|
|
|
|
// --- pins(Clock*) ---
|
|
|
|
TEST_F(StaDesignTest, ClockPins) {
|
|
sta_->ensureClkNetwork(sta_->cmdMode());
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
const PinSet *pins = sta_->pins(clk, sta_->cmdMode());
|
|
EXPECT_NE(pins, nullptr);
|
|
if (pins) {
|
|
EXPECT_GT(pins->size(), 0u);
|
|
}
|
|
}
|
|
|
|
// --- pvt / setPvt ---
|
|
|
|
TEST_F(StaDesignTest, PvtGetSet) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
const Pvt *p = sta_->pvt(top, MinMax::max(), sta_->cmdSdc());
|
|
|
|
// p may be nullptr if not set; just don't crash
|
|
sta_->setPvt(top, MinMaxAll::all(), 1.0f, 1.1f, 25.0f, sta_->cmdSdc());
|
|
|
|
p = sta_->pvt(top, MinMax::max(), sta_->cmdSdc());
|
|
(void)p;
|
|
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- findDelays(int) ---
|
|
|
|
TEST_F(StaDesignTest, FindDelaysLevel) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->findDelays(0);
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- findDelays (no arg - public) ---
|
|
|
|
TEST_F(StaDesignTest, FindDelays) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->findDelays();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- arrivalsInvalid / delaysInvalid ---
|
|
|
|
TEST_F(StaDesignTest, ArrivalsInvalid) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->arrivalsInvalid();
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, DelaysInvalid) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->delaysInvalid();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- makeEquivCells ---
|
|
|
|
TEST_F(StaDesignTest, MakeEquivCells) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
LibertyLibrarySeq *equiv_libs = new LibertyLibrarySeq;
|
|
equiv_libs->push_back(lib_);
|
|
LibertyLibrarySeq *map_libs = new LibertyLibrarySeq;
|
|
map_libs->push_back(lib_);
|
|
sta_->makeEquivCells(equiv_libs, map_libs);
|
|
// Check equivCells for BUF_X1
|
|
LibertyCell *buf = lib_->findLibertyCell("BUF_X1");
|
|
if (buf) {
|
|
LibertyCellSeq *equiv = sta_->equivCells(buf);
|
|
EXPECT_NE(equiv, nullptr);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- maxPathCountVertex ---
|
|
|
|
TEST_F(StaDesignTest, MaxPathCountVertex) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->maxPathCountVertex();
|
|
// May be nullptr; just don't crash
|
|
}() ));
|
|
}
|
|
|
|
// --- makeParasiticAnalysisPts ---
|
|
|
|
TEST_F(StaDesignTest, MakeParasiticAnalysisPts) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
// setParasiticAnalysisPts removed
|
|
// Ensures parasitic analysis points are set up
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- findLogicConstants (Sim) ---
|
|
|
|
TEST_F(StaDesignTest, FindLogicConstants) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->findLogicConstants();
|
|
sta_->clearLogicConstants();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- checkTiming ---
|
|
|
|
TEST_F(StaDesignTest, CheckTiming) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->checkTiming(
|
|
sta_->cmdMode(),
|
|
true, // no_input_delay
|
|
true, // no_output_delay
|
|
true, // reg_multiple_clks
|
|
true, // reg_no_clks
|
|
true, // unconstrained_endpoints
|
|
true, // loops
|
|
true); // generated_clks
|
|
}() ));
|
|
}
|
|
|
|
// --- Property methods ---
|
|
|
|
TEST_F(StaDesignTest, PropertyGetPinArrival) {
|
|
Properties &props = sta_->properties();
|
|
Pin *pin = findPin("u1/Z");
|
|
ASSERT_NE(pin, nullptr);
|
|
props.getProperty(pin, "arrival_max_rise");
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PropertyGetPinSlack) {
|
|
Properties &props = sta_->properties();
|
|
Pin *pin = findPin("r3/D");
|
|
ASSERT_NE(pin, nullptr);
|
|
props.getProperty(pin, "slack_max");
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PropertyGetPinSlew) {
|
|
Properties &props = sta_->properties();
|
|
Pin *pin = findPin("u1/Z");
|
|
ASSERT_NE(pin, nullptr);
|
|
props.getProperty(pin, "slew_max");
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PropertyGetPinArrivalFall) {
|
|
Properties &props = sta_->properties();
|
|
Pin *pin = findPin("u1/Z");
|
|
ASSERT_NE(pin, nullptr);
|
|
props.getProperty(pin, "arrival_max_fall");
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PropertyGetInstanceName) {
|
|
Properties &props = sta_->properties();
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Instance *u1 = network->findChild(top, "u1");
|
|
ASSERT_NE(u1, nullptr);
|
|
props.getProperty(u1, "full_name");
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PropertyGetNetName) {
|
|
Properties &props = sta_->properties();
|
|
Network *network = sta_->cmdNetwork();
|
|
Pin *pin = findPin("u1/Z");
|
|
ASSERT_NE(pin, nullptr);
|
|
Net *net = network->net(pin);
|
|
if (net) {
|
|
props.getProperty(net, "name");
|
|
}
|
|
}
|
|
|
|
// --- Search methods ---
|
|
|
|
TEST_F(StaDesignTest, SearchCopyState) {
|
|
Search *search = sta_->search();
|
|
ASSERT_NE(search, nullptr);
|
|
search->copyState(sta_);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchFindPathGroupByName) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
(void)search;
|
|
// First ensure path groups exist
|
|
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);
|
|
// Search::findPathGroup removed
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchFindPathGroupByClock) {
|
|
Search *search = sta_->search();
|
|
(void)search;
|
|
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);
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
// Search::findPathGroup removed
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchReportTagGroups) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
search->reportTagGroups();
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchDeletePathGroups) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
// Ensure path groups exist first
|
|
sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
search->deletePathGroups();
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchVisitEndpoints) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
(void)search;
|
|
Network *network = sta_->cmdNetwork();
|
|
PinSet pins(network);
|
|
VertexPinCollector collector(pins);
|
|
(void)true /* Search::visitEndpoints removed */;
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Search: visitStartpoints ---
|
|
|
|
TEST_F(StaDesignTest, SearchVisitStartpoints) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
(void)search;
|
|
Network *network = sta_->cmdNetwork();
|
|
PinSet pins(network);
|
|
VertexPinCollector collector(pins);
|
|
(void)true /* Search::visitStartpoints removed */;
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchTagGroup) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
// Tag group index 0 may or may not exist; just don't crash
|
|
if (search->tagGroupCount() > 0) {
|
|
TagGroup *tg = search->tagGroup(0);
|
|
EXPECT_NE(tg, nullptr);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchClockDomainsVertex) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
Vertex *v = findVertex("r1/CK");
|
|
if (v) {
|
|
search->clockDomains(v, sta_->cmdMode());
|
|
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchIsGenClkSrc) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
(void)search;
|
|
Vertex *v = findVertex("r1/Q");
|
|
if (v) {
|
|
(void)true /* Search::isGenClkSrc removed */;
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchPathGroups) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
// Get a path end to query its path groups
|
|
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()) {
|
|
Search *search = sta_->search();
|
|
(void)search;
|
|
(void)true /* Search::pathGroups removed */;
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchPathClkPathArrival) {
|
|
Search *search = sta_->search();
|
|
// Get a path from a vertex
|
|
Vertex *v = findVertex("r1/Q");
|
|
ASSERT_NE(v, nullptr);
|
|
Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max());
|
|
if (path && !path->isNull()) {
|
|
search->pathClkPathArrival(path);
|
|
}
|
|
}
|
|
|
|
// --- ReportPath methods ---
|
|
|
|
// --- ReportPath: reportFull exercised through reportPathEnd (full format) ---
|
|
|
|
TEST_F(StaDesignTest, ReportPathFullClockFormat) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathFormat(ReportPathFormat::full_clock);
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
if (!ends.empty()) {
|
|
sta_->reportPathEnd(ends[0]);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathFullClockExpandedFormat) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathFormat(ReportPathFormat::full_clock_expanded);
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
if (!ends.empty()) {
|
|
sta_->reportPathEnd(ends[0]);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathShorterFormat) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathFormat(ReportPathFormat::shorter);
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
if (!ends.empty()) {
|
|
sta_->reportPathEnd(ends[0]);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathJsonFormat) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathFormat(ReportPathFormat::json);
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
if (!ends.empty()) {
|
|
sta_->reportPathEnd(ends[0]);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathShortMpw) {
|
|
// minPulseWidthSlack and reportShort(MinPulseWidthCheck) removed
|
|
ReportPath *rpt = sta_->reportPath();
|
|
ASSERT_NE(rpt, nullptr);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathVerboseMpw) {
|
|
// minPulseWidthSlack and reportVerbose(MinPulseWidthCheck) removed
|
|
ReportPath *rpt = sta_->reportPath();
|
|
ASSERT_NE(rpt, nullptr);
|
|
}
|
|
|
|
// --- ReportPath: reportJson ---
|
|
|
|
TEST_F(StaDesignTest, ReportJsonHeaderFooter) {
|
|
ReportPath *rpt = sta_->reportPath();
|
|
ASSERT_NE(rpt, nullptr);
|
|
rpt->reportJsonHeader();
|
|
rpt->reportJsonFooter();
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportJsonPathEnd) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
if (!ends.empty()) {
|
|
ReportPath *rpt = sta_->reportPath();
|
|
rpt->reportJsonHeader();
|
|
rpt->reportJson(ends[0], ends.size() == 1);
|
|
rpt->reportJsonFooter();
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- disable / removeDisable ---
|
|
|
|
TEST_F(StaDesignTest, DisableEnableLibertyPort) {
|
|
LibertyCell *buf = lib_->findLibertyCell("BUF_X1");
|
|
ASSERT_NE(buf, nullptr);
|
|
LibertyPort *port_a = buf->findLibertyPort("A");
|
|
ASSERT_NE(port_a, nullptr);
|
|
sta_->disable(port_a, sta_->cmdSdc());
|
|
sta_->removeDisable(port_a, sta_->cmdSdc());
|
|
}
|
|
|
|
TEST_F(StaDesignTest, DisableEnableTimingArcSet) {
|
|
LibertyCell *buf = lib_->findLibertyCell("BUF_X1");
|
|
ASSERT_NE(buf, nullptr);
|
|
const TimingArcSetSeq &arc_sets = buf->timingArcSets();
|
|
ASSERT_GT(arc_sets.size(), 0u);
|
|
sta_->disable(arc_sets[0], sta_->cmdSdc());
|
|
sta_->removeDisable(arc_sets[0], sta_->cmdSdc());
|
|
}
|
|
|
|
TEST_F(StaDesignTest, DisableEnableEdge) {
|
|
Vertex *v = findVertex("u1/Z");
|
|
ASSERT_NE(v, nullptr);
|
|
// Get an edge from this vertex
|
|
VertexInEdgeIterator edge_iter(v, sta_->graph());
|
|
if (edge_iter.hasNext()) {
|
|
Edge *edge = edge_iter.next();
|
|
sta_->disable(edge, sta_->cmdSdc());
|
|
sta_->removeDisable(edge, sta_->cmdSdc());
|
|
}
|
|
}
|
|
|
|
// --- disableClockGatingCheck / removeDisableClockGatingCheck ---
|
|
|
|
TEST_F(StaDesignTest, DisableClockGatingCheckPin) {
|
|
Pin *pin = findPin("r1/CK");
|
|
ASSERT_NE(pin, nullptr);
|
|
sta_->disableClockGatingCheck(pin, sta_->cmdSdc());
|
|
sta_->removeDisableClockGatingCheck(pin, sta_->cmdSdc());
|
|
}
|
|
|
|
// --- setCmdNamespace1 (Sta internal) ---
|
|
|
|
TEST_F(StaDesignTest, SetCmdNamespace1) {
|
|
sta_->setCmdNamespace(CmdNamespace::sdc);
|
|
EXPECT_EQ(sta_->cmdNamespace(), CmdNamespace::sdc);
|
|
sta_->setCmdNamespace(CmdNamespace::sta);
|
|
EXPECT_EQ(sta_->cmdNamespace(), CmdNamespace::sta);
|
|
}
|
|
|
|
// --- delaysInvalidFromFanin ---
|
|
|
|
TEST_F(StaDesignTest, DelaysInvalidFromFaninPin) {
|
|
Pin *pin = findPin("u1/Z");
|
|
ASSERT_NE(pin, nullptr);
|
|
sta_->delaysInvalidFromFanin(pin);
|
|
}
|
|
|
|
// --- setArcDelayAnnotated ---
|
|
|
|
TEST_F(StaDesignTest, SetArcDelayAnnotated) {
|
|
Vertex *v = findVertex("u1/Z");
|
|
ASSERT_NE(v, nullptr);
|
|
VertexInEdgeIterator edge_iter(v, sta_->graph());
|
|
if (edge_iter.hasNext()) {
|
|
Edge *edge = edge_iter.next();
|
|
TimingArcSet *arc_set = edge->timingArcSet();
|
|
if (arc_set) {
|
|
const TimingArcSeq &arcs = arc_set->arcs();
|
|
if (!arcs.empty()) {
|
|
Scene *corner = sta_->cmdScene();
|
|
DcalcAPIndex dcalc_idx = corner->dcalcAnalysisPtIndex(MinMax::max());
|
|
(void)dcalc_idx;
|
|
sta_->setArcDelayAnnotated(edge, arcs[0], corner, MinMax::max(), true);
|
|
sta_->setArcDelayAnnotated(edge, arcs[0], corner, MinMax::max(), false);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- pathAnalysisPt / pathDcalcAnalysisPt ---
|
|
|
|
TEST_F(StaDesignTest, PathAnalysisPt) {
|
|
Vertex *v = findVertex("r1/Q");
|
|
ASSERT_NE(v, nullptr);
|
|
Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max());
|
|
if (path && !path->isNull()) {
|
|
size_t pa = path->tag(sta_)->scene()->index();
|
|
EXPECT_GE(pa, 0u);
|
|
DcalcAPIndex da = path->tag(sta_)->scene()->dcalcAnalysisPtIndex(path->minMax(sta_));
|
|
EXPECT_GE(da, 0);
|
|
}
|
|
}
|
|
|
|
// --- worstSlack / totalNegativeSlack ---
|
|
|
|
TEST_F(StaDesignTest, WorstSlack) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Slack worst;
|
|
Vertex *worst_vertex = nullptr;
|
|
sta_->worstSlack(MinMax::max(), worst, worst_vertex);
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, WorstSlackCorner) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Slack worst;
|
|
Vertex *worst_vertex = nullptr;
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->worstSlack(corner, MinMax::max(), worst, worst_vertex);
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, TotalNegativeSlack) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->totalNegativeSlack(MinMax::max());
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, TotalNegativeSlackCorner) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->totalNegativeSlack(corner, MinMax::max());
|
|
}() ));
|
|
}
|
|
|
|
// --- endpoints / endpointViolationCount ---
|
|
|
|
TEST_F(StaDesignTest, Endpoints) {
|
|
VertexSet &eps = sta_->endpoints();
|
|
(void)eps;
|
|
// endpoints() returns reference, always valid
|
|
}
|
|
|
|
TEST_F(StaDesignTest, EndpointViolationCount) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
int count = sta_->endpointViolationCount(MinMax::max());
|
|
EXPECT_GE(count, 0);
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- findRequireds ---
|
|
|
|
TEST_F(StaDesignTest, FindRequireds) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->findRequireds();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Search: tag(0) ---
|
|
|
|
TEST_F(StaDesignTest, SearchTag) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
if (search->tagCount() > 0) {
|
|
Tag *t = search->tag(0);
|
|
EXPECT_NE(t, nullptr);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Levelize: checkLevels ---
|
|
|
|
TEST_F(StaDesignTest, GraphLoops) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->graphLoops();
|
|
}() ));
|
|
}
|
|
|
|
// --- reportPath (Path*) ---
|
|
|
|
TEST_F(StaDesignTest, ReportPath) {
|
|
Vertex *v = findVertex("u2/ZN");
|
|
ASSERT_NE(v, nullptr);
|
|
Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max());
|
|
if (path && !path->isNull()) {
|
|
sta_->reportPath(path);
|
|
}
|
|
}
|
|
|
|
// --- ClkNetwork: clocks(Pin*) ---
|
|
|
|
TEST_F(StaDesignTest, ClkNetworkClocksPinDirect) {
|
|
sta_->ensureClkNetwork(sta_->cmdMode());
|
|
ClkNetwork *clk_net = sta_->cmdMode()->clkNetwork();
|
|
ASSERT_NE(clk_net, nullptr);
|
|
Pin *clk1_pin = findPin("clk1");
|
|
ASSERT_NE(clk1_pin, nullptr);
|
|
const ClockSet *clks = clk_net->clocks(clk1_pin);
|
|
EXPECT_NE(clks, nullptr);
|
|
}
|
|
|
|
// --- ClkNetwork: pins(Clock*) ---
|
|
|
|
TEST_F(StaDesignTest, ClkNetworkPins) {
|
|
sta_->ensureClkNetwork(sta_->cmdMode());
|
|
ClkNetwork *clk_net = sta_->cmdMode()->clkNetwork();
|
|
ASSERT_NE(clk_net, nullptr);
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
const PinSet *pins = clk_net->pins(clk);
|
|
EXPECT_NE(pins, nullptr);
|
|
}
|
|
|
|
// --- ClkNetwork: isClock(Net*) ---
|
|
|
|
TEST_F(StaDesignTest, ClkNetworkIsClockNet) {
|
|
sta_->ensureClkNetwork(sta_->cmdMode());
|
|
ClkNetwork *clk_net = sta_->cmdMode()->clkNetwork();
|
|
ASSERT_NE(clk_net, nullptr);
|
|
Pin *clk1_pin = findPin("clk1");
|
|
ASSERT_NE(clk1_pin, nullptr);
|
|
Network *network = sta_->cmdNetwork();
|
|
Net *net = network->net(clk1_pin);
|
|
if (net) {
|
|
clk_net->isClock(net);
|
|
}
|
|
}
|
|
|
|
// --- ClkInfo accessors ---
|
|
|
|
TEST_F(StaDesignTest, ClkInfoAccessors) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
if (search->tagCount() > 0) {
|
|
Tag *tag = search->tag(0);
|
|
if (tag) {
|
|
const ClkInfo *clk_info = tag->clkInfo();
|
|
if (clk_info) {
|
|
const ClockEdge *edge = clk_info->clkEdge();
|
|
EXPECT_NE(edge, nullptr);
|
|
clk_info->isPropagated();
|
|
clk_info->isGenClkSrcPath();
|
|
}
|
|
}
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Tag accessors ---
|
|
|
|
TEST_F(StaDesignTest, TagAccessors) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
if (search->tagCount() > 0) {
|
|
Tag *tag = search->tag(0);
|
|
if (tag) {
|
|
PathAPIndex idx = tag->scene()->index();
|
|
EXPECT_GE(idx, 0);
|
|
const Pin *src = tag->clkSrc();
|
|
EXPECT_NE(src, nullptr);
|
|
}
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- TagGroup::report ---
|
|
|
|
TEST_F(StaDesignTest, TagGroupReport) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
if (search->tagGroupCount() > 0) {
|
|
TagGroup *tg = search->tagGroup(0);
|
|
if (tg) {
|
|
tg->report(sta_);
|
|
}
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- BfsIterator ---
|
|
|
|
TEST_F(StaDesignTest, BfsIteratorInit) {
|
|
BfsFwdIterator *iter = sta_->search()->arrivalIterator();
|
|
ASSERT_NE(iter, nullptr);
|
|
// Just verify the iterator exists - init is called internally
|
|
}
|
|
|
|
// --- SearchPred1 ---
|
|
|
|
TEST_F(StaDesignTest, SearchPredNonReg2SearchThru) {
|
|
SearchPred1 pred(sta_);
|
|
Vertex *v = findVertex("u1/Z");
|
|
ASSERT_NE(v, nullptr);
|
|
VertexInEdgeIterator edge_iter(v, sta_->graph());
|
|
if (edge_iter.hasNext()) {
|
|
Edge *edge = edge_iter.next();
|
|
pred.searchThru(edge);
|
|
}
|
|
}
|
|
|
|
// --- PathExpanded ---
|
|
|
|
TEST_F(StaDesignTest, PathExpanded) {
|
|
Vertex *v = findVertex("r3/D");
|
|
ASSERT_NE(v, nullptr);
|
|
Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max());
|
|
if (path && !path->isNull()) {
|
|
PathExpanded expanded(path, false, sta_);
|
|
size_t size = expanded.size();
|
|
for (size_t i = 0; i < size; i++) {
|
|
const Path *p = expanded.path(i);
|
|
EXPECT_NE(p, nullptr);
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Search: endpoints ---
|
|
|
|
TEST_F(StaDesignTest, SearchEndpoints) {
|
|
Search *search = sta_->search();
|
|
VertexSet &eps = search->endpoints();
|
|
(void)eps;
|
|
// endpoints() returns reference, always valid
|
|
}
|
|
|
|
// --- FindRegister (findRegs) ---
|
|
|
|
TEST_F(StaDesignTest, FindRegPins) {
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockSet clk_set;
|
|
clk_set.insert(clk);
|
|
sta_->findRegisterClkPins(&clk_set,
|
|
RiseFallBoth::riseFall(), false, false, sta_->cmdMode());
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindRegDataPins) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->findRegisterDataPins(nullptr, RiseFallBoth::riseFall(), false, false, sta_->cmdMode());
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindRegOutputPins) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->findRegisterOutputPins(nullptr, RiseFallBoth::riseFall(), false, false, sta_->cmdMode());
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindRegAsyncPins) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->findRegisterAsyncPins(nullptr, RiseFallBoth::riseFall(), false, false, sta_->cmdMode());
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindRegInstances) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->findRegisterInstances(nullptr, RiseFallBoth::riseFall(), false, false, sta_->cmdMode());
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Sim::findLogicConstants ---
|
|
|
|
TEST_F(StaDesignTest, SimFindLogicConstants) {
|
|
// Sim access removed from Sta
|
|
sta_->findLogicConstants();
|
|
}
|
|
|
|
// --- reportSlewLimitShortHeader ---
|
|
|
|
TEST_F(StaDesignTest, ReportSlewLimitShortHeader) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
// reportSlewLimitShortHeader removed;
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- reportFanoutLimitShortHeader ---
|
|
|
|
TEST_F(StaDesignTest, ReportFanoutLimitShortHeader) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
// reportFanoutLimitShortHeader removed;
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- reportCapacitanceLimitShortHeader ---
|
|
|
|
TEST_F(StaDesignTest, ReportCapacitanceLimitShortHeader) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
// reportCapacitanceLimitShortHeader removed;
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Path methods ---
|
|
|
|
TEST_F(StaDesignTest, PathTransition) {
|
|
Vertex *v = findVertex("r1/Q");
|
|
ASSERT_NE(v, nullptr);
|
|
Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max());
|
|
if (path && !path->isNull()) {
|
|
const RiseFall *rf = path->transition(sta_);
|
|
EXPECT_NE(rf, nullptr);
|
|
}
|
|
}
|
|
|
|
// --- endpointSlack ---
|
|
|
|
TEST_F(StaDesignTest, EndpointSlack) {
|
|
Pin *pin = findPin("r3/D");
|
|
ASSERT_NE(pin, nullptr);
|
|
sta_->endpointSlack(pin, "clk", MinMax::max());
|
|
}
|
|
|
|
// --- replaceCell ---
|
|
|
|
TEST_F(StaDesignTest, ReplaceCell) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
// Find instance u1 (BUF_X1)
|
|
Instance *u1 = network->findChild(top, "u1");
|
|
ASSERT_NE(u1, nullptr);
|
|
// Replace with BUF_X2 (should exist in nangate45)
|
|
LibertyCell *buf_x2 = lib_->findLibertyCell("BUF_X2");
|
|
if (buf_x2) {
|
|
sta_->replaceCell(u1, buf_x2);
|
|
// Replace back
|
|
LibertyCell *buf_x1 = lib_->findLibertyCell("BUF_X1");
|
|
if (buf_x1)
|
|
sta_->replaceCell(u1, buf_x1);
|
|
}
|
|
}
|
|
|
|
// --- reportPathEnd with prev_end ---
|
|
|
|
TEST_F(StaDesignTest, ReportPathEndWithPrev) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
if (ends.size() >= 2) {
|
|
sta_->reportPathEnd(ends[1]);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- PathEnd static methods ---
|
|
|
|
TEST_F(StaDesignTest, PathEndLess) {
|
|
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.size() >= 2) {
|
|
PathEnd::less(ends[0], ends[1], true, sta_);
|
|
PathEnd::cmpNoCrpr(ends[0], ends[1], sta_);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- PathEnd accessors on real path ends ---
|
|
|
|
TEST_F(StaDesignTest, PathEndAccessors) {
|
|
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()) {
|
|
PathEnd *end = ends[0];
|
|
const char *tn = end->typeName();
|
|
EXPECT_NE(tn, nullptr);
|
|
end->type();
|
|
const RiseFall *rf = end->transition(sta_);
|
|
EXPECT_NE(rf, nullptr);
|
|
// PathEnd::pathIndex removed; use path->pathIndex instead
|
|
PathAPIndex idx = end->path()->pathIndex(sta_);
|
|
EXPECT_GE(idx, 0);
|
|
const Clock *tgt_clk = end->targetClk(sta_);
|
|
EXPECT_NE(tgt_clk, nullptr);
|
|
end->targetClkArrival(sta_);
|
|
end->targetClkTime(sta_);
|
|
end->targetClkOffset(sta_);
|
|
end->targetClkDelay(sta_);
|
|
end->targetClkInsertionDelay(sta_);
|
|
end->targetClkUncertainty(sta_);
|
|
end->targetNonInterClkUncertainty(sta_);
|
|
end->interClkUncertainty(sta_);
|
|
end->targetClkMcpAdjustment(sta_);
|
|
}
|
|
}
|
|
|
|
// --- ReportPath: reportShort for MinPeriodCheck ---
|
|
|
|
TEST_F(StaDesignTest, ReportPathShortMinPeriod) {
|
|
// minPeriodSlack and reportShort(MinPeriodCheck) removed
|
|
ReportPath *rpt = sta_->reportPath();
|
|
ASSERT_NE(rpt, nullptr);
|
|
}
|
|
|
|
// --- ReportPath: reportShort for MaxSkewCheck ---
|
|
|
|
TEST_F(StaDesignTest, ReportPathShortMaxSkew) {
|
|
// maxSkewSlack and reportShort(MaxSkewCheck) removed
|
|
ReportPath *rpt = sta_->reportPath();
|
|
ASSERT_NE(rpt, nullptr);
|
|
}
|
|
|
|
// --- ReportPath: reportCheck for MaxSkewCheck ---
|
|
|
|
TEST_F(StaDesignTest, ReportPathCheckMaxSkew) {
|
|
// maxSkewSlack and reportCheck(MaxSkewCheck) removed
|
|
ReportPath *rpt = sta_->reportPath();
|
|
ASSERT_NE(rpt, nullptr);
|
|
}
|
|
|
|
// --- ReportPath: reportVerbose for MaxSkewCheck ---
|
|
|
|
TEST_F(StaDesignTest, ReportPathVerboseMaxSkew) {
|
|
// maxSkewSlack and reportVerbose(MaxSkewCheck) removed
|
|
ReportPath *rpt = sta_->reportPath();
|
|
ASSERT_NE(rpt, nullptr);
|
|
}
|
|
|
|
// --- ReportPath: reportMpwChecks (covers mpwCheckHiLow internally) ---
|
|
|
|
TEST_F(StaDesignTest, ReportMpwChecks) {
|
|
// minPulseWidthChecks removed; testing reportMinPulseWidthChecks
|
|
sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes());
|
|
}
|
|
|
|
// --- findClkMinPeriod ---
|
|
|
|
TEST_F(StaDesignTest, FindClkMinPeriod) {
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
sta_->findClkMinPeriod(clk, false);
|
|
}
|
|
|
|
// --- slowDrivers ---
|
|
|
|
TEST_F(StaDesignTest, SlowDrivers) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->slowDrivers(5);
|
|
}() ));
|
|
}
|
|
|
|
// --- vertexLevel ---
|
|
|
|
TEST_F(StaDesignTest, VertexLevel) {
|
|
Vertex *v = findVertex("u1/Z");
|
|
ASSERT_NE(v, nullptr);
|
|
Level lvl = sta_->vertexLevel(v);
|
|
EXPECT_GE(lvl, 0);
|
|
}
|
|
|
|
// --- simLogicValue ---
|
|
|
|
TEST_F(StaDesignTest, SimLogicValue) {
|
|
Pin *pin = findPin("u1/Z");
|
|
ASSERT_NE(pin, nullptr);
|
|
sta_->simLogicValue(pin, sta_->cmdMode());
|
|
}
|
|
|
|
// --- Search: clear (exercises initVars internally) ---
|
|
|
|
TEST_F(StaDesignTest, SearchClear) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
// clear() calls initVars() internally
|
|
search->clear();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- readLibertyFile (protected, call through public readLiberty) ---
|
|
// This tests readLibertyFile indirectly
|
|
|
|
TEST_F(StaDesignTest, ReadLibertyFile) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Scene *corner = sta_->cmdScene();
|
|
LibertyLibrary *lib = sta_->readLiberty(
|
|
"test/nangate45/Nangate45_slow.lib", corner, MinMaxAll::min(), false);
|
|
(void)lib;
|
|
// May or may not succeed depending on file existence; just check no crash
|
|
}() ));
|
|
}
|
|
|
|
// --- Property: getProperty on LibertyLibrary ---
|
|
|
|
TEST_F(StaDesignTest, PropertyGetPropertyLibertyLibrary) {
|
|
Properties &props = sta_->properties();
|
|
ASSERT_NE(lib_, nullptr);
|
|
props.getProperty(lib_, "name");
|
|
}
|
|
|
|
// --- Property: getProperty on LibertyCell ---
|
|
|
|
TEST_F(StaDesignTest, PropertyGetPropertyLibertyCell) {
|
|
Properties &props = sta_->properties();
|
|
LibertyCell *buf = lib_->findLibertyCell("BUF_X1");
|
|
ASSERT_NE(buf, nullptr);
|
|
props.getProperty(buf, "name");
|
|
}
|
|
|
|
// --- findPathEnds with unconstrained ---
|
|
|
|
TEST_F(StaDesignTest, FindPathEndsUnconstrained) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
true, // unconstrained
|
|
sta_->scenes(), // all scenes
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
}() ));
|
|
}
|
|
|
|
// --- findPathEnds with hold ---
|
|
|
|
TEST_F(StaDesignTest, FindPathEndsHold) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::min(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
false, true, false, false, false, false);
|
|
}() ));
|
|
}
|
|
|
|
// --- Search: findAllArrivals ---
|
|
|
|
TEST_F(StaDesignTest, SearchFindAllArrivals) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
search->findAllArrivals();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Search: findArrivals / findRequireds ---
|
|
|
|
TEST_F(StaDesignTest, SearchFindArrivalsRequireds) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
search->findArrivals();
|
|
search->findRequireds();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Search: clocks for vertex ---
|
|
|
|
TEST_F(StaDesignTest, SearchClocksVertex) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
Vertex *v = findVertex("r1/CK");
|
|
if (v) {
|
|
search->clocks(v, sta_->cmdMode());
|
|
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Search: wnsSlack ---
|
|
|
|
TEST_F(StaDesignTest, SearchWnsSlack) {
|
|
Search *search = sta_->search();
|
|
Vertex *v = findVertex("r3/D");
|
|
ASSERT_NE(v, nullptr);
|
|
search->wnsSlack(v, 0);
|
|
}
|
|
|
|
// --- Search: isEndpoint ---
|
|
|
|
TEST_F(StaDesignTest, SearchIsEndpoint) {
|
|
Search *search = sta_->search();
|
|
Vertex *v = findVertex("r3/D");
|
|
ASSERT_NE(v, nullptr);
|
|
EXPECT_TRUE(search->isEndpoint(v));
|
|
}
|
|
|
|
// --- reportParasiticAnnotation ---
|
|
|
|
TEST_F(StaDesignTest, ReportParasiticAnnotation) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->reportParasiticAnnotation("", false);
|
|
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- findClkDelays ---
|
|
|
|
TEST_F(StaDesignTest, FindClkDelays) {
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
sta_->findClkDelays(clk, sta_->cmdScene(), false);
|
|
}
|
|
|
|
// --- reportClkLatency ---
|
|
|
|
TEST_F(StaDesignTest, ReportClkLatency) {
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
ConstClockSeq clks;
|
|
clks.push_back(clk);
|
|
sta_->reportClkLatency(clks, sta_->scenes(), false, 4);
|
|
}
|
|
|
|
// --- findWorstClkSkew ---
|
|
|
|
TEST_F(StaDesignTest, FindWorstClkSkew) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->findWorstClkSkew(SetupHold::max(), false);
|
|
}() ));
|
|
}
|
|
|
|
// --- ReportPath: reportJson on a Path ---
|
|
|
|
TEST_F(StaDesignTest, ReportJsonPath) {
|
|
Vertex *v = findVertex("r1/Q");
|
|
ASSERT_NE(v, nullptr);
|
|
Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max());
|
|
if (path && !path->isNull()) {
|
|
ReportPath *rpt = sta_->reportPath();
|
|
rpt->reportJson(path);
|
|
}
|
|
}
|
|
|
|
// --- reportEndHeader / reportEndLine ---
|
|
|
|
TEST_F(StaDesignTest, ReportEndHeaderLine) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathFormat(ReportPathFormat::endpoint);
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
ReportPath *rpt = sta_->reportPath();
|
|
rpt->reportEndHeader();
|
|
if (!ends.empty()) {
|
|
rpt->reportEndLine(ends[0]);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- reportSummaryHeader / reportSummaryLine ---
|
|
|
|
TEST_F(StaDesignTest, ReportSummaryHeaderLine) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathFormat(ReportPathFormat::summary);
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
ReportPath *rpt = sta_->reportPath();
|
|
rpt->reportSummaryHeader();
|
|
if (!ends.empty()) {
|
|
rpt->reportSummaryLine(ends[0]);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- reportSlackOnlyHeader / reportSlackOnly ---
|
|
|
|
TEST_F(StaDesignTest, ReportSlackOnly) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathFormat(ReportPathFormat::slack_only);
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
ReportPath *rpt = sta_->reportPath();
|
|
rpt->reportSlackOnlyHeader();
|
|
if (!ends.empty()) {
|
|
rpt->reportSlackOnly(ends[0]);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Search: reportArrivals ---
|
|
|
|
TEST_F(StaDesignTest, SearchReportArrivals) {
|
|
Search *search = sta_->search();
|
|
Vertex *v = findVertex("r1/Q");
|
|
ASSERT_NE(v, nullptr);
|
|
search->reportArrivals(v, false);
|
|
}
|
|
|
|
// --- Search: reportPathCountHistogram ---
|
|
|
|
TEST_F(StaDesignTest, SearchReportPathCountHistogram) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
search->reportPathCountHistogram();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Search: reportTags ---
|
|
|
|
TEST_F(StaDesignTest, SearchReportTags) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
search->reportTags();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Search: reportClkInfos ---
|
|
|
|
TEST_F(StaDesignTest, SearchReportClkInfos) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
search->reportClkInfos();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- setReportPathFields ---
|
|
|
|
TEST_F(StaDesignTest, SetReportPathFields) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathFields(true, true, true, true, true, true, true, true);
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- setReportPathFieldOrder ---
|
|
|
|
TEST_F(StaDesignTest, SetReportPathFieldOrder) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
StringSeq fields;
|
|
fields.push_back("Fanout");
|
|
fields.push_back("Cap");
|
|
sta_->setReportPathFieldOrder(fields);
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Search: saveEnumPath ---
|
|
// (This is complex - need a valid enumerated path. Test existence.)
|
|
|
|
TEST_F(StaDesignTest, SearchSaveEnumPathExists) {
|
|
auto fn = &Search::saveEnumPath;
|
|
expectCallablePointerUsable(fn);
|
|
}
|
|
|
|
// --- vertexPathCount ---
|
|
|
|
TEST_F(StaDesignTest, VertexPathCount) {
|
|
Vertex *v = findVertex("r1/Q");
|
|
ASSERT_NE(v, nullptr);
|
|
int count = sta_->vertexPathCount(v);
|
|
EXPECT_GE(count, 0);
|
|
}
|
|
|
|
// --- pathCount ---
|
|
|
|
TEST_F(StaDesignTest, PathCount) {
|
|
int count = sta_->pathCount();
|
|
EXPECT_GE(count, 0);
|
|
}
|
|
|
|
// --- writeSdc ---
|
|
|
|
TEST_F(StaDesignTest, WriteSdc) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->writeSdc(sta_->cmdSdc(), "/dev/null", false, false, 4, false, true);
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- ReportPath: reportFull for PathEndCheck ---
|
|
|
|
TEST_F(StaDesignTest, ReportPathFullPathEnd) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathFormat(ReportPathFormat::full);
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
if (!ends.empty()) {
|
|
// reportPathEnd with full format calls reportFull
|
|
sta_->reportPathEnd(ends[0]);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Search: ensureDownstreamClkPins ---
|
|
|
|
TEST_F(StaDesignTest, SearchEnsureDownstreamClkPins) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
search->ensureDownstreamClkPins();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Genclks ---
|
|
|
|
TEST_F(StaDesignTest, GenclksAccessor) {
|
|
// Search::genclks() removed from API
|
|
Search *search = sta_->search();
|
|
EXPECT_NE(search, nullptr);
|
|
}
|
|
|
|
// --- CheckCrpr accessor ---
|
|
|
|
TEST_F(StaDesignTest, CheckCrprAccessor) {
|
|
Search *search = sta_->search();
|
|
CheckCrpr *crpr = search->checkCrpr();
|
|
EXPECT_NE(crpr, nullptr);
|
|
}
|
|
|
|
// --- GatedClk accessor ---
|
|
|
|
TEST_F(StaDesignTest, GatedClkAccessor) {
|
|
Search *search = sta_->search();
|
|
GatedClk *gated = search->gatedClk();
|
|
EXPECT_NE(gated, nullptr);
|
|
}
|
|
|
|
// --- VisitPathEnds accessor ---
|
|
|
|
TEST_F(StaDesignTest, VisitPathEndsAccessor) {
|
|
Search *search = sta_->search();
|
|
VisitPathEnds *vpe = search->visitPathEnds();
|
|
EXPECT_NE(vpe, nullptr);
|
|
}
|
|
|
|
// ============================================================
|
|
// Additional R8_ tests for more coverage
|
|
// ============================================================
|
|
|
|
// --- Search: worstSlack (triggers WorstSlack methods) ---
|
|
|
|
TEST_F(StaDesignTest, SearchWorstSlackMinMax) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
Slack worst;
|
|
Vertex *worst_vertex = nullptr;
|
|
search->worstSlack(MinMax::max(), worst, worst_vertex);
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchWorstSlackCorner) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
Scene *corner = sta_->cmdScene();
|
|
Slack worst;
|
|
Vertex *worst_vertex = nullptr;
|
|
search->worstSlack(corner, MinMax::max(), worst, worst_vertex);
|
|
}() ));
|
|
}
|
|
|
|
// --- Search: totalNegativeSlack ---
|
|
|
|
TEST_F(StaDesignTest, SearchTotalNegativeSlack) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
search->totalNegativeSlack(MinMax::max());
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchTotalNegativeSlackCorner) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
Scene *corner = sta_->cmdScene();
|
|
search->totalNegativeSlack(corner, MinMax::max());
|
|
}() ));
|
|
}
|
|
|
|
// --- Property: getProperty on Edge ---
|
|
|
|
TEST_F(StaDesignTest, PropertyGetEdge) {
|
|
Properties &props = sta_->properties();
|
|
Vertex *v = findVertex("u1/Z");
|
|
ASSERT_NE(v, nullptr);
|
|
VertexInEdgeIterator edge_iter(v, sta_->graph());
|
|
if (edge_iter.hasNext()) {
|
|
Edge *edge = edge_iter.next();
|
|
props.getProperty(edge, "full_name");
|
|
}
|
|
}
|
|
|
|
// --- Property: getProperty on Clock ---
|
|
|
|
TEST_F(StaDesignTest, PropertyGetClock) {
|
|
Properties &props = sta_->properties();
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
props.getProperty(clk, "name");
|
|
}
|
|
|
|
// --- Property: getProperty on LibertyPort ---
|
|
|
|
TEST_F(StaDesignTest, PropertyGetLibertyPort) {
|
|
Properties &props = sta_->properties();
|
|
LibertyCell *buf = lib_->findLibertyCell("BUF_X1");
|
|
ASSERT_NE(buf, nullptr);
|
|
LibertyPort *port = buf->findLibertyPort("A");
|
|
ASSERT_NE(port, nullptr);
|
|
props.getProperty(port, "name");
|
|
}
|
|
|
|
// --- Property: getProperty on Port ---
|
|
|
|
TEST_F(StaDesignTest, PropertyGetPort) {
|
|
Properties &props = sta_->properties();
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Cell *cell = network->cell(top);
|
|
ASSERT_NE(cell, nullptr);
|
|
Port *port = network->findPort(cell, "clk1");
|
|
if (port) {
|
|
props.getProperty(port, "name");
|
|
}
|
|
}
|
|
|
|
// --- Sta: makeInstance / deleteInstance ---
|
|
|
|
TEST_F(StaDesignTest, MakeDeleteInstance) {
|
|
LibertyCell *buf = lib_->findLibertyCell("BUF_X1");
|
|
ASSERT_NE(buf, nullptr);
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Instance *new_inst = sta_->makeInstance("test_buf", buf, top);
|
|
ASSERT_NE(new_inst, nullptr);
|
|
sta_->deleteInstance(new_inst);
|
|
}
|
|
|
|
// --- Sta: makeNet / deleteNet ---
|
|
|
|
TEST_F(StaDesignTest, MakeDeleteNet) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Net *new_net = sta_->makeNet("test_net", top);
|
|
ASSERT_NE(new_net, nullptr);
|
|
sta_->deleteNet(new_net);
|
|
}
|
|
|
|
// --- Sta: connectPin / disconnectPin ---
|
|
|
|
TEST_F(StaDesignTest, ConnectDisconnectPin) {
|
|
LibertyCell *buf = lib_->findLibertyCell("BUF_X1");
|
|
ASSERT_NE(buf, nullptr);
|
|
LibertyPort *port_a = buf->findLibertyPort("A");
|
|
ASSERT_NE(port_a, nullptr);
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Instance *new_inst = sta_->makeInstance("test_buf2", buf, top);
|
|
ASSERT_NE(new_inst, nullptr);
|
|
Net *new_net = sta_->makeNet("test_net2", top);
|
|
ASSERT_NE(new_net, nullptr);
|
|
sta_->connectPin(new_inst, port_a, new_net);
|
|
// Find the pin and disconnect
|
|
Pin *pin = network->findPin(new_inst, "A");
|
|
ASSERT_NE(pin, nullptr);
|
|
sta_->disconnectPin(pin);
|
|
sta_->deleteNet(new_net);
|
|
sta_->deleteInstance(new_inst);
|
|
}
|
|
|
|
// --- Sta: endpointPins ---
|
|
|
|
TEST_F(StaDesignTest, EndpointPins) {
|
|
PinSet eps = sta_->endpointPins();
|
|
EXPECT_GT(eps.size(), 0u);
|
|
}
|
|
|
|
// --- Sta: startpointPins ---
|
|
|
|
TEST_F(StaDesignTest, StartpointPins) {
|
|
// startpointPins() is declared in Sta.hh but not defined - skip
|
|
// PinSet sps = sta_->startpointPins();
|
|
// EXPECT_GT(sps.size(), 0u);
|
|
}
|
|
|
|
// --- Search: arrivalsValid ---
|
|
|
|
TEST_F(StaDesignTest, SearchArrivalsValidDesign) {
|
|
Search *search = sta_->search();
|
|
bool valid = search->arrivalsValid();
|
|
EXPECT_TRUE(valid);
|
|
}
|
|
|
|
// --- Sta: netSlack ---
|
|
|
|
TEST_F(StaDesignTest, NetSlack) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Pin *pin = findPin("u1/Z");
|
|
ASSERT_NE(pin, nullptr);
|
|
Net *net = network->net(pin);
|
|
if (net) {
|
|
sta_->slack(net, MinMax::max());
|
|
}
|
|
}
|
|
|
|
// --- Sta: pinSlack ---
|
|
|
|
TEST_F(StaDesignTest, PinSlackMinMax) {
|
|
Pin *pin = findPin("r3/D");
|
|
ASSERT_NE(pin, nullptr);
|
|
sta_->slack(pin, RiseFallBoth::riseFall(), sta_->scenes(), MinMax::max());
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PinSlackRfMinMax) {
|
|
Pin *pin = findPin("r3/D");
|
|
ASSERT_NE(pin, nullptr);
|
|
sta_->slack(pin, RiseFallBoth::rise(), sta_->scenes(), MinMax::max());
|
|
}
|
|
|
|
// --- Sta: pinArrival ---
|
|
|
|
TEST_F(StaDesignTest, PinArrival) {
|
|
Pin *pin = findPin("u1/Z");
|
|
ASSERT_NE(pin, nullptr);
|
|
sta_->arrival(pin, RiseFallBoth::rise(), MinMax::max());
|
|
}
|
|
|
|
// --- Sta: clocks / clockDomains ---
|
|
|
|
TEST_F(StaDesignTest, ClocksOnPin) {
|
|
Pin *pin = findPin("clk1");
|
|
ASSERT_NE(pin, nullptr);
|
|
sta_->clocks(pin, sta_->cmdMode());
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ClockDomainsOnPin) {
|
|
Pin *pin = findPin("r1/CK");
|
|
ASSERT_NE(pin, nullptr);
|
|
sta_->clockDomains(pin, sta_->cmdMode());
|
|
}
|
|
|
|
// --- Sta: vertexWorstArrivalPath (both overloads) ---
|
|
|
|
TEST_F(StaDesignTest, VertexWorstArrivalPathMinMax) {
|
|
Vertex *v = findVertex("r1/Q");
|
|
ASSERT_NE(v, nullptr);
|
|
Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max());
|
|
EXPECT_NE(path, nullptr);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, VertexWorstArrivalPathRf) {
|
|
Vertex *v = findVertex("r1/Q");
|
|
ASSERT_NE(v, nullptr);
|
|
Path *path = sta_->vertexWorstArrivalPath(v, RiseFall::rise(), MinMax::max());
|
|
EXPECT_NE(path, nullptr);
|
|
}
|
|
|
|
// --- Sta: vertexWorstSlackPath ---
|
|
|
|
TEST_F(StaDesignTest, VertexWorstSlackPath) {
|
|
Vertex *v = findVertex("r3/D");
|
|
ASSERT_NE(v, nullptr);
|
|
Path *path = sta_->vertexWorstSlackPath(v, MinMax::max());
|
|
EXPECT_NE(path, nullptr);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, VertexWorstSlackPathRf) {
|
|
Vertex *v = findVertex("r3/D");
|
|
ASSERT_NE(v, nullptr);
|
|
Path *path = sta_->vertexWorstSlackPath(v, RiseFall::rise(), MinMax::max());
|
|
EXPECT_NE(path, nullptr);
|
|
}
|
|
|
|
// --- Search: isClock on clock vertex ---
|
|
|
|
TEST_F(StaDesignTest, SearchIsClockVertex) {
|
|
Search *search = sta_->search();
|
|
Vertex *v = findVertex("r1/CK");
|
|
ASSERT_NE(v, nullptr);
|
|
(void)(search->clocks(v, sta_->cmdMode()).size() > 0);
|
|
}
|
|
|
|
// --- Search: clkPathArrival ---
|
|
|
|
TEST_F(StaDesignTest, SearchClkPathArrival) {
|
|
Search *search = sta_->search();
|
|
// Need a clock path
|
|
Vertex *v = findVertex("r1/CK");
|
|
ASSERT_NE(v, nullptr);
|
|
Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max());
|
|
if (path && !path->isNull()) {
|
|
search->clkPathArrival(path);
|
|
}
|
|
}
|
|
|
|
// --- Sta: removeDelaySlewAnnotations ---
|
|
|
|
TEST_F(StaDesignTest, RemoveDelaySlewAnnotations) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->removeDelaySlewAnnotations();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Sta: deleteParasitics ---
|
|
|
|
TEST_F(StaDesignTest, DeleteParasitics) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->deleteParasitics();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Sta: delaysInvalid (constraintsChanged was removed) ---
|
|
|
|
TEST_F(StaDesignTest, DelaysInvalid2) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->delaysInvalid();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Sta: networkChanged ---
|
|
|
|
TEST_F(StaDesignTest, NetworkChanged) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->networkChanged();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Search: endpointsInvalid ---
|
|
|
|
TEST_F(StaDesignTest, EndpointsInvalid) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
search->endpointsInvalid();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Search: requiredsInvalid ---
|
|
|
|
TEST_F(StaDesignTest, RequiredsInvalid) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
search->requiredsInvalid();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Search: deleteFilter / filteredEndpoints ---
|
|
|
|
TEST_F(StaDesignTest, SearchDeleteFilter) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
// No filter set, but calling is safe
|
|
search->deleteFilter();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Sta: reportDelayCalc ---
|
|
|
|
TEST_F(StaDesignTest, ReportDelayCalc) {
|
|
Vertex *v = findVertex("u1/Z");
|
|
ASSERT_NE(v, nullptr);
|
|
VertexInEdgeIterator edge_iter(v, sta_->graph());
|
|
if (edge_iter.hasNext()) {
|
|
Edge *edge = edge_iter.next();
|
|
TimingArcSet *arc_set = edge->timingArcSet();
|
|
if (arc_set && !arc_set->arcs().empty()) {
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->reportDelayCalc(
|
|
edge, arc_set->arcs()[0], corner, MinMax::max(), 4);
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Sta: arcDelay ---
|
|
|
|
TEST_F(StaDesignTest, ArcDelay) {
|
|
Vertex *v = findVertex("u1/Z");
|
|
ASSERT_NE(v, nullptr);
|
|
VertexInEdgeIterator edge_iter(v, sta_->graph());
|
|
if (edge_iter.hasNext()) {
|
|
Edge *edge = edge_iter.next();
|
|
TimingArcSet *arc_set = edge->timingArcSet();
|
|
if (arc_set && !arc_set->arcs().empty()) {
|
|
Scene *corner = sta_->cmdScene();
|
|
const DcalcAPIndex dcalc_idx = corner->dcalcAnalysisPtIndex(MinMax::max());
|
|
sta_->arcDelay(edge, arc_set->arcs()[0], dcalc_idx);
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Sta: arcDelayAnnotated ---
|
|
|
|
TEST_F(StaDesignTest, ArcDelayAnnotated) {
|
|
Vertex *v = findVertex("u1/Z");
|
|
ASSERT_NE(v, nullptr);
|
|
VertexInEdgeIterator edge_iter(v, sta_->graph());
|
|
if (edge_iter.hasNext()) {
|
|
Edge *edge = edge_iter.next();
|
|
TimingArcSet *arc_set = edge->timingArcSet();
|
|
if (arc_set && !arc_set->arcs().empty()) {
|
|
Scene *corner = sta_->cmdScene();
|
|
DcalcAPIndex dcalc_idx = corner->dcalcAnalysisPtIndex(MinMax::max());
|
|
(void)dcalc_idx;
|
|
sta_->arcDelayAnnotated(edge, arc_set->arcs()[0], corner, MinMax::max());
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Sta: findReportPathField ---
|
|
|
|
TEST_F(StaDesignTest, FindReportPathField) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->findReportPathField("Fanout");
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Search: arrivalInvalid on a vertex ---
|
|
|
|
TEST_F(StaDesignTest, SearchArrivalInvalid) {
|
|
Search *search = sta_->search();
|
|
Vertex *v = findVertex("u1/Z");
|
|
ASSERT_NE(v, nullptr);
|
|
search->arrivalInvalid(v);
|
|
}
|
|
|
|
// --- Search: requiredInvalid on a vertex ---
|
|
|
|
TEST_F(StaDesignTest, SearchRequiredInvalid) {
|
|
Search *search = sta_->search();
|
|
Vertex *v = findVertex("r3/D");
|
|
ASSERT_NE(v, nullptr);
|
|
search->requiredInvalid(v);
|
|
}
|
|
|
|
// --- Search: isSegmentStart ---
|
|
|
|
TEST_F(StaDesignTest, SearchIsSegmentStart) {
|
|
Search *search = sta_->search();
|
|
(void)search;
|
|
Pin *pin = findPin("in1");
|
|
ASSERT_NE(pin, nullptr);
|
|
(void)true /* Search::isSegmentStart removed */;
|
|
}
|
|
|
|
// --- Search: isInputArrivalSrchStart ---
|
|
|
|
TEST_F(StaDesignTest, SearchIsInputArrivalSrchStart) {
|
|
Search *search = sta_->search();
|
|
Vertex *v = findVertex("in1");
|
|
ASSERT_NE(v, nullptr);
|
|
EXPECT_TRUE(search->isInputArrivalSrchStart(v));
|
|
}
|
|
|
|
// --- Sta: operatingConditions ---
|
|
|
|
TEST_F(StaDesignTest, OperatingConditions) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->operatingConditions(MinMax::max(), sta_->cmdSdc());
|
|
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Search: evalPred / searchAdj ---
|
|
|
|
TEST_F(StaDesignTest, SearchEvalPred) {
|
|
Search *search = sta_->search();
|
|
EvalPred *ep = search->evalPred();
|
|
EXPECT_NE(ep, nullptr);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchSearchAdj) {
|
|
Search *search = sta_->search();
|
|
SearchPred *sp = search->searchAdj();
|
|
EXPECT_NE(sp, nullptr);
|
|
}
|
|
|
|
// --- Search: endpointInvalid ---
|
|
|
|
TEST_F(StaDesignTest, SearchEndpointInvalid) {
|
|
Search *search = sta_->search();
|
|
Vertex *v = findVertex("r3/D");
|
|
ASSERT_NE(v, nullptr);
|
|
search->endpointInvalid(v);
|
|
}
|
|
|
|
// --- Search: tnsInvalid ---
|
|
|
|
TEST_F(StaDesignTest, SearchTnsInvalid) {
|
|
Search *search = sta_->search();
|
|
Vertex *v = findVertex("r3/D");
|
|
ASSERT_NE(v, nullptr);
|
|
search->tnsInvalid(v);
|
|
}
|
|
|
|
// --- Sta: unsetTimingDerate ---
|
|
|
|
TEST_F(StaDesignTest, UnsetTimingDerate) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->unsetTimingDerate(sta_->cmdSdc());
|
|
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Sta: setAnnotatedSlew ---
|
|
|
|
TEST_F(StaDesignTest, SetAnnotatedSlew) {
|
|
Vertex *v = findVertex("u1/Z");
|
|
ASSERT_NE(v, nullptr);
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->setAnnotatedSlew(v, corner, MinMaxAll::all(),
|
|
RiseFallBoth::riseFall(), 1.0e-10f);
|
|
}
|
|
|
|
// --- Sta: vertexPathIterator with MinMax ---
|
|
|
|
TEST_F(StaDesignTest, VertexPathIteratorMinMax) {
|
|
Vertex *v = findVertex("r1/Q");
|
|
ASSERT_NE(v, nullptr);
|
|
// vertexWorstArrivalPath returns a single Path* (not an iterator)
|
|
Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max());
|
|
// May be null if no arrivals computed
|
|
if (path) {
|
|
EXPECT_FALSE(path->isNull());
|
|
}
|
|
}
|
|
|
|
// --- Tag comparison operations (exercised through timing) ---
|
|
|
|
TEST_F(StaDesignTest, TagOperations) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
TagIndex count = search->tagCount();
|
|
if (count >= 2) {
|
|
Tag *t0 = search->tag(0);
|
|
Tag *t1 = search->tag(1);
|
|
if (t0 && t1) {
|
|
// Exercise TagLess
|
|
TagLess less(sta_);
|
|
less(t0, t1);
|
|
// Exercise TagIndexLess
|
|
TagIndexLess idx_less;
|
|
idx_less(t0, t1);
|
|
// Exercise Tag::equal
|
|
Tag::equal(t0, t1, sta_);
|
|
}
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- PathEnd::cmp ---
|
|
|
|
TEST_F(StaDesignTest, PathEndCmp) {
|
|
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.size() >= 2) {
|
|
PathEnd::cmp(ends[0], ends[1], true, sta_);
|
|
PathEnd::cmpSlack(ends[0], ends[1], sta_);
|
|
PathEnd::cmpArrival(ends[0], ends[1], sta_);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- PathEnd: various accessors on specific PathEnd types ---
|
|
|
|
TEST_F(StaDesignTest, PathEndSlackNoCrpr) {
|
|
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()) {
|
|
PathEnd *end = ends[0];
|
|
end->slack(sta_);
|
|
end->slackNoCrpr(sta_);
|
|
end->margin(sta_);
|
|
end->requiredTime(sta_);
|
|
end->dataArrivalTime(sta_);
|
|
end->sourceClkOffset(sta_);
|
|
const ClockEdge *src_edge = end->sourceClkEdge(sta_);
|
|
EXPECT_NE(src_edge, nullptr);
|
|
end->sourceClkLatency(sta_);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- PathEnd: reportShort ---
|
|
|
|
TEST_F(StaDesignTest, PathEndReportShort) {
|
|
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()) {
|
|
ReportPath *rpt = sta_->reportPath();
|
|
ends[0]->reportShort(rpt);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- PathEnd: copy ---
|
|
|
|
TEST_F(StaDesignTest, PathEndCopy) {
|
|
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()) {
|
|
PathEnd *copy = ends[0]->copy();
|
|
EXPECT_NE(copy, nullptr);
|
|
delete copy;
|
|
}
|
|
}
|
|
|
|
// --- Search: tagGroup for a vertex ---
|
|
|
|
TEST_F(StaDesignTest, SearchTagGroupForVertex) {
|
|
Search *search = sta_->search();
|
|
Vertex *v = findVertex("r1/Q");
|
|
ASSERT_NE(v, nullptr);
|
|
TagGroup *tg = search->tagGroup(v);
|
|
EXPECT_NE(tg, nullptr);
|
|
}
|
|
|
|
// --- Sta: findFaninPins / findFanoutPins ---
|
|
|
|
TEST_F(StaDesignTest, FindFaninPins) {
|
|
Pin *pin = findPin("r3/D");
|
|
ASSERT_NE(pin, nullptr);
|
|
PinSeq to_pins;
|
|
to_pins.push_back(pin);
|
|
sta_->findFaninPins(&to_pins, false, false, 0, 10, false, false, sta_->cmdMode());
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindFanoutPins) {
|
|
Pin *pin = findPin("r1/Q");
|
|
ASSERT_NE(pin, nullptr);
|
|
PinSeq from_pins;
|
|
from_pins.push_back(pin);
|
|
sta_->findFanoutPins(&from_pins, false, false, 0, 10, false, false, sta_->cmdMode());
|
|
}
|
|
|
|
// --- Sta: findFaninInstances / findFanoutInstances ---
|
|
|
|
TEST_F(StaDesignTest, FindFaninInstances) {
|
|
Pin *pin = findPin("r3/D");
|
|
ASSERT_NE(pin, nullptr);
|
|
PinSeq to_pins;
|
|
to_pins.push_back(pin);
|
|
sta_->findFaninInstances(&to_pins, false, false, 0, 10, false, false, sta_->cmdMode());
|
|
}
|
|
|
|
// --- Sta: setVoltage ---
|
|
|
|
TEST_F(StaDesignTest, SetVoltage) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setVoltage(MinMax::max(), 1.1f, sta_->cmdSdc());
|
|
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Sta: removeConstraints ---
|
|
|
|
TEST_F(StaDesignTest, RemoveConstraints) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
// This is a destructive operation, so call it but re-create constraints after
|
|
// Just verifying it doesn't crash
|
|
// removeConstraints() removed
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Search: filter ---
|
|
|
|
TEST_F(StaDesignTest, SearchFilter) {
|
|
Search *search = sta_->search();
|
|
(void)search;
|
|
FilterPath *filter = nullptr /* Search::filter() removed */;
|
|
// filter should be null since we haven't set one
|
|
EXPECT_EQ(filter, nullptr);
|
|
}
|
|
|
|
// --- PathExpanded: path(i) and pathsIndex ---
|
|
|
|
TEST_F(StaDesignTest, PathExpandedPaths) {
|
|
Vertex *v = findVertex("u2/ZN");
|
|
ASSERT_NE(v, nullptr);
|
|
Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max());
|
|
if (path && !path->isNull()) {
|
|
PathExpanded expanded(path, true, sta_);
|
|
for (size_t i = 0; i < expanded.size(); i++) {
|
|
const Path *p = expanded.path(i);
|
|
EXPECT_NE(p, nullptr);
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Sta: setOutputDelay ---
|
|
|
|
TEST_F(StaDesignTest, SetOutputDelay) {
|
|
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, 0.0f,
|
|
sta_->cmdSdc());
|
|
}
|
|
|
|
// --- Sta: findPathEnds with setup+hold ---
|
|
|
|
TEST_F(StaDesignTest, FindPathEndsSetupHold) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::all(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, true, false, false, false, false);
|
|
}() ));
|
|
}
|
|
|
|
// --- Sta: findPathEnds unique_pins ---
|
|
|
|
TEST_F(StaDesignTest, FindPathEndsUniquePins) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 3, true, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
}() ));
|
|
}
|
|
|
|
// --- Sta: findPathEnds sort_by_slack ---
|
|
|
|
TEST_F(StaDesignTest, FindPathEndsSortBySlack) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, true, group_names,
|
|
true, false, false, false, false, false);
|
|
}() ));
|
|
}
|
|
|
|
// --- Sta: reportChecks for MinPeriod ---
|
|
|
|
TEST_F(StaDesignTest, ReportChecksMinPeriod) {
|
|
// minPeriodViolations removed; test reportMinPeriodChecks
|
|
sta_->reportMinPeriodChecks(nullptr, 10, false, false, sta_->scenes());
|
|
}
|
|
|
|
// --- Sta: reportChecks for MaxSkew ---
|
|
|
|
TEST_F(StaDesignTest, ReportChecksMaxSkew) {
|
|
// maxSkewViolations removed; testing reportMaxSkewChecks
|
|
sta_->reportMaxSkewChecks(nullptr, 10, false, false, sta_->scenes());
|
|
}
|
|
|
|
// --- ReportPath: reportPeriodHeaderShort ---
|
|
|
|
TEST_F(StaDesignTest, ReportPeriodHeaderShort) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
ReportPath *rpt = sta_->reportPath();
|
|
rpt->reportPeriodHeaderShort();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- ReportPath: reportMpwHeaderShort ---
|
|
|
|
TEST_F(StaDesignTest, ReportMpwHeaderShort) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
ReportPath *rpt = sta_->reportPath();
|
|
rpt->reportMpwHeaderShort();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Sta: maxSlewCheck ---
|
|
|
|
TEST_F(StaDesignTest, MaxSlewCheck) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->checkSlewsPreamble();
|
|
const Pin *pin = nullptr;
|
|
Slew slew;
|
|
float slack, limit;
|
|
sta_->maxSlewCheck(pin, slew, slack, limit);
|
|
// pin may be null if no slew limits
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Sta: maxFanoutCheck ---
|
|
|
|
TEST_F(StaDesignTest, MaxFanoutCheck) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->checkFanoutPreamble();
|
|
const Pin *pin = nullptr;
|
|
(void)pin;
|
|
float fanout, slack, limit;
|
|
(void)fanout;
|
|
(void)slack;
|
|
(void)limit;
|
|
// maxFanoutCheck removed (renamed to maxFanoutMinSlackPin);
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Sta: maxCapacitanceCheck ---
|
|
|
|
TEST_F(StaDesignTest, MaxCapacitanceCheck) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->checkCapacitancesPreamble(sta_->scenes());
|
|
|
|
const Pin *pin = nullptr;
|
|
float cap, slack, limit;
|
|
sta_->maxCapacitanceCheck(pin, cap, slack, limit);
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Sta: vertexSlack with RiseFall + MinMax ---
|
|
|
|
TEST_F(StaDesignTest, VertexSlackRfMinMax) {
|
|
Vertex *v = findVertex("r3/D");
|
|
ASSERT_NE(v, nullptr);
|
|
sta_->slack(v, RiseFall::rise(), MinMax::max());
|
|
}
|
|
|
|
// --- Sta: vertexSlew with MinMax only ---
|
|
|
|
TEST_F(StaDesignTest, VertexSlewMinMax) {
|
|
Vertex *v = findVertex("u1/Z");
|
|
ASSERT_NE(v, nullptr);
|
|
sta_->slew(v, RiseFallBoth::riseFall(), sta_->scenes(), MinMax::max());
|
|
}
|
|
|
|
// --- Sta: setReportPathFormat to each format and report ---
|
|
|
|
TEST_F(StaDesignTest, ReportPathEndpointFormat) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathFormat(ReportPathFormat::endpoint);
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
if (ends.size() >= 2) {
|
|
sta_->reportPathEnd(ends[0]);
|
|
sta_->reportPathEnd(ends[1]);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Search: findClkVertexPins ---
|
|
|
|
TEST_F(StaDesignTest, SearchFindClkVertexPins) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
PinSet clk_pins(sta_->cmdNetwork());
|
|
|
|
search->findClkVertexPins(clk_pins);
|
|
}() ));
|
|
}
|
|
|
|
// --- Property: getProperty on PathEnd ---
|
|
|
|
TEST_F(StaDesignTest, PropertyGetPathEnd) {
|
|
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()) {
|
|
Properties &props = sta_->properties();
|
|
props.getProperty(ends[0], "slack");
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Property: getProperty on Path ---
|
|
|
|
TEST_F(StaDesignTest, PropertyGetPath) {
|
|
Vertex *v = findVertex("r1/Q");
|
|
ASSERT_NE(v, nullptr);
|
|
Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max());
|
|
if (path && !path->isNull()) {
|
|
Properties &props = sta_->properties();
|
|
props.getProperty(path, "arrival");
|
|
}
|
|
}
|
|
|
|
// --- Property: getProperty on TimingArcSet ---
|
|
|
|
TEST_F(StaDesignTest, PropertyGetTimingArcSet) {
|
|
Vertex *v = findVertex("u1/Z");
|
|
ASSERT_NE(v, nullptr);
|
|
VertexInEdgeIterator edge_iter(v, sta_->graph());
|
|
if (edge_iter.hasNext()) {
|
|
Edge *edge = edge_iter.next();
|
|
TimingArcSet *arc_set = edge->timingArcSet();
|
|
if (arc_set) {
|
|
Properties &props = sta_->properties();
|
|
try {
|
|
props.getProperty(arc_set, "from_pin");
|
|
} catch (...) {}
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Sta: setParasiticAnalysisPts per_corner ---
|
|
|
|
TEST_F(StaDesignTest, SetParasiticAnalysisPtsPerCorner) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
// setParasiticAnalysisPts removed
|
|
|
|
}() ));
|
|
}
|
|
|
|
// ============================================================
|
|
// R9_ tests: Comprehensive coverage for search module
|
|
// ============================================================
|
|
|
|
// --- FindRegister tests ---
|
|
|
|
TEST_F(StaDesignTest, FindRegisterInstances) {
|
|
ClockSet *clks = nullptr;
|
|
InstanceSet reg_insts = sta_->findRegisterInstances(clks, RiseFallBoth::riseFall(), true, false, sta_->cmdMode());
|
|
// Design has 3 DFF_X1 instances
|
|
EXPECT_GE(reg_insts.size(), 1u);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindRegisterDataPins) {
|
|
ClockSet *clks = nullptr;
|
|
PinSet data_pins = sta_->findRegisterDataPins(clks, RiseFallBoth::riseFall(), true, false, sta_->cmdMode());
|
|
EXPECT_GE(data_pins.size(), 1u);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindRegisterClkPins) {
|
|
ClockSet *clks = nullptr;
|
|
PinSet clk_pins = sta_->findRegisterClkPins(clks, RiseFallBoth::riseFall(), true, false, sta_->cmdMode());
|
|
|
|
EXPECT_GE(clk_pins.size(), 1u);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindRegisterAsyncPins) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
ClockSet *clks = nullptr;
|
|
sta_->findRegisterAsyncPins(clks, RiseFallBoth::riseFall(), true, false, sta_->cmdMode());
|
|
|
|
// May be empty if no async pins
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindRegisterOutputPins) {
|
|
ClockSet *clks = nullptr;
|
|
PinSet out_pins = sta_->findRegisterOutputPins(clks, RiseFallBoth::riseFall(), true, false, sta_->cmdMode());
|
|
EXPECT_GE(out_pins.size(), 1u);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindRegisterInstancesWithClock) {
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockSet *clks = new ClockSet;
|
|
clks->insert(clk);
|
|
InstanceSet reg_insts = sta_->findRegisterInstances(clks, RiseFallBoth::riseFall(), true, false, sta_->cmdMode());
|
|
EXPECT_GE(reg_insts.size(), 1u);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindRegisterDataPinsWithClock) {
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockSet *clks = new ClockSet;
|
|
clks->insert(clk);
|
|
PinSet data_pins = sta_->findRegisterDataPins(clks, RiseFallBoth::riseFall(), true, false, sta_->cmdMode());
|
|
EXPECT_GE(data_pins.size(), 1u);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindRegisterClkPinsWithClock) {
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockSet *clks = new ClockSet;
|
|
clks->insert(clk);
|
|
PinSet clk_pins = sta_->findRegisterClkPins(clks, RiseFallBoth::riseFall(), true, false, sta_->cmdMode());
|
|
EXPECT_GE(clk_pins.size(), 1u);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindRegisterOutputPinsWithClock) {
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockSet *clks = new ClockSet;
|
|
clks->insert(clk);
|
|
PinSet out_pins = sta_->findRegisterOutputPins(clks, RiseFallBoth::riseFall(), true, false, sta_->cmdMode());
|
|
|
|
EXPECT_GE(out_pins.size(), 1u);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindRegisterRiseOnly) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
ClockSet *clks = nullptr;
|
|
sta_->findRegisterClkPins(clks, RiseFallBoth::rise(), true, false, sta_->cmdMode());
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindRegisterFallOnly) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
ClockSet *clks = nullptr;
|
|
sta_->findRegisterClkPins(clks, RiseFallBoth::fall(), true, false, sta_->cmdMode());
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindRegisterLatches) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
ClockSet *clks = nullptr;
|
|
sta_->findRegisterInstances(clks, RiseFallBoth::riseFall(), false, true, sta_->cmdMode());
|
|
|
|
// No latches in this design
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindRegisterBothEdgeAndLatch) {
|
|
ClockSet *clks = nullptr;
|
|
InstanceSet insts = sta_->findRegisterInstances(clks, RiseFallBoth::riseFall(), true, true, sta_->cmdMode());
|
|
EXPECT_GE(insts.size(), 1u);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindRegisterAsyncPinsWithClock) {
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockSet *clks = new ClockSet;
|
|
clks->insert(clk);
|
|
sta_->findRegisterAsyncPins(clks, RiseFallBoth::riseFall(), true, false, sta_->cmdMode());
|
|
}
|
|
|
|
// --- PathEnd: detailed accessors ---
|
|
|
|
TEST_F(StaDesignTest, PathEndType) {
|
|
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);
|
|
for (const auto &end : ends) {
|
|
end->type();
|
|
const char *name = end->typeName();
|
|
EXPECT_NE(name, nullptr);
|
|
}
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndCheckRole) {
|
|
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);
|
|
for (const auto &end : ends) {
|
|
const TimingRole *role = end->checkRole(sta_);
|
|
EXPECT_NE(role, nullptr);
|
|
const TimingRole *generic_role = end->checkGenericRole(sta_);
|
|
EXPECT_NE(generic_role, nullptr);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndVertex) {
|
|
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);
|
|
for (const auto &end : ends) {
|
|
Vertex *v = end->vertex(sta_);
|
|
EXPECT_NE(v, nullptr);
|
|
}
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndMinMax) {
|
|
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);
|
|
for (const auto &end : ends) {
|
|
const MinMax *mm = end->minMax(sta_);
|
|
EXPECT_NE(mm, nullptr);
|
|
const EarlyLate *el = end->pathEarlyLate(sta_);
|
|
EXPECT_NE(el, nullptr);
|
|
}
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndTransition) {
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
for (const auto &end : ends) {
|
|
const RiseFall *rf = end->transition(sta_);
|
|
EXPECT_NE(rf, nullptr);
|
|
}
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndPathAnalysisPt) {
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
for (const auto &end : ends) {
|
|
// pathAnalysisPt removed from PathEnd; use path->pathIndex instead
|
|
size_t idx = end->path()->pathIndex(sta_);
|
|
EXPECT_GE(idx, 0u);
|
|
}
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndTargetClkAccessors) {
|
|
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);
|
|
for (const auto &end : ends) {
|
|
const Clock *tgt_clk = end->targetClk(sta_);
|
|
EXPECT_NE(tgt_clk, nullptr);
|
|
const ClockEdge *tgt_edge = end->targetClkEdge(sta_);
|
|
EXPECT_NE(tgt_edge, nullptr);
|
|
end->targetClkTime(sta_);
|
|
end->targetClkOffset(sta_);
|
|
end->targetClkArrival(sta_);
|
|
end->targetClkDelay(sta_);
|
|
end->targetClkInsertionDelay(sta_);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndTargetClkUncertainty) {
|
|
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);
|
|
for (const auto &end : ends) {
|
|
end->targetNonInterClkUncertainty(sta_);
|
|
end->interClkUncertainty(sta_);
|
|
end->targetClkUncertainty(sta_);
|
|
end->targetClkMcpAdjustment(sta_);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndClkEarlyLate) {
|
|
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);
|
|
for (const auto &end : ends) {
|
|
const EarlyLate *el = end->clkEarlyLate(sta_);
|
|
EXPECT_NE(el, nullptr);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndIsTypePredicates) {
|
|
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);
|
|
for (const auto &end : ends) {
|
|
bool is_check = end->isCheck();
|
|
bool is_uncon = end->isUnconstrained();
|
|
bool is_data = end->isDataCheck();
|
|
bool is_latch = end->isLatchCheck();
|
|
bool is_output = end->isOutputDelay();
|
|
bool is_gated = end->isGatedClock();
|
|
bool is_pd = end->isPathDelay();
|
|
// At least one should be true
|
|
bool any = is_check || is_uncon || is_data || is_latch
|
|
|| is_output || is_gated || is_pd;
|
|
EXPECT_TRUE(any);
|
|
}
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndCrpr) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
for (const auto &end : ends) {
|
|
end->crpr(sta_);
|
|
end->checkCrpr(sta_);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndClkSkew) {
|
|
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);
|
|
for (const auto &end : ends) {
|
|
end->clkSkew(sta_);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndBorrow) {
|
|
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);
|
|
for (const auto &end : ends) {
|
|
end->borrow(sta_);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndSourceClkInsertionDelay) {
|
|
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);
|
|
for (const auto &end : ends) {
|
|
end->sourceClkInsertionDelay(sta_);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndTargetClkPath) {
|
|
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);
|
|
for (const auto &end : ends) {
|
|
Path *tgt_clk = end->targetClkPath();
|
|
EXPECT_NE(tgt_clk, nullptr);
|
|
const Path *tgt_clk_const = const_cast<const PathEnd*>(end)->targetClkPath();
|
|
EXPECT_NE(tgt_clk_const, nullptr);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndTargetClkEndTrans) {
|
|
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);
|
|
for (const auto &end : ends) {
|
|
const RiseFall *rf = end->targetClkEndTrans(sta_);
|
|
EXPECT_NE(rf, nullptr);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndExceptPathCmp) {
|
|
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.size() >= 2) {
|
|
ends[0]->exceptPathCmp(ends[1], sta_);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndDataArrivalTimeOffset) {
|
|
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);
|
|
for (const auto &end : ends) {
|
|
end->dataArrivalTimeOffset(sta_);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndRequiredTimeOffset) {
|
|
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);
|
|
for (const auto &end : ends) {
|
|
end->requiredTimeOffset(sta_);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndMultiCyclePath) {
|
|
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);
|
|
for (const auto &end : ends) {
|
|
end->multiCyclePath();
|
|
end->pathDelay();
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndCmpNoCrpr) {
|
|
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.size() >= 2) {
|
|
PathEnd::cmpNoCrpr(ends[0], ends[1], sta_);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndLess2) {
|
|
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.size() >= 2) {
|
|
PathEnd::less(ends[0], ends[1], true, sta_);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PathEndMacroClkTreeDelay) {
|
|
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);
|
|
for (const auto &end : ends) {
|
|
end->macroClkTreeDelay(sta_);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- PathEnd: hold check ---
|
|
|
|
TEST_F(StaDesignTest, FindPathEndsHold2) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::min(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
false, true, false, false, false, false);
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindPathEndsHoldAccessors) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::min(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
false, true, false, false, false, false);
|
|
for (const auto &end : ends) {
|
|
end->slack(sta_);
|
|
end->requiredTime(sta_);
|
|
end->margin(sta_);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- PathEnd: unconstrained ---
|
|
|
|
TEST_F(StaDesignTest, FindPathEndsUnconstrained2) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
true, sta_->scenes(), MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
for (const auto &end : ends) {
|
|
if (end->isUnconstrained()) {
|
|
end->reportShort(sta_->reportPath());
|
|
|
|
end->requiredTime(sta_);
|
|
}
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- ReportPath: various report functions ---
|
|
|
|
TEST_F(StaDesignTest, ReportPathEndHeader) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathEndFooter) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathEnd2) {
|
|
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()) {
|
|
sta_->reportPathEnd(ends[0]);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathEnds2) {
|
|
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);
|
|
sta_->reportPathEnds(&ends);
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathEndFull) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathFormat(ReportPathFormat::full);
|
|
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()) {
|
|
sta_->reportPathEnd(ends[0]);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathEndFullClkPath) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathFormat(ReportPathFormat::full_clock);
|
|
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()) {
|
|
sta_->reportPathEnd(ends[0]);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathEndFullClkExpanded) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathFormat(ReportPathFormat::full_clock_expanded);
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
if (!ends.empty()) {
|
|
sta_->reportPathEnd(ends[0]);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathEndShortFormat) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathFormat(ReportPathFormat::shorter);
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
if (!ends.empty()) {
|
|
sta_->reportPathEnd(ends[0]);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathEndSummary) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathFormat(ReportPathFormat::summary);
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
if (!ends.empty()) {
|
|
sta_->reportPathEnd(ends[0]);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathEndSlackOnly) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathFormat(ReportPathFormat::slack_only);
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
if (!ends.empty()) {
|
|
sta_->reportPathEnd(ends[0]);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathEndJson) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathFormat(ReportPathFormat::json);
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
if (!ends.empty()) {
|
|
sta_->reportPathEnd(ends[0]);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathFromVertex) {
|
|
Vertex *v = findVertex("r1/Q");
|
|
ASSERT_NE(v, nullptr);
|
|
Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max());
|
|
if (path && !path->isNull()) {
|
|
sta_->reportPath(path);
|
|
}
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathFullWithPrevEnd) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
PathEndSeq ends = sta_->findPathEnds(
|
|
nullptr, nullptr, nullptr,
|
|
false, sta_->scenes(),
|
|
MinMaxAll::max(),
|
|
10, 1, false, false, -INF, INF, false, group_names,
|
|
true, false, false, false, false, false);
|
|
if (ends.size() >= 2) {
|
|
sta_->setReportPathFormat(ReportPathFormat::full);
|
|
sta_->reportPathEnd(ends[0]);
|
|
sta_->reportPathEnd(ends[1]);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathFieldOrder) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
StringSeq field_names;
|
|
field_names.push_back("fanout");
|
|
field_names.push_back("capacitance");
|
|
field_names.push_back("slew");
|
|
sta_->setReportPathFieldOrder(field_names);
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathFields) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathFields(true, true, true, true, true, true, true, true);
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathDigits) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathDigits(4);
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathNoSplit) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->setReportPathNoSplit(true);
|
|
|
|
}() ));
|
|
}
|
|
|
|
// ReportPathSigmas removed — API no longer exists
|
|
|
|
TEST_F(StaDesignTest, FindReportPathField2) {
|
|
ReportField *field = sta_->findReportPathField("fanout");
|
|
EXPECT_NE(field, nullptr);
|
|
field = sta_->findReportPathField("capacitance");
|
|
EXPECT_NE(field, nullptr);
|
|
field = sta_->findReportPathField("slew");
|
|
EXPECT_NE(field, nullptr);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportPathFieldAccessors) {
|
|
ReportPath *rpt = sta_->reportPath();
|
|
ReportField *slew = rpt->fieldSlew();
|
|
EXPECT_NE(slew, nullptr);
|
|
ReportField *fanout = rpt->fieldFanout();
|
|
EXPECT_NE(fanout, nullptr);
|
|
ReportField *cap = rpt->fieldCapacitance();
|
|
EXPECT_NE(cap, nullptr);
|
|
}
|
|
|
|
// --- ReportPath: MinPulseWidth check ---
|
|
|
|
TEST_F(StaDesignTest, MinPulseWidthSlack2) {
|
|
// minPulseWidthSlack removed; test reportMinPulseWidthChecks instead
|
|
sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes());
|
|
}
|
|
|
|
TEST_F(StaDesignTest, MinPulseWidthViolations2) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->reportMinPulseWidthChecks(nullptr, 10, true, false, sta_->scenes());
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, MinPulseWidthChecksAll2) {
|
|
// minPulseWidthChecks removed; test reportMinPulseWidthChecks
|
|
sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes());
|
|
}
|
|
|
|
TEST_F(StaDesignTest, MinPulseWidthCheckForPin) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Pin *pin = findPin("r1/CK");
|
|
if (pin) {
|
|
PinSeq pins;
|
|
pins.push_back(pin);
|
|
sta_->reportMinPulseWidthChecks(nullptr, 10, false, false, sta_->scenes());
|
|
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- ReportPath: MinPeriod ---
|
|
|
|
TEST_F(StaDesignTest, MinPeriodSlack2) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->reportMinPeriodChecks(nullptr, 10, false, false, sta_->scenes());
|
|
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, MinPeriodViolations2) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->reportMinPeriodChecks(nullptr, 10, true, false, sta_->scenes());
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, MinPeriodCheckVerbose) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
// minPeriodSlack removed
|
|
// check variable removed
|
|
// reportCheck removed
|
|
// reportCheck removed
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- ReportPath: MaxSkew ---
|
|
|
|
TEST_F(StaDesignTest, MaxSkewSlack2) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->reportMaxSkewChecks(nullptr, 10, false, false, sta_->scenes());
|
|
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, MaxSkewViolations2) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->reportMaxSkewChecks(nullptr, 10, true, false, sta_->scenes());
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, MaxSkewCheckVerbose) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
// maxSkewSlack removed
|
|
// check variable removed
|
|
// reportCheck removed
|
|
// reportCheck removed
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportMaxSkewHeaderShort) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
ReportPath *rpt = sta_->reportPath();
|
|
rpt->reportMaxSkewHeaderShort();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- ClkSkew / ClkLatency ---
|
|
|
|
TEST_F(StaDesignTest, ReportClkSkewSetup) {
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
ConstClockSeq clks;
|
|
clks.push_back(clk);
|
|
sta_->reportClkSkew(clks, sta_->scenes(), SetupHold::max(), false, 3);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportClkSkewHold) {
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
ConstClockSeq clks;
|
|
clks.push_back(clk);
|
|
sta_->reportClkSkew(clks, sta_->scenes(), SetupHold::min(), false, 3);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportClkSkewWithInternalLatency) {
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
ConstClockSeq clks;
|
|
clks.push_back(clk);
|
|
sta_->reportClkSkew(clks, sta_->scenes(), SetupHold::max(), true, 3);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindWorstClkSkew2) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
sta_->findWorstClkSkew(SetupHold::max(), false);
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportClkLatency2) {
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
ConstClockSeq clks;
|
|
clks.push_back(clk);
|
|
sta_->reportClkLatency(clks, sta_->scenes(), false, 3);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, ReportClkLatencyWithInternal) {
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
ConstClockSeq clks;
|
|
clks.push_back(clk);
|
|
sta_->reportClkLatency(clks, sta_->scenes(), true, 3);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindClkDelays2) {
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
sta_->findClkDelays(clk, sta_->cmdScene(), false);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindClkMinPeriod2) {
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
sta_->findClkMinPeriod(clk, false);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, FindClkMinPeriodWithPorts) {
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
sta_->findClkMinPeriod(clk, true);
|
|
}
|
|
|
|
// --- Property tests ---
|
|
|
|
TEST_F(StaDesignTest, PropertyGetLibrary) {
|
|
Network *network = sta_->cmdNetwork();
|
|
LibraryIterator *lib_iter = network->libraryIterator();
|
|
if (lib_iter->hasNext()) {
|
|
Library *lib = lib_iter->next();
|
|
Properties &props = sta_->properties();
|
|
PropertyValue pv = props.getProperty(lib, "name");
|
|
EXPECT_EQ(pv.type(), PropertyValue::Type::string);
|
|
}
|
|
delete lib_iter;
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PropertyGetCell) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Cell *cell = network->cell(top);
|
|
if (cell) {
|
|
Properties &props = sta_->properties();
|
|
PropertyValue pv = props.getProperty(cell, "name");
|
|
EXPECT_EQ(pv.type(), PropertyValue::Type::string);
|
|
}
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PropertyGetLibertyLibrary) {
|
|
Properties &props = sta_->properties();
|
|
PropertyValue pv = props.getProperty(lib_, "name");
|
|
EXPECT_EQ(pv.type(), PropertyValue::Type::string);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PropertyGetLibertyCell) {
|
|
LibertyCell *cell = lib_->findLibertyCell("DFF_X1");
|
|
ASSERT_NE(cell, nullptr);
|
|
Properties &props = sta_->properties();
|
|
PropertyValue pv = props.getProperty(cell, "name");
|
|
EXPECT_EQ(pv.type(), PropertyValue::Type::string);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PropertyGetLibertyPort2) {
|
|
LibertyCell *cell = lib_->findLibertyCell("DFF_X1");
|
|
ASSERT_NE(cell, nullptr);
|
|
LibertyPort *port = cell->findLibertyPort("D");
|
|
ASSERT_NE(port, nullptr);
|
|
Properties &props = sta_->properties();
|
|
PropertyValue pv = props.getProperty(port, "name");
|
|
EXPECT_EQ(pv.type(), PropertyValue::Type::string);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PropertyGetInstance) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
InstanceChildIterator *child_iter = network->childIterator(top);
|
|
if (child_iter->hasNext()) {
|
|
Instance *inst = child_iter->next();
|
|
Properties &props = sta_->properties();
|
|
PropertyValue pv = props.getProperty(inst, "name");
|
|
EXPECT_EQ(pv.type(), PropertyValue::Type::string);
|
|
}
|
|
delete child_iter;
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PropertyGetPin) {
|
|
Pin *pin = findPin("r1/Q");
|
|
ASSERT_NE(pin, nullptr);
|
|
Properties &props = sta_->properties();
|
|
PropertyValue pv = props.getProperty(pin, "name");
|
|
EXPECT_EQ(pv.type(), PropertyValue::Type::string);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PropertyGetPinDirection) {
|
|
Pin *pin = findPin("r1/Q");
|
|
ASSERT_NE(pin, nullptr);
|
|
Properties &props = sta_->properties();
|
|
PropertyValue pv = props.getProperty(pin, "direction");
|
|
EXPECT_EQ(pv.type(), PropertyValue::Type::string);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PropertyGetNet) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Pin *pin = findPin("r1/Q");
|
|
ASSERT_NE(pin, nullptr);
|
|
Net *net = network->net(pin);
|
|
if (net) {
|
|
Properties &props = sta_->properties();
|
|
PropertyValue pv = props.getProperty(net, "name");
|
|
EXPECT_EQ(pv.type(), PropertyValue::Type::string);
|
|
}
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PropertyGetClock2) {
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
Properties &props = sta_->properties();
|
|
PropertyValue pv = props.getProperty(clk, "name");
|
|
EXPECT_EQ(pv.type(), PropertyValue::Type::string);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PropertyGetClockPeriod) {
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
Properties &props = sta_->properties();
|
|
PropertyValue pv = props.getProperty(clk, "period");
|
|
EXPECT_EQ(pv.type(), PropertyValue::Type::float_);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PropertyGetPort2) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Cell *cell = network->cell(top);
|
|
CellPortIterator *port_iter = network->portIterator(cell);
|
|
if (port_iter->hasNext()) {
|
|
Port *port = port_iter->next();
|
|
Properties &props = sta_->properties();
|
|
PropertyValue pv = props.getProperty(port, "name");
|
|
EXPECT_EQ(pv.type(), PropertyValue::Type::string);
|
|
}
|
|
delete port_iter;
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PropertyGetEdge2) {
|
|
Vertex *v = findVertex("u1/Z");
|
|
ASSERT_NE(v, nullptr);
|
|
VertexInEdgeIterator edge_iter(v, sta_->graph());
|
|
if (edge_iter.hasNext()) {
|
|
Edge *edge = edge_iter.next();
|
|
Properties &props = sta_->properties();
|
|
props.getProperty(edge, "from_pin");
|
|
}
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PropertyGetPathEndSlack) {
|
|
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()) {
|
|
Properties &props = sta_->properties();
|
|
props.getProperty(ends[0], "startpoint");
|
|
props.getProperty(ends[0], "endpoint");
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PropertyGetPathEndMore) {
|
|
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()) {
|
|
Properties &props = sta_->properties();
|
|
props.getProperty(ends[0], "startpoint_clock");
|
|
props.getProperty(ends[0], "endpoint_clock");
|
|
props.getProperty(ends[0], "points");
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
// --- Property: pin arrival/slack ---
|
|
|
|
TEST_F(StaDesignTest, PinArrival2) {
|
|
Pin *pin = findPin("r1/Q");
|
|
ASSERT_NE(pin, nullptr);
|
|
sta_->arrival(pin, RiseFallBoth::rise(), MinMax::max());
|
|
}
|
|
|
|
TEST_F(StaDesignTest, PinSlack) {
|
|
Pin *pin = findPin("r3/D");
|
|
ASSERT_NE(pin, nullptr);
|
|
sta_->slack(pin, RiseFallBoth::riseFall(), sta_->scenes(), MinMax::max());
|
|
sta_->slack(pin, RiseFallBoth::rise(), sta_->scenes(), MinMax::max());
|
|
}
|
|
|
|
TEST_F(StaDesignTest, NetSlack2) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Pin *pin = findPin("r3/D");
|
|
ASSERT_NE(pin, nullptr);
|
|
Net *net = network->net(pin);
|
|
if (net) {
|
|
sta_->slack(net, MinMax::max());
|
|
}
|
|
}
|
|
|
|
// --- Search: various methods ---
|
|
|
|
TEST_F(StaDesignTest, SearchIsClock) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
Vertex *v = findVertex("r1/CK");
|
|
if (v) {
|
|
(void)(search->clocks(v, sta_->cmdMode()).size() > 0);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchIsGenClkSrc2) {
|
|
Search *search = sta_->search();
|
|
(void)search;
|
|
Vertex *v = findVertex("r1/Q");
|
|
ASSERT_NE(v, nullptr);
|
|
(void)true /* Search::isGenClkSrc removed */;
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchClocks) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
Vertex *v = findVertex("r1/CK");
|
|
if (v) {
|
|
search->clocks(v, sta_->cmdMode());
|
|
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchClockDomains) {
|
|
Search *search = sta_->search();
|
|
Vertex *v = findVertex("r1/Q");
|
|
ASSERT_NE(v, nullptr);
|
|
search->clockDomains(v, sta_->cmdMode());
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchClockDomainsPin) {
|
|
Search *search = sta_->search();
|
|
Pin *pin = findPin("r1/Q");
|
|
ASSERT_NE(pin, nullptr);
|
|
search->clockDomains(pin, sta_->cmdMode());
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchClocksPin) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
Pin *pin = findPin("r1/CK");
|
|
if (pin) {
|
|
search->clocks(pin, sta_->cmdMode());
|
|
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchIsEndpoint2) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
Vertex *v_data = findVertex("r3/D");
|
|
if (v_data) {
|
|
EXPECT_TRUE(search->isEndpoint(v_data));
|
|
}
|
|
Vertex *v_out = findVertex("r1/Q");
|
|
if (v_out) {
|
|
EXPECT_FALSE(search->isEndpoint(v_out));
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchHavePathGroups) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
(void)search;
|
|
(void)true /* Search::havePathGroups removed */;
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchFindPathGroup) {
|
|
Search *search = sta_->search();
|
|
(void)search;
|
|
Clock *clk = sta_->cmdSdc()->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
// Search::findPathGroup removed
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchClkInfoCount) {
|
|
Search *search = sta_->search();
|
|
int count = search->clkInfoCount();
|
|
EXPECT_GE(count, 0);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchTagGroupCount) {
|
|
Search *search = sta_->search();
|
|
TagGroupIndex count = search->tagGroupCount();
|
|
EXPECT_GE(count, 0u);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchTagGroupByIndex) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
TagGroupIndex count = search->tagGroupCount();
|
|
if (count > 0) {
|
|
TagGroup *tg = search->tagGroup(0);
|
|
EXPECT_NE(tg, nullptr);
|
|
}
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchReportTagGroups2) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
search->reportTagGroups();
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchReportArrivals2) {
|
|
Search *search = sta_->search();
|
|
Vertex *v = findVertex("r1/Q");
|
|
ASSERT_NE(v, nullptr);
|
|
search->reportArrivals(v, false);
|
|
search->reportArrivals(v, true);
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchSeedArrival) {
|
|
// seedArrival(Vertex*) removed; seedArrivals() is now protected.
|
|
// Exercise search through Sta::arrival instead.
|
|
Vertex *v = findVertex("in1");
|
|
if (v) {
|
|
sta_->arrival(v, RiseFallBoth::rise(), sta_->scenes(), MinMax::max());
|
|
}
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchPathClkPathArrival2) {
|
|
Search *search = sta_->search();
|
|
Vertex *v = findVertex("r1/Q");
|
|
ASSERT_NE(v, nullptr);
|
|
Path *path = sta_->vertexWorstArrivalPath(v, MinMax::max());
|
|
if (path && !path->isNull()) {
|
|
search->pathClkPathArrival(path);
|
|
}
|
|
}
|
|
|
|
TEST_F(StaDesignTest, SearchFindClkArrivals) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Search *search = sta_->search();
|
|
search->findClkArrivals();
|
|
|
|
}() ));
|
|
}
|
|
|
|
} // namespace sta
|