10328 lines
334 KiB
C++
10328 lines
334 KiB
C++
#include <gtest/gtest.h>
|
|
#include <tcl.h>
|
|
#include "Transition.hh"
|
|
#include "MinMax.hh"
|
|
#include "ExceptionPath.hh"
|
|
#include "TimingRole.hh"
|
|
#include "Clock.hh"
|
|
#include "RiseFallMinMax.hh"
|
|
#include "CycleAccting.hh"
|
|
#include "SdcCmdComment.hh"
|
|
#include "Variables.hh"
|
|
#include "DeratingFactors.hh"
|
|
#include "ClockLatency.hh"
|
|
#include "ClockInsertion.hh"
|
|
#include "ClockGatingCheck.hh"
|
|
#include "PortExtCap.hh"
|
|
#include "DataCheck.hh"
|
|
#include "PinPair.hh"
|
|
#include "Sta.hh"
|
|
#include "Sdc.hh"
|
|
#include "ReportTcl.hh"
|
|
#include "Corner.hh"
|
|
#include "DisabledPorts.hh"
|
|
#include "InputDrive.hh"
|
|
#include "PatternMatch.hh"
|
|
#include "Network.hh"
|
|
#include "Liberty.hh"
|
|
#include "TimingArc.hh"
|
|
#include "Graph.hh"
|
|
#include "PortDelay.hh"
|
|
#include "PortDirection.hh"
|
|
|
|
namespace sta {
|
|
|
|
// RiseFall tests
|
|
class RiseFallTest : public ::testing::Test {};
|
|
|
|
TEST_F(RiseFallTest, Singletons) {
|
|
EXPECT_NE(RiseFall::rise(), nullptr);
|
|
EXPECT_NE(RiseFall::fall(), nullptr);
|
|
EXPECT_NE(RiseFall::rise(), RiseFall::fall());
|
|
}
|
|
|
|
TEST_F(RiseFallTest, Names) {
|
|
// to_string() returns short_name: "^" for rise, "v" for fall
|
|
EXPECT_EQ(RiseFall::rise()->to_string(), "^");
|
|
EXPECT_EQ(RiseFall::fall()->to_string(), "v");
|
|
}
|
|
|
|
TEST_F(RiseFallTest, Indices) {
|
|
EXPECT_EQ(RiseFall::riseIndex(), RiseFall::rise()->index());
|
|
EXPECT_EQ(RiseFall::fallIndex(), RiseFall::fall()->index());
|
|
EXPECT_NE(RiseFall::riseIndex(), RiseFall::fallIndex());
|
|
}
|
|
|
|
TEST_F(RiseFallTest, Opposite) {
|
|
EXPECT_EQ(RiseFall::rise()->opposite(), RiseFall::fall());
|
|
EXPECT_EQ(RiseFall::fall()->opposite(), RiseFall::rise());
|
|
}
|
|
|
|
TEST_F(RiseFallTest, Find) {
|
|
EXPECT_EQ(RiseFall::find("rise"), RiseFall::rise());
|
|
EXPECT_EQ(RiseFall::find("fall"), RiseFall::fall());
|
|
}
|
|
|
|
TEST_F(RiseFallTest, Range) {
|
|
auto &range = RiseFall::range();
|
|
EXPECT_EQ(range.size(), 2u);
|
|
}
|
|
|
|
// RiseFallBoth tests
|
|
class RiseFallBothTest : public ::testing::Test {};
|
|
|
|
TEST_F(RiseFallBothTest, Singletons) {
|
|
EXPECT_NE(RiseFallBoth::rise(), nullptr);
|
|
EXPECT_NE(RiseFallBoth::fall(), nullptr);
|
|
EXPECT_NE(RiseFallBoth::riseFall(), nullptr);
|
|
}
|
|
|
|
TEST_F(RiseFallBothTest, Matches) {
|
|
EXPECT_TRUE(RiseFallBoth::rise()->matches(RiseFall::rise()));
|
|
EXPECT_FALSE(RiseFallBoth::rise()->matches(RiseFall::fall()));
|
|
EXPECT_TRUE(RiseFallBoth::riseFall()->matches(RiseFall::rise()));
|
|
EXPECT_TRUE(RiseFallBoth::riseFall()->matches(RiseFall::fall()));
|
|
}
|
|
|
|
// Transition tests
|
|
class TransitionTest : public ::testing::Test {};
|
|
|
|
TEST_F(TransitionTest, Singletons) {
|
|
EXPECT_NE(Transition::rise(), nullptr);
|
|
EXPECT_NE(Transition::fall(), nullptr);
|
|
EXPECT_NE(Transition::tr0Z(), nullptr);
|
|
EXPECT_NE(Transition::trZ1(), nullptr);
|
|
}
|
|
|
|
TEST_F(TransitionTest, Find) {
|
|
// Transition names in the map are "^"/"01" for rise, "v"/"10" for fall
|
|
EXPECT_EQ(Transition::find("^"), Transition::rise());
|
|
EXPECT_EQ(Transition::find("v"), Transition::fall());
|
|
EXPECT_EQ(Transition::find("01"), Transition::rise());
|
|
EXPECT_EQ(Transition::find("10"), Transition::fall());
|
|
}
|
|
|
|
TEST_F(TransitionTest, AsRiseFall) {
|
|
EXPECT_EQ(Transition::rise()->asRiseFall(), RiseFall::rise());
|
|
EXPECT_EQ(Transition::fall()->asRiseFall(), RiseFall::fall());
|
|
}
|
|
|
|
TEST_F(TransitionTest, Matches) {
|
|
EXPECT_TRUE(Transition::rise()->matches(Transition::rise()));
|
|
EXPECT_FALSE(Transition::rise()->matches(Transition::fall()));
|
|
}
|
|
|
|
// MinMax tests
|
|
class MinMaxTest : public ::testing::Test {};
|
|
|
|
TEST_F(MinMaxTest, Singletons) {
|
|
EXPECT_NE(MinMax::min(), nullptr);
|
|
EXPECT_NE(MinMax::max(), nullptr);
|
|
EXPECT_NE(MinMax::min(), MinMax::max());
|
|
}
|
|
|
|
TEST_F(MinMaxTest, Names) {
|
|
EXPECT_EQ(MinMax::min()->to_string(), "min");
|
|
EXPECT_EQ(MinMax::max()->to_string(), "max");
|
|
}
|
|
|
|
TEST_F(MinMaxTest, Indices) {
|
|
EXPECT_EQ(MinMax::minIndex(), MinMax::min()->index());
|
|
EXPECT_EQ(MinMax::maxIndex(), MinMax::max()->index());
|
|
}
|
|
|
|
TEST_F(MinMaxTest, Compare) {
|
|
// min: value1 < value2 is true
|
|
EXPECT_TRUE(MinMax::min()->compare(1.0f, 2.0f));
|
|
EXPECT_FALSE(MinMax::min()->compare(2.0f, 1.0f));
|
|
// max: value1 > value2 is true
|
|
EXPECT_TRUE(MinMax::max()->compare(2.0f, 1.0f));
|
|
EXPECT_FALSE(MinMax::max()->compare(1.0f, 2.0f));
|
|
}
|
|
|
|
TEST_F(MinMaxTest, MinMaxFunc) {
|
|
EXPECT_FLOAT_EQ(MinMax::min()->minMax(3.0f, 5.0f), 3.0f);
|
|
EXPECT_FLOAT_EQ(MinMax::max()->minMax(3.0f, 5.0f), 5.0f);
|
|
}
|
|
|
|
TEST_F(MinMaxTest, Opposite) {
|
|
EXPECT_EQ(MinMax::min()->opposite(), MinMax::max());
|
|
EXPECT_EQ(MinMax::max()->opposite(), MinMax::min());
|
|
}
|
|
|
|
TEST_F(MinMaxTest, Find) {
|
|
EXPECT_EQ(MinMax::find("min"), MinMax::min());
|
|
EXPECT_EQ(MinMax::find("max"), MinMax::max());
|
|
EXPECT_EQ(MinMax::find(MinMax::minIndex()), MinMax::min());
|
|
}
|
|
|
|
TEST_F(MinMaxTest, InitValue) {
|
|
// min init value should be large positive
|
|
EXPECT_GT(MinMax::min()->initValue(), 0.0f);
|
|
// max init value should be large negative
|
|
EXPECT_LT(MinMax::max()->initValue(), 0.0f);
|
|
}
|
|
|
|
// MinMaxAll tests
|
|
class MinMaxAllTest : public ::testing::Test {};
|
|
|
|
TEST_F(MinMaxAllTest, Singletons) {
|
|
EXPECT_NE(MinMaxAll::min(), nullptr);
|
|
EXPECT_NE(MinMaxAll::max(), nullptr);
|
|
EXPECT_NE(MinMaxAll::all(), nullptr);
|
|
}
|
|
|
|
TEST_F(MinMaxAllTest, Matches) {
|
|
EXPECT_TRUE(MinMaxAll::min()->matches(MinMax::min()));
|
|
EXPECT_FALSE(MinMaxAll::min()->matches(MinMax::max()));
|
|
EXPECT_TRUE(MinMaxAll::all()->matches(MinMax::min()));
|
|
EXPECT_TRUE(MinMaxAll::all()->matches(MinMax::max()));
|
|
}
|
|
|
|
TEST_F(MinMaxAllTest, Find) {
|
|
EXPECT_EQ(MinMaxAll::find("min"), MinMaxAll::min());
|
|
EXPECT_EQ(MinMaxAll::find("max"), MinMaxAll::max());
|
|
EXPECT_EQ(MinMaxAll::find("all"), MinMaxAll::all());
|
|
}
|
|
|
|
TEST_F(MinMaxAllTest, Range) {
|
|
// "all" should have both min and max in its range
|
|
auto &range = MinMaxAll::all()->range();
|
|
EXPECT_EQ(range.size(), 2u);
|
|
}
|
|
|
|
TEST_F(MinMaxAllTest, AsMinMax) {
|
|
EXPECT_EQ(MinMaxAll::min()->asMinMax(), MinMax::min());
|
|
EXPECT_EQ(MinMaxAll::max()->asMinMax(), MinMax::max());
|
|
}
|
|
|
|
TEST_F(MinMaxAllTest, Index) {
|
|
EXPECT_EQ(MinMaxAll::min()->index(), MinMax::min()->index());
|
|
EXPECT_EQ(MinMaxAll::max()->index(), MinMax::max()->index());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// ExceptionPath tests for SDC coverage
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
class SdcExceptionPathTest : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override {
|
|
initSta();
|
|
}
|
|
};
|
|
|
|
// FalsePath with min_max variations
|
|
TEST_F(SdcExceptionPathTest, FalsePathMinMaxMin) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::min(), true, nullptr);
|
|
EXPECT_TRUE(fp.matches(MinMax::min(), false));
|
|
EXPECT_FALSE(fp.matches(MinMax::max(), false));
|
|
}
|
|
|
|
TEST_F(SdcExceptionPathTest, FalsePathMinMaxMax) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::max(), true, nullptr);
|
|
EXPECT_FALSE(fp.matches(MinMax::min(), false));
|
|
EXPECT_TRUE(fp.matches(MinMax::max(), false));
|
|
}
|
|
|
|
// FalsePath with comment
|
|
TEST_F(SdcExceptionPathTest, FalsePathWithComment) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, "test comment");
|
|
EXPECT_STREQ(fp.comment(), "test comment");
|
|
}
|
|
|
|
// FalsePath priority constructor
|
|
TEST_F(SdcExceptionPathTest, FalsePathWithPriority) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, 1234, nullptr);
|
|
EXPECT_EQ(fp.priority(), 1234);
|
|
}
|
|
|
|
// PathDelay with comment
|
|
TEST_F(SdcExceptionPathTest, PathDelayWithComment) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
1.0e-9f, true, "path delay comment");
|
|
EXPECT_STREQ(pd.comment(), "path delay comment");
|
|
}
|
|
|
|
// MultiCyclePath with comment
|
|
TEST_F(SdcExceptionPathTest, MultiCyclePathWithComment) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
false, 2, true, "mcp comment");
|
|
EXPECT_STREQ(mcp.comment(), "mcp comment");
|
|
EXPECT_FALSE(mcp.useEndClk());
|
|
}
|
|
|
|
// GroupPath with comment
|
|
TEST_F(SdcExceptionPathTest, GroupPathWithComment) {
|
|
GroupPath gp("gp", false, nullptr, nullptr, nullptr, true, "gp comment");
|
|
EXPECT_STREQ(gp.comment(), "gp comment");
|
|
}
|
|
|
|
// GroupPath overrides
|
|
TEST_F(SdcExceptionPathTest, GroupPathOverridesSameNameDefault) {
|
|
GroupPath gp1("reg", true, nullptr, nullptr, nullptr, true, nullptr);
|
|
GroupPath gp2("reg", true, nullptr, nullptr, nullptr, true, nullptr);
|
|
EXPECT_TRUE(gp1.overrides(&gp2));
|
|
}
|
|
|
|
TEST_F(SdcExceptionPathTest, GroupPathNotOverridesDifferentName) {
|
|
GroupPath gp1("reg1", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
GroupPath gp2("reg2", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
EXPECT_FALSE(gp1.overrides(&gp2));
|
|
}
|
|
|
|
TEST_F(SdcExceptionPathTest, GroupPathNotOverridesDifferentType) {
|
|
GroupPath gp("gp", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
EXPECT_FALSE(gp.overrides(&fp));
|
|
}
|
|
|
|
// GroupPath mergeable
|
|
TEST_F(SdcExceptionPathTest, GroupPathMergeableSameName) {
|
|
GroupPath gp1("grp", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
GroupPath gp2("grp", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
EXPECT_TRUE(gp1.mergeable(&gp2));
|
|
}
|
|
|
|
TEST_F(SdcExceptionPathTest, GroupPathNotMergeableDifferentName) {
|
|
GroupPath gp1("grp1", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
GroupPath gp2("grp2", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
EXPECT_FALSE(gp1.mergeable(&gp2));
|
|
}
|
|
|
|
// PathDelay overrides
|
|
TEST_F(SdcExceptionPathTest, PathDelayOverridesPathDelay) {
|
|
PathDelay pd1(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
5.0e-9f, true, nullptr);
|
|
PathDelay pd2(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
10.0e-9f, true, nullptr);
|
|
EXPECT_TRUE(pd1.overrides(&pd2));
|
|
}
|
|
|
|
TEST_F(SdcExceptionPathTest, PathDelayNotOverridesFalsePath) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
5.0e-9f, true, nullptr);
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
EXPECT_FALSE(pd.overrides(&fp));
|
|
}
|
|
|
|
// PathDelay mergeable
|
|
TEST_F(SdcExceptionPathTest, PathDelayMergeableSame) {
|
|
PathDelay pd1(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
5.0e-9f, true, nullptr);
|
|
PathDelay pd2(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
5.0e-9f, true, nullptr);
|
|
EXPECT_TRUE(pd1.mergeable(&pd2));
|
|
}
|
|
|
|
TEST_F(SdcExceptionPathTest, PathDelayNotMergeableDifferentDelay) {
|
|
PathDelay pd1(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
5.0e-9f, true, nullptr);
|
|
PathDelay pd2(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
10.0e-9f, true, nullptr);
|
|
EXPECT_FALSE(pd1.mergeable(&pd2));
|
|
}
|
|
|
|
TEST_F(SdcExceptionPathTest, PathDelayNotMergeableDifferentIgnoreLatency) {
|
|
PathDelay pd1(nullptr, nullptr, nullptr, MinMax::max(), true, false,
|
|
5.0e-9f, true, nullptr);
|
|
PathDelay pd2(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
5.0e-9f, true, nullptr);
|
|
EXPECT_FALSE(pd1.mergeable(&pd2));
|
|
}
|
|
|
|
// MultiCyclePath overrides
|
|
TEST_F(SdcExceptionPathTest, MultiCyclePathOverrides) {
|
|
MultiCyclePath mcp1(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, nullptr);
|
|
MultiCyclePath mcp2(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, nullptr);
|
|
EXPECT_TRUE(mcp1.overrides(&mcp2));
|
|
}
|
|
|
|
TEST_F(SdcExceptionPathTest, MultiCyclePathNotOverridesFalsePath) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, nullptr);
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
EXPECT_FALSE(mcp.overrides(&fp));
|
|
}
|
|
|
|
// MultiCyclePath mergeable
|
|
TEST_F(SdcExceptionPathTest, MultiCyclePathMergeable) {
|
|
MultiCyclePath mcp1(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, nullptr);
|
|
MultiCyclePath mcp2(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, nullptr);
|
|
EXPECT_TRUE(mcp1.mergeable(&mcp2));
|
|
}
|
|
|
|
TEST_F(SdcExceptionPathTest, MultiCyclePathNotMergeableDifferentMultiplier) {
|
|
MultiCyclePath mcp1(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, nullptr);
|
|
MultiCyclePath mcp2(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 5, true, nullptr);
|
|
EXPECT_FALSE(mcp1.mergeable(&mcp2));
|
|
}
|
|
|
|
// FalsePath overrides
|
|
TEST_F(SdcExceptionPathTest, FalsePathOverrides) {
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
EXPECT_TRUE(fp1.overrides(&fp2));
|
|
}
|
|
|
|
TEST_F(SdcExceptionPathTest, FalsePathNotOverridesDifferentMinMax) {
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::min(), true, nullptr);
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::max(), true, nullptr);
|
|
EXPECT_FALSE(fp1.overrides(&fp2));
|
|
}
|
|
|
|
// ExceptionPath hash
|
|
TEST_F(SdcExceptionPathTest, DifferentTypeDifferentHash) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
FilterPath flp(nullptr, nullptr, nullptr, true);
|
|
// Different type priorities generally produce different hashes
|
|
// (but not guaranteed - just verify the function works)
|
|
size_t h1 = fp.hash();
|
|
size_t h2 = flp.hash();
|
|
// Just verify both are valid; may or may not be different
|
|
EXPECT_GE(h1, 0u);
|
|
EXPECT_GE(h2, 0u);
|
|
}
|
|
|
|
// ExceptionPath fromThruToPriority
|
|
TEST_F(SdcExceptionPathTest, FromThruToPriorityNone) {
|
|
EXPECT_EQ(ExceptionPath::fromThruToPriority(nullptr, nullptr, nullptr), 0);
|
|
}
|
|
|
|
// ExceptionState tests
|
|
TEST_F(SdcExceptionPathTest, StateComplete) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
ExceptionState *state = fp.firstState();
|
|
EXPECT_NE(state, nullptr);
|
|
EXPECT_TRUE(state->isComplete());
|
|
EXPECT_EQ(state->nextThru(), nullptr);
|
|
EXPECT_EQ(state->nextState(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcExceptionPathTest, StateSetNextState) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
ExceptionState *state = fp.firstState();
|
|
// Verify default next state is null
|
|
EXPECT_EQ(state->nextState(), nullptr);
|
|
}
|
|
|
|
// ExceptionStateLess
|
|
TEST_F(SdcExceptionPathTest, StateLessComparison) {
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
fp1.setId(10);
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
fp2.setId(20);
|
|
|
|
ExceptionState *s1 = fp1.firstState();
|
|
ExceptionState *s2 = fp2.firstState();
|
|
|
|
ExceptionStateLess less;
|
|
EXPECT_TRUE(less(s1, s2));
|
|
EXPECT_FALSE(less(s2, s1));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// CycleAccting comparator tests
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
class CycleAcctingTest : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override {
|
|
initSta();
|
|
}
|
|
};
|
|
|
|
TEST_F(CycleAcctingTest, CycleAcctingHashAndEqual) {
|
|
// Test the hash and equal functors with placeholder data
|
|
CycleAcctingHash hasher;
|
|
CycleAcctingEqual equal;
|
|
// These work on CycleAccting pointers but we can verify the functors exist
|
|
// by testing that they compile and are callable
|
|
EXPECT_TRUE(true); // Compilation test
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// InterClockUncertainty tests
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
class InterClockUncertaintyTest : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override {
|
|
initSta();
|
|
}
|
|
};
|
|
|
|
TEST_F(InterClockUncertaintyTest, ConstructAndEmpty) {
|
|
InterClockUncertainty icu(nullptr, nullptr);
|
|
EXPECT_EQ(icu.src(), nullptr);
|
|
EXPECT_EQ(icu.target(), nullptr);
|
|
EXPECT_TRUE(icu.empty());
|
|
}
|
|
|
|
TEST_F(InterClockUncertaintyTest, SetAndGetUncertainty) {
|
|
InterClockUncertainty icu(nullptr, nullptr);
|
|
icu.setUncertainty(RiseFallBoth::riseFall(), RiseFallBoth::riseFall(),
|
|
SetupHoldAll::all(), 0.5f);
|
|
EXPECT_FALSE(icu.empty());
|
|
|
|
float unc;
|
|
bool exists;
|
|
icu.uncertainty(RiseFall::rise(), RiseFall::rise(), SetupHold::min(),
|
|
unc, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(unc, 0.5f);
|
|
|
|
icu.uncertainty(RiseFall::fall(), RiseFall::fall(), SetupHold::max(),
|
|
unc, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(unc, 0.5f);
|
|
}
|
|
|
|
TEST_F(InterClockUncertaintyTest, SetSpecificTransitions) {
|
|
InterClockUncertainty icu(nullptr, nullptr);
|
|
icu.setUncertainty(RiseFallBoth::rise(), RiseFallBoth::fall(),
|
|
SetupHoldAll::min(), 0.3f);
|
|
EXPECT_FALSE(icu.empty());
|
|
|
|
float unc;
|
|
bool exists;
|
|
icu.uncertainty(RiseFall::rise(), RiseFall::fall(), SetupHold::min(),
|
|
unc, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(unc, 0.3f);
|
|
|
|
// Other combinations should not exist
|
|
icu.uncertainty(RiseFall::fall(), RiseFall::rise(), SetupHold::min(),
|
|
unc, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
TEST_F(InterClockUncertaintyTest, RemoveUncertainty) {
|
|
InterClockUncertainty icu(nullptr, nullptr);
|
|
icu.setUncertainty(RiseFallBoth::riseFall(), RiseFallBoth::riseFall(),
|
|
SetupHoldAll::all(), 0.5f);
|
|
EXPECT_FALSE(icu.empty());
|
|
|
|
icu.removeUncertainty(RiseFallBoth::riseFall(), RiseFallBoth::riseFall(),
|
|
SetupHoldAll::all());
|
|
EXPECT_TRUE(icu.empty());
|
|
}
|
|
|
|
TEST_F(InterClockUncertaintyTest, Uncertainties) {
|
|
InterClockUncertainty icu(nullptr, nullptr);
|
|
icu.setUncertainty(RiseFallBoth::rise(), RiseFallBoth::riseFall(),
|
|
SetupHoldAll::min(), 0.2f);
|
|
const RiseFallMinMax *rfmm = icu.uncertainties(RiseFall::rise());
|
|
EXPECT_NE(rfmm, nullptr);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// ClockNameLess tests
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
class ClockCmpTest : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override {
|
|
initSta();
|
|
}
|
|
};
|
|
|
|
// Just test that the comparator class can be instantiated
|
|
// (actual Clock objects require Sdc which requires full setup)
|
|
TEST_F(ClockCmpTest, ClkNameLessInstantiation) {
|
|
ClkNameLess less;
|
|
// Just verify it compiles
|
|
EXPECT_TRUE(true);
|
|
}
|
|
|
|
TEST_F(ClockCmpTest, ClockNameLessInstantiation) {
|
|
ClockNameLess less;
|
|
EXPECT_TRUE(true);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// ExceptionPath priority ordering
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
class ExceptionPriorityTest : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override {
|
|
initSta();
|
|
}
|
|
};
|
|
|
|
TEST_F(ExceptionPriorityTest, PriorityOrdering) {
|
|
// FalsePath > PathDelay > MultiCyclePath > FilterPath > GroupPath
|
|
EXPECT_GT(ExceptionPath::falsePathPriority(), ExceptionPath::pathDelayPriority());
|
|
EXPECT_GT(ExceptionPath::pathDelayPriority(), ExceptionPath::multiCyclePathPriority());
|
|
EXPECT_GT(ExceptionPath::multiCyclePathPriority(), ExceptionPath::filterPathPriority());
|
|
EXPECT_GT(ExceptionPath::filterPathPriority(), ExceptionPath::groupPathPriority());
|
|
EXPECT_EQ(ExceptionPath::groupPathPriority(), 0);
|
|
}
|
|
|
|
TEST_F(ExceptionPriorityTest, SpecificValues) {
|
|
EXPECT_EQ(ExceptionPath::falsePathPriority(), 4000);
|
|
EXPECT_EQ(ExceptionPath::pathDelayPriority(), 3000);
|
|
EXPECT_EQ(ExceptionPath::multiCyclePathPriority(), 2000);
|
|
EXPECT_EQ(ExceptionPath::filterPathPriority(), 1000);
|
|
EXPECT_EQ(ExceptionPath::groupPathPriority(), 0);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// Additional MinMaxAll tests for SDC coverage
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
class SdcMinMaxAllTest : public ::testing::Test {};
|
|
|
|
TEST_F(SdcMinMaxAllTest, MinAsMinMax) {
|
|
EXPECT_EQ(MinMaxAll::min()->asMinMax(), MinMax::min());
|
|
}
|
|
|
|
TEST_F(SdcMinMaxAllTest, MaxAsMinMax) {
|
|
EXPECT_EQ(MinMaxAll::max()->asMinMax(), MinMax::max());
|
|
}
|
|
|
|
TEST_F(SdcMinMaxAllTest, MinRange) {
|
|
auto &range = MinMaxAll::min()->range();
|
|
EXPECT_EQ(range.size(), 1u);
|
|
EXPECT_EQ(range[0], MinMax::min());
|
|
}
|
|
|
|
TEST_F(SdcMinMaxAllTest, MaxRange) {
|
|
auto &range = MinMaxAll::max()->range();
|
|
EXPECT_EQ(range.size(), 1u);
|
|
EXPECT_EQ(range[0], MinMax::max());
|
|
}
|
|
|
|
TEST_F(SdcMinMaxAllTest, MatchesSelf) {
|
|
EXPECT_TRUE(MinMaxAll::min()->matches(MinMaxAll::min()));
|
|
EXPECT_TRUE(MinMaxAll::max()->matches(MinMaxAll::max()));
|
|
EXPECT_TRUE(MinMaxAll::all()->matches(MinMaxAll::all()));
|
|
}
|
|
|
|
TEST_F(SdcMinMaxAllTest, AllMatchesEverything) {
|
|
EXPECT_TRUE(MinMaxAll::all()->matches(MinMaxAll::min()));
|
|
EXPECT_TRUE(MinMaxAll::all()->matches(MinMaxAll::max()));
|
|
EXPECT_TRUE(MinMaxAll::all()->matches(MinMax::min()));
|
|
EXPECT_TRUE(MinMaxAll::all()->matches(MinMax::max()));
|
|
}
|
|
|
|
TEST_F(SdcMinMaxAllTest, MinNotMatchesMax) {
|
|
EXPECT_FALSE(MinMaxAll::min()->matches(MinMaxAll::max()));
|
|
EXPECT_FALSE(MinMaxAll::max()->matches(MinMaxAll::min()));
|
|
}
|
|
|
|
TEST_F(SdcMinMaxAllTest, ToString) {
|
|
EXPECT_EQ(MinMaxAll::min()->to_string(), "min");
|
|
EXPECT_EQ(MinMaxAll::max()->to_string(), "max");
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// SetupHold tests (SetupHold is typedef for MinMax)
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
class SetupHoldTest : public ::testing::Test {};
|
|
|
|
TEST_F(SetupHoldTest, Singletons) {
|
|
// SetupHold is typedef for MinMax: setup=min, hold=max
|
|
EXPECT_NE(SetupHold::min(), nullptr);
|
|
EXPECT_NE(SetupHold::max(), nullptr);
|
|
EXPECT_NE(SetupHold::min(), SetupHold::max());
|
|
}
|
|
|
|
TEST_F(SetupHoldTest, Indices) {
|
|
EXPECT_NE(SetupHold::min()->index(), SetupHold::max()->index());
|
|
}
|
|
|
|
TEST_F(SetupHoldTest, Opposite) {
|
|
EXPECT_EQ(SetupHold::min()->opposite(), SetupHold::max());
|
|
EXPECT_EQ(SetupHold::max()->opposite(), SetupHold::min());
|
|
}
|
|
|
|
class SetupHoldAllTest : public ::testing::Test {};
|
|
|
|
TEST_F(SetupHoldAllTest, Singletons) {
|
|
// SetupHoldAll is typedef for MinMaxAll
|
|
EXPECT_NE(SetupHoldAll::min(), nullptr);
|
|
EXPECT_NE(SetupHoldAll::max(), nullptr);
|
|
EXPECT_NE(SetupHoldAll::all(), nullptr);
|
|
}
|
|
|
|
TEST_F(SetupHoldAllTest, Matches) {
|
|
EXPECT_TRUE(SetupHoldAll::min()->matches(SetupHold::min()));
|
|
EXPECT_FALSE(SetupHoldAll::min()->matches(SetupHold::max()));
|
|
EXPECT_TRUE(SetupHoldAll::max()->matches(SetupHold::max()));
|
|
EXPECT_FALSE(SetupHoldAll::max()->matches(SetupHold::min()));
|
|
EXPECT_TRUE(SetupHoldAll::all()->matches(SetupHold::min()));
|
|
EXPECT_TRUE(SetupHoldAll::all()->matches(SetupHold::max()));
|
|
}
|
|
|
|
TEST_F(SetupHoldAllTest, Range) {
|
|
auto &range = SetupHoldAll::all()->range();
|
|
EXPECT_EQ(range.size(), 2u);
|
|
}
|
|
|
|
TEST_F(SetupHoldAllTest, Find) {
|
|
EXPECT_EQ(SetupHoldAll::find("min"), SetupHoldAll::min());
|
|
EXPECT_EQ(SetupHoldAll::find("max"), SetupHoldAll::max());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// RiseFallMinMax additional tests for SDC coverage
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
class SdcRiseFallMinMaxTest : public ::testing::Test {};
|
|
|
|
TEST_F(SdcRiseFallMinMaxTest, MergeValueIntoEmpty) {
|
|
RiseFallMinMax rfmm;
|
|
rfmm.mergeValue(RiseFallBoth::riseFall(), MinMaxAll::all(), 3.0f);
|
|
// When empty, merge should set the value
|
|
EXPECT_FLOAT_EQ(rfmm.value(RiseFall::rise(), MinMax::min()), 3.0f);
|
|
EXPECT_FLOAT_EQ(rfmm.value(RiseFall::fall(), MinMax::max()), 3.0f);
|
|
}
|
|
|
|
TEST_F(SdcRiseFallMinMaxTest, MergeValueRfMm) {
|
|
RiseFallMinMax rfmm;
|
|
rfmm.setValue(RiseFall::rise(), MinMax::max(), 5.0f);
|
|
rfmm.mergeValue(RiseFall::rise(), MinMax::max(), 10.0f);
|
|
EXPECT_FLOAT_EQ(rfmm.value(RiseFall::rise(), MinMax::max()), 10.0f);
|
|
rfmm.mergeValue(RiseFall::rise(), MinMax::max(), 3.0f);
|
|
EXPECT_FLOAT_EQ(rfmm.value(RiseFall::rise(), MinMax::max()), 10.0f);
|
|
}
|
|
|
|
TEST_F(SdcRiseFallMinMaxTest, MergeValueRfMmMin) {
|
|
RiseFallMinMax rfmm;
|
|
rfmm.setValue(RiseFall::fall(), MinMax::min(), 5.0f);
|
|
rfmm.mergeValue(RiseFall::fall(), MinMax::min(), 2.0f);
|
|
EXPECT_FLOAT_EQ(rfmm.value(RiseFall::fall(), MinMax::min()), 2.0f);
|
|
rfmm.mergeValue(RiseFall::fall(), MinMax::min(), 8.0f);
|
|
EXPECT_FLOAT_EQ(rfmm.value(RiseFall::fall(), MinMax::min()), 2.0f);
|
|
}
|
|
|
|
TEST_F(SdcRiseFallMinMaxTest, MergeValueIntoEmptyRfMm) {
|
|
RiseFallMinMax rfmm;
|
|
rfmm.mergeValue(RiseFall::rise(), MinMax::min(), 7.0f);
|
|
EXPECT_FLOAT_EQ(rfmm.value(RiseFall::rise(), MinMax::min()), 7.0f);
|
|
}
|
|
|
|
TEST_F(SdcRiseFallMinMaxTest, MergeWithBothExist) {
|
|
RiseFallMinMax rfmm1;
|
|
rfmm1.setValue(RiseFall::rise(), MinMax::min(), 5.0f);
|
|
rfmm1.setValue(RiseFall::rise(), MinMax::max(), 5.0f);
|
|
rfmm1.setValue(RiseFall::fall(), MinMax::min(), 5.0f);
|
|
rfmm1.setValue(RiseFall::fall(), MinMax::max(), 5.0f);
|
|
|
|
RiseFallMinMax rfmm2;
|
|
rfmm2.setValue(RiseFall::rise(), MinMax::min(), 3.0f);
|
|
rfmm2.setValue(RiseFall::rise(), MinMax::max(), 10.0f);
|
|
rfmm2.setValue(RiseFall::fall(), MinMax::min(), 3.0f);
|
|
rfmm2.setValue(RiseFall::fall(), MinMax::max(), 10.0f);
|
|
|
|
rfmm1.mergeWith(&rfmm2);
|
|
EXPECT_FLOAT_EQ(rfmm1.value(RiseFall::rise(), MinMax::min()), 3.0f);
|
|
EXPECT_FLOAT_EQ(rfmm1.value(RiseFall::rise(), MinMax::max()), 10.0f);
|
|
}
|
|
|
|
TEST_F(SdcRiseFallMinMaxTest, MergeWithOnlySecondExists) {
|
|
RiseFallMinMax rfmm1;
|
|
// rfmm1 is empty
|
|
|
|
RiseFallMinMax rfmm2;
|
|
rfmm2.setValue(RiseFall::rise(), MinMax::min(), 7.0f);
|
|
|
|
rfmm1.mergeWith(&rfmm2);
|
|
EXPECT_FLOAT_EQ(rfmm1.value(RiseFall::rise(), MinMax::min()), 7.0f);
|
|
}
|
|
|
|
TEST_F(SdcRiseFallMinMaxTest, RemoveValueRfBothMm) {
|
|
RiseFallMinMax rfmm(1.0f);
|
|
rfmm.removeValue(RiseFallBoth::riseFall(), MinMax::min());
|
|
EXPECT_FALSE(rfmm.hasValue(RiseFall::rise(), MinMax::min()));
|
|
EXPECT_FALSE(rfmm.hasValue(RiseFall::fall(), MinMax::min()));
|
|
EXPECT_TRUE(rfmm.hasValue(RiseFall::rise(), MinMax::max()));
|
|
EXPECT_TRUE(rfmm.hasValue(RiseFall::fall(), MinMax::max()));
|
|
}
|
|
|
|
TEST_F(SdcRiseFallMinMaxTest, RemoveValueRfBothMmAll) {
|
|
RiseFallMinMax rfmm(1.0f);
|
|
rfmm.removeValue(RiseFallBoth::rise(), MinMaxAll::all());
|
|
EXPECT_FALSE(rfmm.hasValue(RiseFall::rise(), MinMax::min()));
|
|
EXPECT_FALSE(rfmm.hasValue(RiseFall::rise(), MinMax::max()));
|
|
EXPECT_TRUE(rfmm.hasValue(RiseFall::fall(), MinMax::min()));
|
|
EXPECT_TRUE(rfmm.hasValue(RiseFall::fall(), MinMax::max()));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// Variables tests
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
class VariablesTest : public ::testing::Test {};
|
|
|
|
TEST_F(VariablesTest, DefaultValues) {
|
|
Variables vars;
|
|
EXPECT_TRUE(vars.crprEnabled());
|
|
EXPECT_EQ(vars.crprMode(), CrprMode::same_pin);
|
|
EXPECT_TRUE(vars.propagateGatedClockEnable());
|
|
EXPECT_FALSE(vars.presetClrArcsEnabled());
|
|
EXPECT_TRUE(vars.condDefaultArcsEnabled());
|
|
EXPECT_FALSE(vars.bidirectInstPathsEnabled());
|
|
EXPECT_FALSE(vars.bidirectNetPathsEnabled());
|
|
EXPECT_TRUE(vars.recoveryRemovalChecksEnabled());
|
|
EXPECT_TRUE(vars.gatedClkChecksEnabled());
|
|
EXPECT_FALSE(vars.clkThruTristateEnabled());
|
|
EXPECT_FALSE(vars.dynamicLoopBreaking());
|
|
EXPECT_FALSE(vars.propagateAllClocks());
|
|
EXPECT_FALSE(vars.useDefaultArrivalClock());
|
|
EXPECT_FALSE(vars.pocvEnabled());
|
|
}
|
|
|
|
TEST_F(VariablesTest, SetCrprEnabled) {
|
|
Variables vars;
|
|
vars.setCrprEnabled(false);
|
|
EXPECT_FALSE(vars.crprEnabled());
|
|
vars.setCrprEnabled(true);
|
|
EXPECT_TRUE(vars.crprEnabled());
|
|
}
|
|
|
|
TEST_F(VariablesTest, SetCrprMode) {
|
|
Variables vars;
|
|
vars.setCrprMode(CrprMode::same_transition);
|
|
EXPECT_EQ(vars.crprMode(), CrprMode::same_transition);
|
|
vars.setCrprMode(CrprMode::same_pin);
|
|
EXPECT_EQ(vars.crprMode(), CrprMode::same_pin);
|
|
}
|
|
|
|
TEST_F(VariablesTest, SetPropagateGatedClockEnable) {
|
|
Variables vars;
|
|
vars.setPropagateGatedClockEnable(false);
|
|
EXPECT_FALSE(vars.propagateGatedClockEnable());
|
|
}
|
|
|
|
TEST_F(VariablesTest, SetPresetClrArcsEnabled) {
|
|
Variables vars;
|
|
vars.setPresetClrArcsEnabled(true);
|
|
EXPECT_TRUE(vars.presetClrArcsEnabled());
|
|
}
|
|
|
|
TEST_F(VariablesTest, SetCondDefaultArcsEnabled) {
|
|
Variables vars;
|
|
vars.setCondDefaultArcsEnabled(false);
|
|
EXPECT_FALSE(vars.condDefaultArcsEnabled());
|
|
}
|
|
|
|
TEST_F(VariablesTest, SetBidirectInstPathsEnabled) {
|
|
Variables vars;
|
|
vars.setBidirectInstPathsEnabled(true);
|
|
EXPECT_TRUE(vars.bidirectInstPathsEnabled());
|
|
}
|
|
|
|
TEST_F(VariablesTest, SetBidirectNetPathsEnabled) {
|
|
Variables vars;
|
|
vars.setBidirectNetPathsEnabled(true);
|
|
EXPECT_TRUE(vars.bidirectNetPathsEnabled());
|
|
}
|
|
|
|
TEST_F(VariablesTest, SetRecoveryRemovalChecksEnabled) {
|
|
Variables vars;
|
|
vars.setRecoveryRemovalChecksEnabled(false);
|
|
EXPECT_FALSE(vars.recoveryRemovalChecksEnabled());
|
|
}
|
|
|
|
TEST_F(VariablesTest, SetGatedClkChecksEnabled) {
|
|
Variables vars;
|
|
vars.setGatedClkChecksEnabled(false);
|
|
EXPECT_FALSE(vars.gatedClkChecksEnabled());
|
|
}
|
|
|
|
TEST_F(VariablesTest, SetDynamicLoopBreaking) {
|
|
Variables vars;
|
|
vars.setDynamicLoopBreaking(true);
|
|
EXPECT_TRUE(vars.dynamicLoopBreaking());
|
|
}
|
|
|
|
TEST_F(VariablesTest, SetPropagateAllClocks) {
|
|
Variables vars;
|
|
vars.setPropagateAllClocks(true);
|
|
EXPECT_TRUE(vars.propagateAllClocks());
|
|
}
|
|
|
|
TEST_F(VariablesTest, SetClkThruTristateEnabled) {
|
|
Variables vars;
|
|
vars.setClkThruTristateEnabled(true);
|
|
EXPECT_TRUE(vars.clkThruTristateEnabled());
|
|
}
|
|
|
|
TEST_F(VariablesTest, SetUseDefaultArrivalClock) {
|
|
Variables vars;
|
|
vars.setUseDefaultArrivalClock(true);
|
|
EXPECT_TRUE(vars.useDefaultArrivalClock());
|
|
}
|
|
|
|
TEST_F(VariablesTest, SetPocvEnabled) {
|
|
Variables vars;
|
|
vars.setPocvEnabled(true);
|
|
EXPECT_TRUE(vars.pocvEnabled());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// DeratingFactors tests
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
class DeratingFactorsTest : public ::testing::Test {};
|
|
|
|
TEST_F(DeratingFactorsTest, DefaultConstruction) {
|
|
DeratingFactors df;
|
|
EXPECT_FALSE(df.hasValue());
|
|
}
|
|
|
|
TEST_F(DeratingFactorsTest, SetFactorClkData) {
|
|
DeratingFactors df;
|
|
df.setFactor(PathClkOrData::clk, RiseFallBoth::riseFall(),
|
|
MinMax::min(), 0.95f);
|
|
EXPECT_TRUE(df.hasValue());
|
|
|
|
float factor;
|
|
bool exists;
|
|
df.factor(PathClkOrData::clk, RiseFall::rise(), MinMax::min(),
|
|
factor, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(factor, 0.95f);
|
|
|
|
df.factor(PathClkOrData::clk, RiseFall::fall(), MinMax::min(),
|
|
factor, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(factor, 0.95f);
|
|
}
|
|
|
|
TEST_F(DeratingFactorsTest, SetFactorData) {
|
|
DeratingFactors df;
|
|
df.setFactor(PathClkOrData::data, RiseFallBoth::rise(),
|
|
MinMax::max(), 1.05f);
|
|
|
|
float factor;
|
|
bool exists;
|
|
df.factor(PathClkOrData::data, RiseFall::rise(), MinMax::max(),
|
|
factor, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(factor, 1.05f);
|
|
|
|
// Fall should not exist
|
|
df.factor(PathClkOrData::data, RiseFall::fall(), MinMax::max(),
|
|
factor, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
TEST_F(DeratingFactorsTest, Clear) {
|
|
DeratingFactors df;
|
|
df.setFactor(PathClkOrData::clk, RiseFallBoth::riseFall(),
|
|
MinMax::min(), 0.95f);
|
|
EXPECT_TRUE(df.hasValue());
|
|
df.clear();
|
|
EXPECT_FALSE(df.hasValue());
|
|
}
|
|
|
|
TEST_F(DeratingFactorsTest, IsOneValueTrue) {
|
|
DeratingFactors df;
|
|
df.setFactor(PathClkOrData::clk, RiseFallBoth::riseFall(),
|
|
MinMax::min(), 0.95f);
|
|
df.setFactor(PathClkOrData::data, RiseFallBoth::riseFall(),
|
|
MinMax::min(), 0.95f);
|
|
bool is_one;
|
|
float val;
|
|
df.isOneValue(MinMax::min(), is_one, val);
|
|
EXPECT_TRUE(is_one);
|
|
EXPECT_FLOAT_EQ(val, 0.95f);
|
|
}
|
|
|
|
TEST_F(DeratingFactorsTest, IsOneValueFalse) {
|
|
DeratingFactors df;
|
|
df.setFactor(PathClkOrData::clk, RiseFallBoth::riseFall(),
|
|
MinMax::min(), 0.95f);
|
|
df.setFactor(PathClkOrData::data, RiseFallBoth::riseFall(),
|
|
MinMax::min(), 1.05f);
|
|
bool is_one;
|
|
float val;
|
|
df.isOneValue(MinMax::min(), is_one, val);
|
|
EXPECT_FALSE(is_one);
|
|
}
|
|
|
|
TEST_F(DeratingFactorsTest, IsOneValueClkData) {
|
|
DeratingFactors df;
|
|
df.setFactor(PathClkOrData::clk, RiseFallBoth::riseFall(),
|
|
MinMax::min(), 0.95f);
|
|
bool is_one;
|
|
float val;
|
|
df.isOneValue(PathClkOrData::clk, MinMax::min(), is_one, val);
|
|
EXPECT_TRUE(is_one);
|
|
EXPECT_FLOAT_EQ(val, 0.95f);
|
|
}
|
|
|
|
// DeratingFactorsGlobal tests
|
|
class DeratingFactorsGlobalTest : public ::testing::Test {};
|
|
|
|
TEST_F(DeratingFactorsGlobalTest, DefaultConstruction) {
|
|
DeratingFactorsGlobal dfg;
|
|
// Should be constructible and clearable
|
|
dfg.clear();
|
|
}
|
|
|
|
TEST_F(DeratingFactorsGlobalTest, SetFactorCellDelay) {
|
|
DeratingFactorsGlobal dfg;
|
|
dfg.setFactor(TimingDerateType::cell_delay, PathClkOrData::data,
|
|
RiseFallBoth::riseFall(), MinMax::max(), 1.1f);
|
|
|
|
float factor;
|
|
bool exists;
|
|
dfg.factor(TimingDerateType::cell_delay, PathClkOrData::data,
|
|
RiseFall::rise(), MinMax::max(), factor, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(factor, 1.1f);
|
|
}
|
|
|
|
TEST_F(DeratingFactorsGlobalTest, SetFactorCellCheck) {
|
|
DeratingFactorsGlobal dfg;
|
|
dfg.setFactor(TimingDerateType::cell_check, PathClkOrData::clk,
|
|
RiseFallBoth::fall(), MinMax::min(), 0.9f);
|
|
|
|
float factor;
|
|
bool exists;
|
|
dfg.factor(TimingDerateType::cell_check, PathClkOrData::clk,
|
|
RiseFall::fall(), MinMax::min(), factor, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(factor, 0.9f);
|
|
}
|
|
|
|
TEST_F(DeratingFactorsGlobalTest, SetFactorNetDelay) {
|
|
DeratingFactorsGlobal dfg;
|
|
dfg.setFactor(TimingDerateType::net_delay, PathClkOrData::data,
|
|
RiseFallBoth::riseFall(), MinMax::max(), 1.2f);
|
|
|
|
float factor;
|
|
bool exists;
|
|
dfg.factor(TimingDerateType::net_delay, PathClkOrData::data,
|
|
RiseFall::rise(), MinMax::max(), factor, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(factor, 1.2f);
|
|
}
|
|
|
|
TEST_F(DeratingFactorsGlobalTest, FactorCellType) {
|
|
DeratingFactorsGlobal dfg;
|
|
dfg.setFactor(TimingDerateType::cell_delay, PathClkOrData::data,
|
|
RiseFallBoth::riseFall(), MinMax::max(), 1.15f);
|
|
|
|
float factor;
|
|
bool exists;
|
|
dfg.factor(TimingDerateCellType::cell_delay, PathClkOrData::data,
|
|
RiseFall::rise(), MinMax::max(), factor, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(factor, 1.15f);
|
|
}
|
|
|
|
TEST_F(DeratingFactorsGlobalTest, Factors) {
|
|
DeratingFactorsGlobal dfg;
|
|
DeratingFactors *f = dfg.factors(TimingDerateType::cell_delay);
|
|
EXPECT_NE(f, nullptr);
|
|
EXPECT_FALSE(f->hasValue());
|
|
}
|
|
|
|
// DeratingFactorsCell tests
|
|
class DeratingFactorsCellTest : public ::testing::Test {};
|
|
|
|
TEST_F(DeratingFactorsCellTest, DefaultConstruction) {
|
|
DeratingFactorsCell dfc;
|
|
dfc.clear();
|
|
}
|
|
|
|
TEST_F(DeratingFactorsCellTest, SetFactorCellDelay) {
|
|
DeratingFactorsCell dfc;
|
|
dfc.setFactor(TimingDerateCellType::cell_delay, PathClkOrData::data,
|
|
RiseFallBoth::riseFall(), MinMax::max(), 1.1f);
|
|
|
|
float factor;
|
|
bool exists;
|
|
dfc.factor(TimingDerateCellType::cell_delay, PathClkOrData::data,
|
|
RiseFall::rise(), MinMax::max(), factor, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(factor, 1.1f);
|
|
}
|
|
|
|
TEST_F(DeratingFactorsCellTest, SetFactorCellCheck) {
|
|
DeratingFactorsCell dfc;
|
|
dfc.setFactor(TimingDerateCellType::cell_check, PathClkOrData::clk,
|
|
RiseFallBoth::fall(), MinMax::min(), 0.85f);
|
|
|
|
float factor;
|
|
bool exists;
|
|
dfc.factor(TimingDerateCellType::cell_check, PathClkOrData::clk,
|
|
RiseFall::fall(), MinMax::min(), factor, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(factor, 0.85f);
|
|
}
|
|
|
|
TEST_F(DeratingFactorsCellTest, Factors) {
|
|
DeratingFactorsCell dfc;
|
|
DeratingFactors *f = dfc.factors(TimingDerateCellType::cell_delay);
|
|
EXPECT_NE(f, nullptr);
|
|
}
|
|
|
|
TEST_F(DeratingFactorsCellTest, IsOneValue) {
|
|
DeratingFactorsCell dfc;
|
|
dfc.setFactor(TimingDerateCellType::cell_delay, PathClkOrData::clk,
|
|
RiseFallBoth::riseFall(), MinMax::min(), 0.9f);
|
|
dfc.setFactor(TimingDerateCellType::cell_delay, PathClkOrData::data,
|
|
RiseFallBoth::riseFall(), MinMax::min(), 0.9f);
|
|
dfc.setFactor(TimingDerateCellType::cell_check, PathClkOrData::clk,
|
|
RiseFallBoth::riseFall(), MinMax::min(), 0.9f);
|
|
dfc.setFactor(TimingDerateCellType::cell_check, PathClkOrData::data,
|
|
RiseFallBoth::riseFall(), MinMax::min(), 0.9f);
|
|
bool is_one;
|
|
float val;
|
|
dfc.isOneValue(MinMax::min(), is_one, val);
|
|
EXPECT_TRUE(is_one);
|
|
EXPECT_FLOAT_EQ(val, 0.9f);
|
|
}
|
|
|
|
TEST_F(DeratingFactorsCellTest, IsOneValueDifferent) {
|
|
DeratingFactorsCell dfc;
|
|
dfc.setFactor(TimingDerateCellType::cell_delay, PathClkOrData::data,
|
|
RiseFallBoth::riseFall(), MinMax::min(), 0.9f);
|
|
dfc.setFactor(TimingDerateCellType::cell_check, PathClkOrData::data,
|
|
RiseFallBoth::riseFall(), MinMax::min(), 1.1f);
|
|
bool is_one;
|
|
float val;
|
|
dfc.isOneValue(MinMax::min(), is_one, val);
|
|
EXPECT_FALSE(is_one);
|
|
}
|
|
|
|
// DeratingFactorsNet tests
|
|
class DeratingFactorsNetTest : public ::testing::Test {};
|
|
|
|
TEST_F(DeratingFactorsNetTest, DefaultConstruction) {
|
|
DeratingFactorsNet dfn;
|
|
EXPECT_FALSE(dfn.hasValue());
|
|
}
|
|
|
|
TEST_F(DeratingFactorsNetTest, InheritsSetFactor) {
|
|
DeratingFactorsNet dfn;
|
|
dfn.setFactor(PathClkOrData::data, RiseFallBoth::riseFall(),
|
|
MinMax::max(), 1.05f);
|
|
EXPECT_TRUE(dfn.hasValue());
|
|
float factor;
|
|
bool exists;
|
|
dfn.factor(PathClkOrData::data, RiseFall::rise(), MinMax::max(),
|
|
factor, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(factor, 1.05f);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// ClockLatency tests
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
class ClockLatencyTest : public ::testing::Test {};
|
|
|
|
TEST_F(ClockLatencyTest, Construction) {
|
|
ClockLatency cl(nullptr, nullptr);
|
|
EXPECT_EQ(cl.clock(), nullptr);
|
|
EXPECT_EQ(cl.pin(), nullptr);
|
|
}
|
|
|
|
TEST_F(ClockLatencyTest, SetAndGetDelay) {
|
|
ClockLatency cl(nullptr, nullptr);
|
|
cl.setDelay(RiseFall::rise(), MinMax::max(), 1.5f);
|
|
EXPECT_FLOAT_EQ(cl.delay(RiseFall::rise(), MinMax::max()), 1.5f);
|
|
// Unset returns 0.0
|
|
EXPECT_FLOAT_EQ(cl.delay(RiseFall::fall(), MinMax::max()), 0.0f);
|
|
}
|
|
|
|
TEST_F(ClockLatencyTest, SetDelayBoth) {
|
|
ClockLatency cl(nullptr, nullptr);
|
|
cl.setDelay(RiseFallBoth::riseFall(), MinMaxAll::all(), 2.0f);
|
|
EXPECT_FLOAT_EQ(cl.delay(RiseFall::rise(), MinMax::min()), 2.0f);
|
|
EXPECT_FLOAT_EQ(cl.delay(RiseFall::fall(), MinMax::max()), 2.0f);
|
|
}
|
|
|
|
TEST_F(ClockLatencyTest, DelayWithExists) {
|
|
ClockLatency cl(nullptr, nullptr);
|
|
float latency;
|
|
bool exists;
|
|
cl.delay(RiseFall::rise(), MinMax::min(), latency, exists);
|
|
EXPECT_FALSE(exists);
|
|
EXPECT_FLOAT_EQ(latency, 0.0f);
|
|
|
|
cl.setDelay(RiseFall::rise(), MinMax::min(), 3.0f);
|
|
cl.delay(RiseFall::rise(), MinMax::min(), latency, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(latency, 3.0f);
|
|
}
|
|
|
|
TEST_F(ClockLatencyTest, Delays) {
|
|
ClockLatency cl(nullptr, nullptr);
|
|
RiseFallMinMax *delays = cl.delays();
|
|
EXPECT_NE(delays, nullptr);
|
|
}
|
|
|
|
TEST_F(ClockLatencyTest, SetDelays) {
|
|
RiseFallMinMax src(5.0f);
|
|
ClockLatency cl(nullptr, nullptr);
|
|
cl.setDelays(&src);
|
|
EXPECT_FLOAT_EQ(cl.delay(RiseFall::rise(), MinMax::min()), 5.0f);
|
|
EXPECT_FLOAT_EQ(cl.delay(RiseFall::fall(), MinMax::max()), 5.0f);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// ClockInsertion tests
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
class ClockInsertionTest : public ::testing::Test {};
|
|
|
|
TEST_F(ClockInsertionTest, Construction) {
|
|
ClockInsertion ci(nullptr, nullptr);
|
|
EXPECT_EQ(ci.clock(), nullptr);
|
|
EXPECT_EQ(ci.pin(), nullptr);
|
|
}
|
|
|
|
TEST_F(ClockInsertionTest, SetAndGetDelay) {
|
|
ClockInsertion ci(nullptr, nullptr);
|
|
ci.setDelay(RiseFall::rise(), MinMax::max(), EarlyLate::min(), 1.5f);
|
|
float delay = ci.delay(RiseFall::rise(), MinMax::max(), EarlyLate::min());
|
|
EXPECT_FLOAT_EQ(delay, 1.5f);
|
|
// Unset returns 0.0
|
|
float delay2 = ci.delay(RiseFall::fall(), MinMax::max(), EarlyLate::min());
|
|
EXPECT_FLOAT_EQ(delay2, 0.0f);
|
|
}
|
|
|
|
TEST_F(ClockInsertionTest, SetDelayBoth) {
|
|
ClockInsertion ci(nullptr, nullptr);
|
|
ci.setDelay(RiseFallBoth::riseFall(), MinMaxAll::all(),
|
|
EarlyLateAll::all(), 2.0f);
|
|
EXPECT_FLOAT_EQ(ci.delay(RiseFall::rise(), MinMax::min(), EarlyLate::min()), 2.0f);
|
|
EXPECT_FLOAT_EQ(ci.delay(RiseFall::fall(), MinMax::max(), EarlyLate::max()), 2.0f);
|
|
}
|
|
|
|
TEST_F(ClockInsertionTest, DelayWithExists) {
|
|
ClockInsertion ci(nullptr, nullptr);
|
|
float insertion;
|
|
bool exists;
|
|
ci.delay(RiseFall::rise(), MinMax::min(), EarlyLate::min(), insertion, exists);
|
|
EXPECT_FALSE(exists);
|
|
EXPECT_FLOAT_EQ(insertion, 0.0f);
|
|
|
|
ci.setDelay(RiseFall::rise(), MinMax::min(), EarlyLate::min(), 3.0f);
|
|
ci.delay(RiseFall::rise(), MinMax::min(), EarlyLate::min(), insertion, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(insertion, 3.0f);
|
|
}
|
|
|
|
TEST_F(ClockInsertionTest, Delays) {
|
|
ClockInsertion ci(nullptr, nullptr);
|
|
RiseFallMinMax *delays = ci.delays(EarlyLate::min());
|
|
EXPECT_NE(delays, nullptr);
|
|
}
|
|
|
|
TEST_F(ClockInsertionTest, SetDelays) {
|
|
RiseFallMinMax src(7.0f);
|
|
ClockInsertion ci(nullptr, nullptr);
|
|
ci.setDelays(&src);
|
|
EXPECT_FLOAT_EQ(ci.delay(RiseFall::rise(), MinMax::min(), EarlyLate::min()), 7.0f);
|
|
EXPECT_FLOAT_EQ(ci.delay(RiseFall::fall(), MinMax::max(), EarlyLate::max()), 7.0f);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// ClockGatingCheck tests
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
class ClockGatingCheckTest : public ::testing::Test {};
|
|
|
|
TEST_F(ClockGatingCheckTest, DefaultConstruction) {
|
|
ClockGatingCheck cgc;
|
|
EXPECT_EQ(cgc.activeValue(), LogicValue::unknown);
|
|
}
|
|
|
|
TEST_F(ClockGatingCheckTest, SetActiveValue) {
|
|
ClockGatingCheck cgc;
|
|
cgc.setActiveValue(LogicValue::one);
|
|
EXPECT_EQ(cgc.activeValue(), LogicValue::one);
|
|
cgc.setActiveValue(LogicValue::zero);
|
|
EXPECT_EQ(cgc.activeValue(), LogicValue::zero);
|
|
}
|
|
|
|
TEST_F(ClockGatingCheckTest, Margins) {
|
|
ClockGatingCheck cgc;
|
|
RiseFallMinMax *margins = cgc.margins();
|
|
EXPECT_NE(margins, nullptr);
|
|
EXPECT_TRUE(margins->empty());
|
|
}
|
|
|
|
TEST_F(ClockGatingCheckTest, SetMargins) {
|
|
ClockGatingCheck cgc;
|
|
RiseFallMinMax *margins = cgc.margins();
|
|
margins->setValue(RiseFall::rise(), MinMax::min(), 0.1f);
|
|
float val;
|
|
bool exists;
|
|
margins->value(RiseFall::rise(), MinMax::min(), val, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(val, 0.1f);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// SdcCmdComment tests
|
|
// SdcCmdComment has a protected destructor so we use a testable subclass
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
class TestableSdcCmdComment : public SdcCmdComment {
|
|
public:
|
|
TestableSdcCmdComment() : SdcCmdComment() {}
|
|
TestableSdcCmdComment(const char *comment) : SdcCmdComment(comment) {}
|
|
~TestableSdcCmdComment() {}
|
|
};
|
|
|
|
class SdcCmdCommentTest : public ::testing::Test {};
|
|
|
|
TEST_F(SdcCmdCommentTest, DefaultConstruction) {
|
|
TestableSdcCmdComment scc;
|
|
EXPECT_EQ(scc.comment(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcCmdCommentTest, CommentConstruction) {
|
|
TestableSdcCmdComment scc("test comment");
|
|
EXPECT_STREQ(scc.comment(), "test comment");
|
|
}
|
|
|
|
TEST_F(SdcCmdCommentTest, EmptyCommentConstruction) {
|
|
TestableSdcCmdComment scc("");
|
|
EXPECT_EQ(scc.comment(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcCmdCommentTest, NullCommentConstruction) {
|
|
TestableSdcCmdComment scc(nullptr);
|
|
EXPECT_EQ(scc.comment(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcCmdCommentTest, SetComment) {
|
|
TestableSdcCmdComment scc;
|
|
scc.setComment("new comment");
|
|
EXPECT_STREQ(scc.comment(), "new comment");
|
|
}
|
|
|
|
TEST_F(SdcCmdCommentTest, SetCommentNull) {
|
|
TestableSdcCmdComment scc("original");
|
|
scc.setComment(nullptr);
|
|
EXPECT_EQ(scc.comment(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcCmdCommentTest, SetCommentEmpty) {
|
|
TestableSdcCmdComment scc("original");
|
|
scc.setComment("");
|
|
EXPECT_EQ(scc.comment(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcCmdCommentTest, SetCommentReplace) {
|
|
TestableSdcCmdComment scc("first");
|
|
scc.setComment("second");
|
|
EXPECT_STREQ(scc.comment(), "second");
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// PortExtCap tests
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
class PortExtCapTest : public ::testing::Test {};
|
|
|
|
TEST_F(PortExtCapTest, Construction) {
|
|
PortExtCap pec(nullptr);
|
|
EXPECT_EQ(pec.port(), nullptr);
|
|
}
|
|
|
|
TEST_F(PortExtCapTest, PinCap) {
|
|
PortExtCap pec(nullptr);
|
|
float cap;
|
|
bool exists;
|
|
pec.pinCap(RiseFall::rise(), MinMax::max(), cap, exists);
|
|
EXPECT_FALSE(exists);
|
|
|
|
pec.setPinCap(1.5f, RiseFall::rise(), MinMax::max());
|
|
pec.pinCap(RiseFall::rise(), MinMax::max(), cap, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(cap, 1.5f);
|
|
}
|
|
|
|
TEST_F(PortExtCapTest, WireCap) {
|
|
PortExtCap pec(nullptr);
|
|
float cap;
|
|
bool exists;
|
|
pec.wireCap(RiseFall::fall(), MinMax::min(), cap, exists);
|
|
EXPECT_FALSE(exists);
|
|
|
|
pec.setWireCap(2.5f, RiseFall::fall(), MinMax::min());
|
|
pec.wireCap(RiseFall::fall(), MinMax::min(), cap, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(cap, 2.5f);
|
|
}
|
|
|
|
TEST_F(PortExtCapTest, Fanout) {
|
|
PortExtCap pec(nullptr);
|
|
int fanout;
|
|
bool exists;
|
|
pec.fanout(MinMax::max(), fanout, exists);
|
|
EXPECT_FALSE(exists);
|
|
|
|
pec.setFanout(4, MinMax::max());
|
|
pec.fanout(MinMax::max(), fanout, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_EQ(fanout, 4);
|
|
}
|
|
|
|
TEST_F(PortExtCapTest, PinCapPtr) {
|
|
PortExtCap pec(nullptr);
|
|
RiseFallMinMax *pc = pec.pinCap();
|
|
EXPECT_NE(pc, nullptr);
|
|
}
|
|
|
|
TEST_F(PortExtCapTest, WireCapPtr) {
|
|
PortExtCap pec(nullptr);
|
|
RiseFallMinMax *wc = pec.wireCap();
|
|
EXPECT_NE(wc, nullptr);
|
|
}
|
|
|
|
TEST_F(PortExtCapTest, FanoutPtr) {
|
|
PortExtCap pec(nullptr);
|
|
FanoutValues *fv = pec.fanout();
|
|
EXPECT_NE(fv, nullptr);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// DataCheck tests
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
class DataCheckTest : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override {
|
|
initSta();
|
|
}
|
|
};
|
|
|
|
TEST_F(DataCheckTest, Construction) {
|
|
DataCheck dc(nullptr, nullptr, nullptr);
|
|
EXPECT_EQ(dc.from(), nullptr);
|
|
EXPECT_EQ(dc.to(), nullptr);
|
|
EXPECT_EQ(dc.clk(), nullptr);
|
|
EXPECT_TRUE(dc.empty());
|
|
}
|
|
|
|
TEST_F(DataCheckTest, SetAndGetMargin) {
|
|
DataCheck dc(nullptr, nullptr, nullptr);
|
|
dc.setMargin(RiseFallBoth::riseFall(), RiseFallBoth::riseFall(),
|
|
SetupHoldAll::all(), 0.5f);
|
|
EXPECT_FALSE(dc.empty());
|
|
|
|
float margin;
|
|
bool exists;
|
|
dc.margin(RiseFall::rise(), RiseFall::rise(), SetupHold::min(),
|
|
margin, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(margin, 0.5f);
|
|
}
|
|
|
|
TEST_F(DataCheckTest, SetMarginSpecific) {
|
|
DataCheck dc(nullptr, nullptr, nullptr);
|
|
dc.setMargin(RiseFallBoth::rise(), RiseFallBoth::fall(),
|
|
SetupHoldAll::min(), 0.3f);
|
|
|
|
float margin;
|
|
bool exists;
|
|
dc.margin(RiseFall::rise(), RiseFall::fall(), SetupHold::min(),
|
|
margin, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(margin, 0.3f);
|
|
|
|
// Other combination should not exist
|
|
dc.margin(RiseFall::fall(), RiseFall::rise(), SetupHold::min(),
|
|
margin, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
TEST_F(DataCheckTest, RemoveMargin) {
|
|
DataCheck dc(nullptr, nullptr, nullptr);
|
|
dc.setMargin(RiseFallBoth::riseFall(), RiseFallBoth::riseFall(),
|
|
SetupHoldAll::all(), 0.5f);
|
|
EXPECT_FALSE(dc.empty());
|
|
|
|
dc.removeMargin(RiseFallBoth::riseFall(), RiseFallBoth::riseFall(),
|
|
SetupHoldAll::all());
|
|
EXPECT_TRUE(dc.empty());
|
|
}
|
|
|
|
TEST_F(DataCheckTest, MarginIsOneValue) {
|
|
DataCheck dc(nullptr, nullptr, nullptr);
|
|
dc.setMargin(RiseFallBoth::riseFall(), RiseFallBoth::riseFall(),
|
|
SetupHoldAll::min(), 0.5f);
|
|
float val;
|
|
bool is_one;
|
|
dc.marginIsOneValue(SetupHold::min(), val, is_one);
|
|
EXPECT_TRUE(is_one);
|
|
EXPECT_FLOAT_EQ(val, 0.5f);
|
|
}
|
|
|
|
TEST_F(DataCheckTest, MarginIsOneValueDifferent) {
|
|
DataCheck dc(nullptr, nullptr, nullptr);
|
|
dc.setMargin(RiseFallBoth::rise(), RiseFallBoth::riseFall(),
|
|
SetupHoldAll::min(), 0.5f);
|
|
dc.setMargin(RiseFallBoth::fall(), RiseFallBoth::riseFall(),
|
|
SetupHoldAll::min(), 0.3f);
|
|
float val;
|
|
bool is_one;
|
|
dc.marginIsOneValue(SetupHold::min(), val, is_one);
|
|
EXPECT_FALSE(is_one);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// PinPairEqual tests
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
class PinPairEqualTest : public ::testing::Test {};
|
|
|
|
TEST_F(PinPairEqualTest, SamePinsEqual) {
|
|
const Pin *p1 = reinterpret_cast<const Pin*>(0x1000);
|
|
const Pin *p2 = reinterpret_cast<const Pin*>(0x2000);
|
|
PinPair pair1(p1, p2);
|
|
PinPair pair2(p1, p2);
|
|
PinPairEqual eq;
|
|
EXPECT_TRUE(eq(pair1, pair2));
|
|
}
|
|
|
|
TEST_F(PinPairEqualTest, DifferentPinsNotEqual) {
|
|
const Pin *p1 = reinterpret_cast<const Pin*>(0x1000);
|
|
const Pin *p2 = reinterpret_cast<const Pin*>(0x2000);
|
|
const Pin *p3 = reinterpret_cast<const Pin*>(0x3000);
|
|
PinPair pair1(p1, p2);
|
|
PinPair pair2(p1, p3);
|
|
PinPairEqual eq;
|
|
EXPECT_FALSE(eq(pair1, pair2));
|
|
}
|
|
|
|
TEST_F(PinPairEqualTest, NullPinsEqual) {
|
|
PinPair pair1(nullptr, nullptr);
|
|
PinPair pair2(nullptr, nullptr);
|
|
PinPairEqual eq;
|
|
EXPECT_TRUE(eq(pair1, pair2));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// ClockGroups type tests
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
class ClockGroupsTest : public ::testing::Test {};
|
|
|
|
TEST_F(ClockGroupsTest, ClockSenseValues) {
|
|
// Verify enum values exist
|
|
EXPECT_NE(static_cast<int>(ClockSense::positive), static_cast<int>(ClockSense::negative));
|
|
EXPECT_NE(static_cast<int>(ClockSense::negative), static_cast<int>(ClockSense::stop));
|
|
EXPECT_NE(static_cast<int>(ClockSense::positive), static_cast<int>(ClockSense::stop));
|
|
}
|
|
|
|
TEST_F(ClockGroupsTest, AnalysisTypeValues) {
|
|
EXPECT_NE(static_cast<int>(AnalysisType::single), static_cast<int>(AnalysisType::bc_wc));
|
|
EXPECT_NE(static_cast<int>(AnalysisType::bc_wc), static_cast<int>(AnalysisType::ocv));
|
|
}
|
|
|
|
TEST_F(ClockGroupsTest, ExceptionPathTypeValues) {
|
|
EXPECT_NE(static_cast<int>(ExceptionPathType::false_path),
|
|
static_cast<int>(ExceptionPathType::loop));
|
|
EXPECT_NE(static_cast<int>(ExceptionPathType::multi_cycle),
|
|
static_cast<int>(ExceptionPathType::path_delay));
|
|
EXPECT_NE(static_cast<int>(ExceptionPathType::group_path),
|
|
static_cast<int>(ExceptionPathType::filter));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// SDC tests that require full Sta initialization
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
class SdcInitTest : 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_);
|
|
}
|
|
void TearDown() override {
|
|
deleteAllMemory();
|
|
sta_ = nullptr;
|
|
if (interp_)
|
|
Tcl_DeleteInterp(interp_);
|
|
interp_ = nullptr;
|
|
}
|
|
Sta *sta_;
|
|
Tcl_Interp *interp_;
|
|
};
|
|
|
|
// Sdc clear operations
|
|
TEST_F(SdcInitTest, SdcClearAfterConstraints) {
|
|
Sdc *sdc = sta_->sdc();
|
|
// Set some constraints then clear
|
|
sdc->setMinPulseWidth(RiseFallBoth::rise(), 0.5);
|
|
sdc->setMaxArea(100.0);
|
|
sdc->setWireloadMode(WireloadMode::top);
|
|
sdc->clear();
|
|
}
|
|
|
|
// Sdc remove constraints
|
|
TEST_F(SdcInitTest, SdcRemoveConstraints) {
|
|
sta_->removeConstraints();
|
|
}
|
|
|
|
// Clock creation and queries
|
|
TEST_F(SdcInitTest, MakeClockNoPins) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("test_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("test_clk");
|
|
EXPECT_NE(clk, nullptr);
|
|
EXPECT_FLOAT_EQ(clk->period(), 10.0);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, MakeClockAndRemove) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("clk1", nullptr, false, 10.0, waveform, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk1");
|
|
EXPECT_NE(clk, nullptr);
|
|
|
|
sta_->removeClock(clk);
|
|
EXPECT_EQ(sdc->findClock("clk1"), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, MultipleClocksQuery) {
|
|
FloatSeq *wave1 = new FloatSeq;
|
|
wave1->push_back(0.0);
|
|
wave1->push_back(5.0);
|
|
sta_->makeClock("clk_a", nullptr, false, 10.0, wave1, nullptr);
|
|
|
|
FloatSeq *wave2 = new FloatSeq;
|
|
wave2->push_back(0.0);
|
|
wave2->push_back(2.5);
|
|
sta_->makeClock("clk_b", nullptr, false, 5.0, wave2, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
ClockSeq clks = sdc->clks();
|
|
EXPECT_EQ(clks.size(), 2u);
|
|
}
|
|
|
|
// Clock properties
|
|
TEST_F(SdcInitTest, ClockProperties) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("prop_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("prop_clk");
|
|
EXPECT_STREQ(clk->name(), "prop_clk");
|
|
EXPECT_FLOAT_EQ(clk->period(), 10.0);
|
|
EXPECT_FALSE(clk->isPropagated());
|
|
EXPECT_FALSE(clk->isGenerated());
|
|
// Clock with no pins is virtual
|
|
EXPECT_TRUE(clk->isVirtual());
|
|
}
|
|
|
|
// Clock slew
|
|
TEST_F(SdcInitTest, ClockSlew) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("slew_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("slew_clk");
|
|
sta_->setClockSlew(clk, RiseFallBoth::riseFall(), MinMaxAll::all(), 0.5);
|
|
sta_->removeClockSlew(clk);
|
|
}
|
|
|
|
// Clock latency with clock
|
|
TEST_F(SdcInitTest, ClockLatencyOnClock) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("lat_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("lat_clk");
|
|
sta_->setClockLatency(clk, nullptr, RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), 1.0);
|
|
sta_->removeClockLatency(clk, nullptr);
|
|
}
|
|
|
|
// Clock insertion delay
|
|
TEST_F(SdcInitTest, ClockInsertionOnClock) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("ins_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("ins_clk");
|
|
sta_->setClockInsertion(clk, nullptr, RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), EarlyLateAll::all(), 0.5);
|
|
sta_->removeClockInsertion(clk, nullptr);
|
|
}
|
|
|
|
// Clock uncertainty
|
|
TEST_F(SdcInitTest, ClockUncertainty) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("unc_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("unc_clk");
|
|
sta_->setClockUncertainty(clk, SetupHoldAll::all(), 0.1);
|
|
sta_->removeClockUncertainty(clk, SetupHoldAll::all());
|
|
}
|
|
|
|
// Inter-clock uncertainty
|
|
TEST_F(SdcInitTest, InterClockUncertainty) {
|
|
FloatSeq *wave1 = new FloatSeq;
|
|
wave1->push_back(0.0);
|
|
wave1->push_back(5.0);
|
|
sta_->makeClock("iuc_clk1", nullptr, false, 10.0, wave1, nullptr);
|
|
|
|
FloatSeq *wave2 = new FloatSeq;
|
|
wave2->push_back(0.0);
|
|
wave2->push_back(2.5);
|
|
sta_->makeClock("iuc_clk2", nullptr, false, 5.0, wave2, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk1 = sdc->findClock("iuc_clk1");
|
|
Clock *clk2 = sdc->findClock("iuc_clk2");
|
|
sta_->setClockUncertainty(clk1, RiseFallBoth::riseFall(),
|
|
clk2, RiseFallBoth::riseFall(),
|
|
SetupHoldAll::all(), 0.2);
|
|
sta_->removeClockUncertainty(clk1, RiseFallBoth::riseFall(),
|
|
clk2, RiseFallBoth::riseFall(),
|
|
SetupHoldAll::all());
|
|
}
|
|
|
|
// Clock groups
|
|
TEST_F(SdcInitTest, ClockGroupsOperations) {
|
|
FloatSeq *wave1 = new FloatSeq;
|
|
wave1->push_back(0.0);
|
|
wave1->push_back(5.0);
|
|
sta_->makeClock("grp_clk1", nullptr, false, 10.0, wave1, nullptr);
|
|
|
|
FloatSeq *wave2 = new FloatSeq;
|
|
wave2->push_back(0.0);
|
|
wave2->push_back(2.5);
|
|
sta_->makeClock("grp_clk2", nullptr, false, 5.0, wave2, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk1 = sdc->findClock("grp_clk1");
|
|
Clock *clk2 = sdc->findClock("grp_clk2");
|
|
|
|
ClockGroups *groups = sta_->makeClockGroups("grp1", true, false, false, false, nullptr);
|
|
ClockSet *clk_set = new ClockSet;
|
|
clk_set->insert(clk1);
|
|
clk_set->insert(clk2);
|
|
sta_->makeClockGroup(groups, clk_set);
|
|
|
|
sta_->removeClockGroupsLogicallyExclusive("grp1");
|
|
}
|
|
|
|
// Clock propagation
|
|
TEST_F(SdcInitTest, ClockPropagation) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("prop_clk2", nullptr, false, 10.0, waveform, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("prop_clk2");
|
|
sta_->setPropagatedClock(clk);
|
|
EXPECT_TRUE(clk->isPropagated());
|
|
sta_->removePropagatedClock(clk);
|
|
EXPECT_FALSE(clk->isPropagated());
|
|
}
|
|
|
|
// Timing derate with clock
|
|
TEST_F(SdcInitTest, TimingDerateWithClock) {
|
|
sta_->setTimingDerate(TimingDerateType::cell_delay,
|
|
PathClkOrData::clk,
|
|
RiseFallBoth::rise(),
|
|
EarlyLate::early(),
|
|
0.95);
|
|
sta_->setTimingDerate(TimingDerateType::cell_check,
|
|
PathClkOrData::clk,
|
|
RiseFallBoth::fall(),
|
|
EarlyLate::late(),
|
|
1.05);
|
|
sta_->setTimingDerate(TimingDerateType::net_delay,
|
|
PathClkOrData::data,
|
|
RiseFallBoth::riseFall(),
|
|
EarlyLate::early(),
|
|
0.97);
|
|
sta_->unsetTimingDerate();
|
|
}
|
|
|
|
// Clock gating check with clock
|
|
TEST_F(SdcInitTest, ClockGatingCheckWithClock) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("cgc_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("cgc_clk");
|
|
sta_->setClockGatingCheck(clk, RiseFallBoth::riseFall(),
|
|
SetupHold::max(), 0.5);
|
|
}
|
|
|
|
// False path
|
|
TEST_F(SdcInitTest, MakeFalsePath) {
|
|
sta_->makeFalsePath(nullptr, nullptr, nullptr, MinMaxAll::all(), nullptr);
|
|
}
|
|
|
|
// Group path
|
|
TEST_F(SdcInitTest, MakeGroupPath) {
|
|
sta_->makeGroupPath("test_group", false, nullptr, nullptr, nullptr, nullptr);
|
|
EXPECT_TRUE(sta_->isPathGroupName("test_group"));
|
|
}
|
|
|
|
// Latch borrow limit
|
|
TEST_F(SdcInitTest, LatchBorrowLimitClock) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("lbl_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("lbl_clk");
|
|
sta_->setLatchBorrowLimit(clk, 2.0);
|
|
}
|
|
|
|
// Min pulse width with clock
|
|
TEST_F(SdcInitTest, MinPulseWidthClock) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("mpw_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("mpw_clk");
|
|
sta_->setMinPulseWidth(clk, RiseFallBoth::riseFall(), 1.0);
|
|
}
|
|
|
|
// Slew limit on clock
|
|
TEST_F(SdcInitTest, SlewLimitClock) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("sl_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("sl_clk");
|
|
sta_->setSlewLimit(clk, RiseFallBoth::riseFall(),
|
|
PathClkOrData::clk, MinMax::max(), 2.0);
|
|
}
|
|
|
|
// DisabledPorts class
|
|
TEST_F(SdcInitTest, DisabledPortsObject) {
|
|
DisabledPorts dp;
|
|
EXPECT_FALSE(dp.all());
|
|
dp.setDisabledAll();
|
|
EXPECT_TRUE(dp.all());
|
|
dp.removeDisabledAll();
|
|
EXPECT_FALSE(dp.all());
|
|
}
|
|
|
|
// WriteSdc on empty design throws
|
|
TEST_F(SdcInitTest, WriteSdcEmptyThrows) {
|
|
EXPECT_THROW(sta_->writeSdc("/dev/null", false, false, 4, false, false),
|
|
std::exception);
|
|
}
|
|
|
|
// Operating conditions
|
|
TEST_F(SdcInitTest, SdcOperatingConditions) {
|
|
Sdc *sdc = sta_->sdc();
|
|
// No operating conditions set
|
|
const OperatingConditions *op_min = sdc->operatingConditions(MinMax::min());
|
|
const OperatingConditions *op_max = sdc->operatingConditions(MinMax::max());
|
|
EXPECT_EQ(op_min, nullptr);
|
|
EXPECT_EQ(op_max, nullptr);
|
|
}
|
|
|
|
// Sdc analysis type changes
|
|
TEST_F(SdcInitTest, SdcAnalysisTypeChanges) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setAnalysisType(AnalysisType::single);
|
|
EXPECT_EQ(sdc->analysisType(), AnalysisType::single);
|
|
sdc->setAnalysisType(AnalysisType::bc_wc);
|
|
EXPECT_EQ(sdc->analysisType(), AnalysisType::bc_wc);
|
|
sdc->setAnalysisType(AnalysisType::ocv);
|
|
EXPECT_EQ(sdc->analysisType(), AnalysisType::ocv);
|
|
}
|
|
|
|
// Multicycle path
|
|
TEST_F(SdcInitTest, MakeMulticyclePath) {
|
|
sta_->makeMulticyclePath(nullptr, nullptr, nullptr,
|
|
MinMaxAll::all(),
|
|
true, // use_end_clk
|
|
2, // path_multiplier
|
|
nullptr);
|
|
}
|
|
|
|
// Reset path
|
|
TEST_F(SdcInitTest, ResetPath) {
|
|
sta_->resetPath(nullptr, nullptr, nullptr, MinMaxAll::all());
|
|
}
|
|
|
|
// Clock waveform details
|
|
TEST_F(SdcInitTest, ClockWaveformDetails) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(3.0);
|
|
sta_->makeClock("wave_clk", nullptr, false, 8.0, waveform, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("wave_clk");
|
|
EXPECT_NE(clk, nullptr);
|
|
EXPECT_FLOAT_EQ(clk->period(), 8.0);
|
|
|
|
// Get waveform edges
|
|
FloatSeq *edges = clk->waveform();
|
|
EXPECT_NE(edges, nullptr);
|
|
EXPECT_EQ(edges->size(), 2u);
|
|
EXPECT_FLOAT_EQ((*edges)[0], 0.0);
|
|
EXPECT_FLOAT_EQ((*edges)[1], 3.0);
|
|
}
|
|
|
|
// Clock edge access
|
|
TEST_F(SdcInitTest, ClockEdges) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("edge_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("edge_clk");
|
|
ClockEdge *rise_edge = clk->edge(RiseFall::rise());
|
|
ClockEdge *fall_edge = clk->edge(RiseFall::fall());
|
|
EXPECT_NE(rise_edge, nullptr);
|
|
EXPECT_NE(fall_edge, nullptr);
|
|
EXPECT_FLOAT_EQ(rise_edge->time(), 0.0);
|
|
EXPECT_FLOAT_EQ(fall_edge->time(), 5.0);
|
|
}
|
|
|
|
// Multiple timing derate types via Sdc
|
|
TEST_F(SdcInitTest, SdcTimingDerateAllTypes) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setTimingDerate(TimingDerateType::cell_delay,
|
|
PathClkOrData::clk,
|
|
RiseFallBoth::rise(),
|
|
EarlyLate::early(), 0.95);
|
|
sdc->setTimingDerate(TimingDerateType::cell_check,
|
|
PathClkOrData::data,
|
|
RiseFallBoth::fall(),
|
|
EarlyLate::late(), 1.05);
|
|
sdc->setTimingDerate(TimingDerateType::net_delay,
|
|
PathClkOrData::clk,
|
|
RiseFallBoth::riseFall(),
|
|
EarlyLate::early(), 0.97);
|
|
sdc->unsetTimingDerate();
|
|
}
|
|
|
|
// Multiple clocks and removal
|
|
TEST_F(SdcInitTest, MultipleClockRemoval) {
|
|
FloatSeq *w1 = new FloatSeq;
|
|
w1->push_back(0.0);
|
|
w1->push_back(5.0);
|
|
sta_->makeClock("rm_clk1", nullptr, false, 10.0, w1, nullptr);
|
|
|
|
FloatSeq *w2 = new FloatSeq;
|
|
w2->push_back(0.0);
|
|
w2->push_back(2.5);
|
|
sta_->makeClock("rm_clk2", nullptr, false, 5.0, w2, nullptr);
|
|
|
|
FloatSeq *w3 = new FloatSeq;
|
|
w3->push_back(0.0);
|
|
w3->push_back(1.0);
|
|
sta_->makeClock("rm_clk3", nullptr, false, 2.0, w3, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_EQ(sdc->clks().size(), 3u);
|
|
|
|
Clock *clk2 = sdc->findClock("rm_clk2");
|
|
sta_->removeClock(clk2);
|
|
EXPECT_EQ(sdc->clks().size(), 2u);
|
|
EXPECT_EQ(sdc->findClock("rm_clk2"), nullptr);
|
|
}
|
|
|
|
// Voltage settings via Sdc
|
|
TEST_F(SdcInitTest, SdcVoltage) {
|
|
sta_->setVoltage(MinMax::max(), 1.1);
|
|
sta_->setVoltage(MinMax::min(), 0.9);
|
|
}
|
|
|
|
// DisabledPorts fromTo
|
|
TEST_F(SdcInitTest, DisabledPortsFromTo) {
|
|
DisabledPorts dp;
|
|
// Initially empty
|
|
EXPECT_EQ(dp.from(), nullptr);
|
|
EXPECT_EQ(dp.to(), nullptr);
|
|
EXPECT_EQ(dp.fromTo(), nullptr);
|
|
EXPECT_FALSE(dp.all());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// Additional SDC tests for function coverage
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// ExceptionPath: clone, asString, typeString, tighterThan
|
|
TEST_F(SdcInitTest, FalsePathClone) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
ExceptionPath *cloned = fp.clone(nullptr, nullptr, nullptr, true);
|
|
EXPECT_NE(cloned, nullptr);
|
|
EXPECT_TRUE(cloned->isFalse());
|
|
delete cloned;
|
|
}
|
|
|
|
TEST_F(SdcInitTest, PathDelayClone) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
5.0e-9f, true, nullptr);
|
|
ExceptionPath *cloned = pd.clone(nullptr, nullptr, nullptr, true);
|
|
EXPECT_NE(cloned, nullptr);
|
|
EXPECT_TRUE(cloned->isPathDelay());
|
|
EXPECT_FLOAT_EQ(cloned->delay(), 5.0e-9f);
|
|
delete cloned;
|
|
}
|
|
|
|
TEST_F(SdcInitTest, MultiCyclePathClone) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, nullptr);
|
|
ExceptionPath *cloned = mcp.clone(nullptr, nullptr, nullptr, true);
|
|
EXPECT_NE(cloned, nullptr);
|
|
EXPECT_TRUE(cloned->isMultiCycle());
|
|
EXPECT_EQ(cloned->pathMultiplier(), 3);
|
|
delete cloned;
|
|
}
|
|
|
|
TEST_F(SdcInitTest, GroupPathClone) {
|
|
GroupPath gp("grp", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
ExceptionPath *cloned = gp.clone(nullptr, nullptr, nullptr, true);
|
|
EXPECT_NE(cloned, nullptr);
|
|
EXPECT_TRUE(cloned->isGroupPath());
|
|
EXPECT_STREQ(cloned->name(), "grp");
|
|
delete cloned;
|
|
}
|
|
|
|
TEST_F(SdcInitTest, FilterPathClone) {
|
|
FilterPath flp(nullptr, nullptr, nullptr, true);
|
|
ExceptionPath *cloned = flp.clone(nullptr, nullptr, nullptr, true);
|
|
EXPECT_NE(cloned, nullptr);
|
|
EXPECT_TRUE(cloned->isFilter());
|
|
delete cloned;
|
|
}
|
|
|
|
TEST_F(SdcInitTest, FalsePathAsString) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
const char *str = fp.asString(sta_->cmdNetwork());
|
|
EXPECT_NE(str, nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, PathDelayAsString) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
1.0e-9f, true, nullptr);
|
|
const char *str = pd.asString(sta_->cmdNetwork());
|
|
EXPECT_NE(str, nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, MultiCyclePathAsString) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 2, true, nullptr);
|
|
const char *str = mcp.asString(sta_->cmdNetwork());
|
|
EXPECT_NE(str, nullptr);
|
|
}
|
|
|
|
// ExceptionPath type predicates
|
|
TEST_F(SdcInitTest, ExceptionTypePredicates) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
EXPECT_TRUE(fp.isFalse());
|
|
EXPECT_FALSE(fp.isLoop());
|
|
EXPECT_FALSE(fp.isMultiCycle());
|
|
EXPECT_FALSE(fp.isPathDelay());
|
|
EXPECT_FALSE(fp.isGroupPath());
|
|
EXPECT_FALSE(fp.isFilter());
|
|
EXPECT_EQ(fp.type(), ExceptionPathType::false_path);
|
|
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
1.0e-9f, true, nullptr);
|
|
EXPECT_TRUE(pd.isPathDelay());
|
|
EXPECT_FALSE(pd.isFalse());
|
|
EXPECT_EQ(pd.type(), ExceptionPathType::path_delay);
|
|
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 2, true, nullptr);
|
|
EXPECT_TRUE(mcp.isMultiCycle());
|
|
EXPECT_EQ(mcp.type(), ExceptionPathType::multi_cycle);
|
|
|
|
FilterPath flp(nullptr, nullptr, nullptr, true);
|
|
EXPECT_TRUE(flp.isFilter());
|
|
EXPECT_EQ(flp.type(), ExceptionPathType::filter);
|
|
|
|
GroupPath gp("g", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
EXPECT_TRUE(gp.isGroupPath());
|
|
EXPECT_EQ(gp.type(), ExceptionPathType::group_path);
|
|
}
|
|
|
|
// ExceptionPath tighterThan
|
|
TEST_F(SdcInitTest, FalsePathTighterThan) {
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
EXPECT_FALSE(fp1.tighterThan(&fp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, PathDelayTighterThan) {
|
|
PathDelay pd1(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
5.0e-9f, true, nullptr);
|
|
PathDelay pd2(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
10.0e-9f, true, nullptr);
|
|
// Smaller delay is tighter for max
|
|
EXPECT_TRUE(pd1.tighterThan(&pd2));
|
|
EXPECT_FALSE(pd2.tighterThan(&pd1));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, MultiCyclePathTighterThan) {
|
|
MultiCyclePath mcp1(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 2, true, nullptr);
|
|
MultiCyclePath mcp2(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 5, true, nullptr);
|
|
EXPECT_TRUE(mcp1.tighterThan(&mcp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, FilterPathTighterThan) {
|
|
FilterPath flp1(nullptr, nullptr, nullptr, true);
|
|
FilterPath flp2(nullptr, nullptr, nullptr, true);
|
|
EXPECT_FALSE(flp1.tighterThan(&flp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, GroupPathTighterThan) {
|
|
GroupPath gp1("g1", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
GroupPath gp2("g2", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
EXPECT_FALSE(gp1.tighterThan(&gp2));
|
|
}
|
|
|
|
// ExceptionPath typePriority
|
|
TEST_F(SdcInitTest, ExceptionTypePriority) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
EXPECT_EQ(fp.typePriority(), ExceptionPath::falsePathPriority());
|
|
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
1.0e-9f, true, nullptr);
|
|
EXPECT_EQ(pd.typePriority(), ExceptionPath::pathDelayPriority());
|
|
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 2, true, nullptr);
|
|
EXPECT_EQ(mcp.typePriority(), ExceptionPath::multiCyclePathPriority());
|
|
|
|
FilterPath flp(nullptr, nullptr, nullptr, true);
|
|
EXPECT_EQ(flp.typePriority(), ExceptionPath::filterPathPriority());
|
|
|
|
GroupPath gp("g", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
EXPECT_EQ(gp.typePriority(), ExceptionPath::groupPathPriority());
|
|
}
|
|
|
|
// LoopPath
|
|
TEST_F(SdcInitTest, LoopPathBasic) {
|
|
LoopPath lp(nullptr, true);
|
|
EXPECT_TRUE(lp.isFalse());
|
|
EXPECT_TRUE(lp.isLoop());
|
|
EXPECT_EQ(lp.type(), ExceptionPathType::loop);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, LoopPathMergeable) {
|
|
LoopPath lp1(nullptr, true);
|
|
LoopPath lp2(nullptr, true);
|
|
// LoopPaths are not mergeable
|
|
EXPECT_FALSE(lp1.mergeable(&lp2));
|
|
}
|
|
|
|
// ExceptionPath setId and priority
|
|
TEST_F(SdcInitTest, ExceptionPathSetIdPriority) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
fp.setId(42);
|
|
EXPECT_EQ(fp.id(), 42u);
|
|
fp.setPriority(5000);
|
|
EXPECT_EQ(fp.priority(), 5000);
|
|
}
|
|
|
|
// ExceptionPath default handlers
|
|
TEST_F(SdcInitTest, ExceptionPathDefaultHandlers) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
EXPECT_FALSE(fp.useEndClk());
|
|
EXPECT_EQ(fp.pathMultiplier(), 0);
|
|
EXPECT_FLOAT_EQ(fp.delay(), 0.0f);
|
|
EXPECT_EQ(fp.name(), nullptr);
|
|
EXPECT_FALSE(fp.isDefault());
|
|
EXPECT_FALSE(fp.ignoreClkLatency());
|
|
EXPECT_FALSE(fp.breakPath());
|
|
}
|
|
|
|
// PathDelay ignoreClkLatency and breakPath
|
|
TEST_F(SdcInitTest, PathDelayIgnoreAndBreak) {
|
|
PathDelay pd1(nullptr, nullptr, nullptr, MinMax::max(), true, true,
|
|
1.0e-9f, true, nullptr);
|
|
EXPECT_TRUE(pd1.ignoreClkLatency());
|
|
EXPECT_TRUE(pd1.breakPath());
|
|
|
|
PathDelay pd2(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
1.0e-9f, true, nullptr);
|
|
EXPECT_FALSE(pd2.ignoreClkLatency());
|
|
EXPECT_FALSE(pd2.breakPath());
|
|
}
|
|
|
|
// MultiCyclePath priority with MinMax
|
|
TEST_F(SdcInitTest, MultiCyclePathPriorityWithMinMax) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, nullptr);
|
|
int p_min = mcp.priority(MinMax::min());
|
|
int p_max = mcp.priority(MinMax::max());
|
|
EXPECT_GE(p_min, 0);
|
|
EXPECT_GE(p_max, 0);
|
|
}
|
|
|
|
// MultiCyclePath pathMultiplier with MinMax
|
|
TEST_F(SdcInitTest, MultiCyclePathMultiplierWithMinMax) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 4, true, nullptr);
|
|
EXPECT_EQ(mcp.pathMultiplier(MinMax::max()), 4);
|
|
}
|
|
|
|
// MultiCyclePath matches min_max exactly
|
|
TEST_F(SdcInitTest, MultiCyclePathMatchesExact) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::min(),
|
|
true, 3, true, nullptr);
|
|
EXPECT_TRUE(mcp.matches(MinMax::min(), true));
|
|
EXPECT_FALSE(mcp.matches(MinMax::max(), true));
|
|
}
|
|
|
|
// GroupPath isDefault
|
|
TEST_F(SdcInitTest, GroupPathIsDefault) {
|
|
GroupPath gp1("reg", true, nullptr, nullptr, nullptr, true, nullptr);
|
|
EXPECT_TRUE(gp1.isDefault());
|
|
GroupPath gp2("cust", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
EXPECT_FALSE(gp2.isDefault());
|
|
}
|
|
|
|
// FilterPath overrides always returns false
|
|
TEST_F(SdcInitTest, FilterPathOverrides) {
|
|
FilterPath flp1(nullptr, nullptr, nullptr, true);
|
|
FilterPath flp2(nullptr, nullptr, nullptr, true);
|
|
EXPECT_FALSE(flp1.overrides(&flp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, FilterPathNotOverridesDifferent) {
|
|
FilterPath flp(nullptr, nullptr, nullptr, true);
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
EXPECT_FALSE(flp.overrides(&fp));
|
|
}
|
|
|
|
// FilterPath mergeable always returns false
|
|
TEST_F(SdcInitTest, FilterPathMergeable) {
|
|
FilterPath flp1(nullptr, nullptr, nullptr, true);
|
|
FilterPath flp2(nullptr, nullptr, nullptr, true);
|
|
EXPECT_FALSE(flp1.mergeable(&flp2));
|
|
}
|
|
|
|
// ExceptionPtIterator
|
|
TEST_F(SdcInitTest, ExceptionPtIteratorNoPoints) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
ExceptionPtIterator iter(&fp);
|
|
EXPECT_FALSE(iter.hasNext());
|
|
}
|
|
|
|
// ExceptionPath from/thrus/to accessors
|
|
TEST_F(SdcInitTest, ExceptionPathAccessors) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
EXPECT_EQ(fp.from(), nullptr);
|
|
EXPECT_EQ(fp.thrus(), nullptr);
|
|
EXPECT_EQ(fp.to(), nullptr);
|
|
EXPECT_EQ(fp.minMax(), MinMaxAll::all());
|
|
}
|
|
|
|
// ExceptionPath firstPt with no points
|
|
TEST_F(SdcInitTest, ExceptionPathFirstPtNull) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
EXPECT_EQ(fp.firstPt(), nullptr);
|
|
}
|
|
|
|
// EmptyExpceptionPt exception
|
|
TEST_F(SdcInitTest, EmptyExceptionPtWhat) {
|
|
EmptyExpceptionPt e;
|
|
EXPECT_NE(e.what(), nullptr);
|
|
}
|
|
|
|
// InputDrive tests
|
|
TEST_F(SdcInitTest, InputDriveDefault) {
|
|
InputDrive drive;
|
|
float slew;
|
|
bool exists;
|
|
drive.slew(RiseFall::rise(), MinMax::max(), slew, exists);
|
|
EXPECT_FALSE(exists);
|
|
|
|
float res;
|
|
drive.driveResistance(RiseFall::rise(), MinMax::max(), res, exists);
|
|
EXPECT_FALSE(exists);
|
|
|
|
EXPECT_FALSE(drive.hasDriveResistance(RiseFall::rise(), MinMax::max()));
|
|
EXPECT_FALSE(drive.hasDriveCell(RiseFall::rise(), MinMax::max()));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, InputDriveSetSlew) {
|
|
InputDrive drive;
|
|
drive.setSlew(RiseFallBoth::riseFall(), MinMaxAll::all(), 0.5);
|
|
float slew;
|
|
bool exists;
|
|
drive.slew(RiseFall::rise(), MinMax::max(), slew, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(slew, 0.5f);
|
|
drive.slew(RiseFall::fall(), MinMax::min(), slew, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(slew, 0.5f);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, InputDriveSetResistance) {
|
|
InputDrive drive;
|
|
drive.setDriveResistance(RiseFallBoth::riseFall(), MinMaxAll::all(), 100.0);
|
|
float res;
|
|
bool exists;
|
|
drive.driveResistance(RiseFall::rise(), MinMax::max(), res, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(res, 100.0f);
|
|
EXPECT_TRUE(drive.hasDriveResistance(RiseFall::rise(), MinMax::max()));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, InputDriveResistanceMinMaxEqual) {
|
|
InputDrive drive;
|
|
drive.setDriveResistance(RiseFallBoth::rise(), MinMaxAll::all(), 100.0);
|
|
EXPECT_TRUE(drive.driveResistanceMinMaxEqual(RiseFall::rise()));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, InputDriveSlews) {
|
|
InputDrive drive;
|
|
drive.setSlew(RiseFallBoth::riseFall(), MinMaxAll::all(), 0.3);
|
|
const RiseFallMinMax *slews = drive.slews();
|
|
EXPECT_NE(slews, nullptr);
|
|
EXPECT_FALSE(slews->empty());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, InputDriveDriveCellsEqual) {
|
|
InputDrive drive;
|
|
// Set the same drive cell for all rise/fall min/max
|
|
float from_slews[2] = {0.1f, 0.2f};
|
|
drive.setDriveCell(nullptr, nullptr, nullptr, from_slews, nullptr,
|
|
RiseFallBoth::riseFall(), MinMaxAll::all());
|
|
EXPECT_TRUE(drive.driveCellsEqual());
|
|
}
|
|
|
|
// InputDriveCell tests
|
|
TEST_F(SdcInitTest, InputDriveCellAccessors) {
|
|
float from_slews[2] = {0.1f, 0.2f};
|
|
InputDriveCell dc(nullptr, nullptr, nullptr, from_slews, nullptr);
|
|
EXPECT_EQ(dc.library(), nullptr);
|
|
EXPECT_EQ(dc.cell(), nullptr);
|
|
EXPECT_EQ(dc.fromPort(), nullptr);
|
|
EXPECT_EQ(dc.toPort(), nullptr);
|
|
float *slews = dc.fromSlews();
|
|
EXPECT_NE(slews, nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, InputDriveCellSetters) {
|
|
float from_slews[2] = {0.1f, 0.2f};
|
|
InputDriveCell dc(nullptr, nullptr, nullptr, from_slews, nullptr);
|
|
dc.setLibrary(nullptr);
|
|
dc.setCell(nullptr);
|
|
dc.setFromPort(nullptr);
|
|
dc.setToPort(nullptr);
|
|
float new_slews[2] = {0.3f, 0.4f};
|
|
dc.setFromSlews(new_slews);
|
|
EXPECT_FLOAT_EQ(dc.fromSlews()[0], 0.3f);
|
|
EXPECT_FLOAT_EQ(dc.fromSlews()[1], 0.4f);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, InputDriveCellEqual) {
|
|
float slews1[2] = {0.1f, 0.2f};
|
|
float slews2[2] = {0.1f, 0.2f};
|
|
InputDriveCell dc1(nullptr, nullptr, nullptr, slews1, nullptr);
|
|
InputDriveCell dc2(nullptr, nullptr, nullptr, slews2, nullptr);
|
|
EXPECT_TRUE(dc1.equal(&dc2));
|
|
}
|
|
|
|
// Sdc constraint setters/getters
|
|
TEST_F(SdcInitTest, SdcMaxArea) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setMaxArea(500.0);
|
|
EXPECT_FLOAT_EQ(sdc->maxArea(), 500.0f);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, SdcWireloadMode) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setWireloadMode(WireloadMode::top);
|
|
EXPECT_EQ(sdc->wireloadMode(), WireloadMode::top);
|
|
sdc->setWireloadMode(WireloadMode::enclosed);
|
|
EXPECT_EQ(sdc->wireloadMode(), WireloadMode::enclosed);
|
|
sdc->setWireloadMode(WireloadMode::segmented);
|
|
EXPECT_EQ(sdc->wireloadMode(), WireloadMode::segmented);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, SdcMinPulseWidthGlobal) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setMinPulseWidth(RiseFallBoth::rise(), 0.5);
|
|
sdc->setMinPulseWidth(RiseFallBoth::fall(), 0.3);
|
|
}
|
|
|
|
// Sdc design rule limits
|
|
TEST_F(SdcInitTest, SdcSlewLimitPort) {
|
|
Sdc *sdc = sta_->sdc();
|
|
// We can't easily create ports without a network, but we can call
|
|
// methods that don't crash with nullptr
|
|
// Instead test clock slew limits
|
|
FloatSeq *wave = new FloatSeq;
|
|
wave->push_back(0.0);
|
|
wave->push_back(5.0);
|
|
sta_->makeClock("sl_test_clk", nullptr, false, 10.0, wave, nullptr);
|
|
Clock *clk = sdc->findClock("sl_test_clk");
|
|
sdc->setSlewLimit(clk, RiseFallBoth::riseFall(), PathClkOrData::clk,
|
|
MinMax::max(), 2.0);
|
|
EXPECT_TRUE(sdc->haveClkSlewLimits());
|
|
float slew;
|
|
bool exists;
|
|
sdc->slewLimit(clk, RiseFall::rise(), PathClkOrData::clk,
|
|
MinMax::max(), slew, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(slew, 2.0f);
|
|
}
|
|
|
|
// Clock: waveformInvalid (invalidation function), period
|
|
TEST_F(SdcInitTest, ClockPeriodAfterCreate) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("sp_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("sp_clk");
|
|
EXPECT_FLOAT_EQ(clk->period(), 10.0);
|
|
// waveformInvalid() invalidates cached waveform data - just call it
|
|
clk->waveformInvalid();
|
|
}
|
|
|
|
TEST_F(SdcInitTest, ClockWaveformInvalid) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("wi_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("wi_clk");
|
|
EXPECT_TRUE(clk->waveformValid());
|
|
clk->waveformInvalid();
|
|
EXPECT_FALSE(clk->waveformValid());
|
|
}
|
|
|
|
// Clock: setAddToPins
|
|
TEST_F(SdcInitTest, ClockSetAddToPins) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("atp_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("atp_clk");
|
|
clk->setAddToPins(true);
|
|
EXPECT_TRUE(clk->addToPins());
|
|
clk->setAddToPins(false);
|
|
EXPECT_FALSE(clk->addToPins());
|
|
}
|
|
|
|
// Clock: isIdeal, isGenerated
|
|
TEST_F(SdcInitTest, ClockIdealGenerated) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("ig_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("ig_clk");
|
|
EXPECT_TRUE(clk->isIdeal());
|
|
EXPECT_FALSE(clk->isGenerated());
|
|
}
|
|
|
|
// Clock: index
|
|
TEST_F(SdcInitTest, ClockIndex) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("idx_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("idx_clk");
|
|
EXPECT_GE(clk->index(), 0);
|
|
}
|
|
|
|
// ClockEdge: transition, opposite, name, index, pulseWidth
|
|
TEST_F(SdcInitTest, ClockEdgeDetails) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("ced_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("ced_clk");
|
|
ClockEdge *rise = clk->edge(RiseFall::rise());
|
|
ClockEdge *fall = clk->edge(RiseFall::fall());
|
|
|
|
EXPECT_EQ(rise->transition(), RiseFall::rise());
|
|
EXPECT_EQ(fall->transition(), RiseFall::fall());
|
|
EXPECT_EQ(rise->opposite(), fall);
|
|
EXPECT_EQ(fall->opposite(), rise);
|
|
EXPECT_NE(rise->name(), nullptr);
|
|
EXPECT_NE(fall->name(), nullptr);
|
|
EXPECT_GE(rise->index(), 0);
|
|
EXPECT_GE(fall->index(), 0);
|
|
EXPECT_NE(rise->index(), fall->index());
|
|
EXPECT_FLOAT_EQ(rise->pulseWidth(), 5.0);
|
|
EXPECT_FLOAT_EQ(fall->pulseWidth(), 5.0);
|
|
EXPECT_EQ(rise->clock(), clk);
|
|
}
|
|
|
|
// Clock: setSlew/slew
|
|
TEST_F(SdcInitTest, ClockSlewSetGet) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("csl_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("csl_clk");
|
|
clk->setSlew(RiseFallBoth::riseFall(), MinMaxAll::all(), 0.5);
|
|
float slew;
|
|
bool exists;
|
|
clk->slew(RiseFall::rise(), MinMax::max(), slew, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(slew, 0.5f);
|
|
// slew with no exists parameter
|
|
float slew2 = clk->slew(RiseFall::fall(), MinMax::min());
|
|
EXPECT_FLOAT_EQ(slew2, 0.5f);
|
|
// slews() accessor
|
|
const RiseFallMinMax &slews = clk->slews();
|
|
EXPECT_FALSE(slews.empty());
|
|
// removeSlew
|
|
clk->removeSlew();
|
|
clk->slew(RiseFall::rise(), MinMax::max(), slew, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
// Clock: uncertainty setters/getters
|
|
TEST_F(SdcInitTest, ClockUncertaintySetGet) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("cu_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("cu_clk");
|
|
clk->setUncertainty(SetupHoldAll::all(), 0.1);
|
|
float unc;
|
|
bool exists;
|
|
clk->uncertainty(SetupHold::max(), unc, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(unc, 0.1f);
|
|
clk->removeUncertainty(SetupHoldAll::all());
|
|
clk->uncertainty(SetupHold::max(), unc, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
// Clock: setSlewLimit and slewLimit
|
|
TEST_F(SdcInitTest, ClockSlewLimitSetGet) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("csl2_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("csl2_clk");
|
|
clk->setSlewLimit(RiseFallBoth::riseFall(), PathClkOrData::clk,
|
|
MinMax::max(), 1.5);
|
|
float slew;
|
|
bool exists;
|
|
clk->slewLimit(RiseFall::rise(), PathClkOrData::clk,
|
|
MinMax::max(), slew, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(slew, 1.5f);
|
|
}
|
|
|
|
// Sdc: findClocksMatching
|
|
TEST_F(SdcInitTest, SdcFindClocksMatching) {
|
|
FloatSeq *wave = new FloatSeq;
|
|
wave->push_back(0.0);
|
|
wave->push_back(5.0);
|
|
sta_->makeClock("match_clk1", nullptr, false, 10.0, wave, nullptr);
|
|
|
|
FloatSeq *wave2 = new FloatSeq;
|
|
wave2->push_back(0.0);
|
|
wave2->push_back(2.5);
|
|
sta_->makeClock("match_clk2", nullptr, false, 5.0, wave2, nullptr);
|
|
|
|
FloatSeq *wave3 = new FloatSeq;
|
|
wave3->push_back(0.0);
|
|
wave3->push_back(1.0);
|
|
sta_->makeClock("other_clk", nullptr, false, 2.0, wave3, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
PatternMatch pattern("match_*");
|
|
ClockSeq matches = sdc->findClocksMatching(&pattern);
|
|
EXPECT_EQ(matches.size(), 2u);
|
|
}
|
|
|
|
// Sdc: sortedClocks
|
|
TEST_F(SdcInitTest, SdcSortedClocks) {
|
|
FloatSeq *wave1 = new FloatSeq;
|
|
wave1->push_back(0.0);
|
|
wave1->push_back(5.0);
|
|
sta_->makeClock("b_clk", nullptr, false, 10.0, wave1, nullptr);
|
|
|
|
FloatSeq *wave2 = new FloatSeq;
|
|
wave2->push_back(0.0);
|
|
wave2->push_back(2.5);
|
|
sta_->makeClock("a_clk", nullptr, false, 5.0, wave2, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
ClockSeq sorted;
|
|
sdc->sortedClocks(sorted);
|
|
EXPECT_EQ(sorted.size(), 2u);
|
|
// Should be sorted by name: a_clk before b_clk
|
|
EXPECT_STREQ(sorted[0]->name(), "a_clk");
|
|
EXPECT_STREQ(sorted[1]->name(), "b_clk");
|
|
}
|
|
|
|
// Sdc: defaultArrivalClock
|
|
TEST_F(SdcInitTest, SdcDefaultArrivalClock) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *default_clk = sdc->defaultArrivalClock();
|
|
// Default arrival clock always exists
|
|
EXPECT_NE(default_clk, nullptr);
|
|
ClockEdge *edge = sdc->defaultArrivalClockEdge();
|
|
EXPECT_NE(edge, nullptr);
|
|
}
|
|
|
|
// Sdc: clockLatencies/clockInsertions accessors
|
|
TEST_F(SdcInitTest, SdcClockLatenciesAccessor) {
|
|
Sdc *sdc = sta_->sdc();
|
|
auto *latencies = sdc->clockLatencies();
|
|
EXPECT_NE(latencies, nullptr);
|
|
const auto *const_latencies = static_cast<const Sdc*>(sdc)->clockLatencies();
|
|
EXPECT_NE(const_latencies, nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, SdcClockInsertionsAccessor) {
|
|
Sdc *sdc = sta_->sdc();
|
|
const auto &insertions = sdc->clockInsertions();
|
|
// Initially empty
|
|
EXPECT_TRUE(insertions.empty());
|
|
}
|
|
|
|
// Sdc: pathDelaysWithoutTo
|
|
TEST_F(SdcInitTest, SdcPathDelaysWithoutTo) {
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_FALSE(sdc->pathDelaysWithoutTo());
|
|
}
|
|
|
|
// Sdc: exceptions accessor
|
|
TEST_F(SdcInitTest, SdcExceptionsAccessor) {
|
|
Sdc *sdc = sta_->sdc();
|
|
auto &exceptions = sdc->exceptions();
|
|
// Initially empty
|
|
EXPECT_TRUE(exceptions.empty());
|
|
}
|
|
|
|
// Sdc: groupPaths accessor
|
|
TEST_F(SdcInitTest, SdcGroupPathsAccessor) {
|
|
Sdc *sdc = sta_->sdc();
|
|
auto &gp = sdc->groupPaths();
|
|
EXPECT_TRUE(gp.empty());
|
|
|
|
sta_->makeGroupPath("test_grp", false, nullptr, nullptr, nullptr, nullptr);
|
|
EXPECT_FALSE(sdc->groupPaths().empty());
|
|
}
|
|
|
|
// Sdc: netResistances
|
|
TEST_F(SdcInitTest, SdcNetResistancesAccessor) {
|
|
Sdc *sdc = sta_->sdc();
|
|
auto &res = sdc->netResistances();
|
|
EXPECT_TRUE(res.empty());
|
|
}
|
|
|
|
// Sdc: disabledPins/Ports/LibPorts/Edges accessors
|
|
TEST_F(SdcInitTest, SdcDisabledAccessors) {
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_NE(sdc->disabledPins(), nullptr);
|
|
EXPECT_NE(sdc->disabledPorts(), nullptr);
|
|
EXPECT_NE(sdc->disabledLibPorts(), nullptr);
|
|
EXPECT_NE(sdc->disabledEdges(), nullptr);
|
|
EXPECT_NE(sdc->disabledCellPorts(), nullptr);
|
|
EXPECT_NE(sdc->disabledInstancePorts(), nullptr);
|
|
}
|
|
|
|
// Sdc: logicValues/caseLogicValues
|
|
TEST_F(SdcInitTest, SdcLogicValueMaps) {
|
|
Sdc *sdc = sta_->sdc();
|
|
auto &lv = sdc->logicValues();
|
|
EXPECT_TRUE(lv.empty());
|
|
auto &cv = sdc->caseLogicValues();
|
|
EXPECT_TRUE(cv.empty());
|
|
}
|
|
|
|
// Sdc: inputDelays/outputDelays
|
|
TEST_F(SdcInitTest, SdcPortDelayAccessors) {
|
|
Sdc *sdc = sta_->sdc();
|
|
const auto &inputs = sdc->inputDelays();
|
|
EXPECT_TRUE(inputs.empty());
|
|
const auto &outputs = sdc->outputDelays();
|
|
EXPECT_TRUE(outputs.empty());
|
|
const auto &input_pin_map = sdc->inputDelayPinMap();
|
|
EXPECT_TRUE(input_pin_map.empty());
|
|
const auto &output_pin_map = sdc->outputDelaysPinMap();
|
|
EXPECT_TRUE(output_pin_map.empty());
|
|
}
|
|
|
|
// Sdc: makeExceptionFrom/Thru/To - returns nullptr with empty sets
|
|
TEST_F(SdcInitTest, SdcMakeExceptionFromThruTo) {
|
|
Sdc *sdc = sta_->sdc();
|
|
// With all null/empty sets, these return nullptr
|
|
ExceptionFrom *from = sdc->makeExceptionFrom(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::riseFall());
|
|
EXPECT_EQ(from, nullptr);
|
|
|
|
ExceptionThru *thru = sdc->makeExceptionThru(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::riseFall());
|
|
EXPECT_EQ(thru, nullptr);
|
|
|
|
ExceptionTo *to = sdc->makeExceptionTo(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(),
|
|
RiseFallBoth::riseFall());
|
|
EXPECT_EQ(to, nullptr);
|
|
}
|
|
|
|
// Sdc: makePathDelay
|
|
TEST_F(SdcInitTest, SdcMakePathDelay) {
|
|
sta_->makePathDelay(nullptr, nullptr, nullptr,
|
|
MinMax::max(), false, false, 5.0e-9, nullptr);
|
|
}
|
|
|
|
// Sdc: removeClockGroupsPhysicallyExclusive/Asynchronous
|
|
TEST_F(SdcInitTest, SdcRemoveClockGroupsOther) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->removeClockGroupsPhysicallyExclusive(nullptr);
|
|
sdc->removeClockGroupsAsynchronous(nullptr);
|
|
}
|
|
|
|
// Sdc: sameClockGroup
|
|
TEST_F(SdcInitTest, SdcSameClockGroup) {
|
|
FloatSeq *wave1 = new FloatSeq;
|
|
wave1->push_back(0.0);
|
|
wave1->push_back(5.0);
|
|
sta_->makeClock("scg_clk1", nullptr, false, 10.0, wave1, nullptr);
|
|
|
|
FloatSeq *wave2 = new FloatSeq;
|
|
wave2->push_back(0.0);
|
|
wave2->push_back(2.5);
|
|
sta_->makeClock("scg_clk2", nullptr, false, 5.0, wave2, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk1 = sdc->findClock("scg_clk1");
|
|
Clock *clk2 = sdc->findClock("scg_clk2");
|
|
// Without explicit groups, clocks are in the same group
|
|
EXPECT_TRUE(sdc->sameClockGroup(clk1, clk2));
|
|
}
|
|
|
|
// Sdc: invalidateGeneratedClks
|
|
TEST_F(SdcInitTest, SdcInvalidateGeneratedClks) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->invalidateGeneratedClks();
|
|
}
|
|
|
|
// Sdc: clkHpinDisablesInvalid
|
|
TEST_F(SdcInitTest, SdcClkHpinDisablesInvalid) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->clkHpinDisablesInvalid();
|
|
}
|
|
|
|
// Sdc: deleteExceptions/searchPreamble
|
|
TEST_F(SdcInitTest, SdcDeleteExceptions) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->deleteExceptions();
|
|
}
|
|
|
|
TEST_F(SdcInitTest, SdcSearchPreamble) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->searchPreamble();
|
|
}
|
|
|
|
// Sdc: setClockGatingCheck global
|
|
TEST_F(SdcInitTest, SdcClockGatingCheckGlobal) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setClockGatingCheck(RiseFallBoth::riseFall(),
|
|
SetupHold::max(), 0.5);
|
|
}
|
|
|
|
// Sdc: clkStopPropagation with non-existent pin
|
|
TEST_F(SdcInitTest, SdcClkStopPropagation) {
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_FALSE(sdc->clkStopPropagation(nullptr, nullptr));
|
|
}
|
|
|
|
// Sdc: voltage
|
|
TEST_F(SdcInitTest, SdcVoltageGetSet) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setVoltage(MinMax::max(), 1.2);
|
|
float voltage;
|
|
bool exists;
|
|
sdc->voltage(MinMax::max(), voltage, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(voltage, 1.2f);
|
|
}
|
|
|
|
// Sdc: removeNetLoadCaps
|
|
TEST_F(SdcInitTest, SdcRemoveNetLoadCaps) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->removeNetLoadCaps();
|
|
}
|
|
|
|
// CycleAccting hash and equal functors
|
|
TEST_F(SdcInitTest, CycleAcctingFunctorsCompile) {
|
|
CycleAcctingHash hasher;
|
|
CycleAcctingEqual equal;
|
|
// Just verify they compile and can be instantiated
|
|
EXPECT_TRUE(true);
|
|
}
|
|
|
|
// clkCmp, clkEdgeCmp, clkEdgeLess
|
|
TEST_F(SdcInitTest, ClockComparisons) {
|
|
FloatSeq *wave1 = new FloatSeq;
|
|
wave1->push_back(0.0);
|
|
wave1->push_back(5.0);
|
|
sta_->makeClock("cmp_a", nullptr, false, 10.0, wave1, nullptr);
|
|
|
|
FloatSeq *wave2 = new FloatSeq;
|
|
wave2->push_back(0.0);
|
|
wave2->push_back(2.5);
|
|
sta_->makeClock("cmp_b", nullptr, false, 5.0, wave2, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clkA = sdc->findClock("cmp_a");
|
|
Clock *clkB = sdc->findClock("cmp_b");
|
|
|
|
int cmp_result = clkCmp(clkA, clkB);
|
|
EXPECT_NE(cmp_result, 0);
|
|
// Self-compare should be 0
|
|
EXPECT_EQ(clkCmp(clkA, clkA), 0);
|
|
|
|
ClockEdge *edgeA = clkA->edge(RiseFall::rise());
|
|
ClockEdge *edgeB = clkB->edge(RiseFall::rise());
|
|
int edge_cmp = clkEdgeCmp(edgeA, edgeB);
|
|
EXPECT_NE(edge_cmp, 0);
|
|
|
|
bool edge_less = clkEdgeLess(edgeA, edgeB);
|
|
bool edge_less2 = clkEdgeLess(edgeB, edgeA);
|
|
EXPECT_NE(edge_less, edge_less2);
|
|
}
|
|
|
|
// ClockNameLess
|
|
TEST_F(SdcInitTest, ClockNameLessComparison) {
|
|
FloatSeq *wave1 = new FloatSeq;
|
|
wave1->push_back(0.0);
|
|
wave1->push_back(5.0);
|
|
sta_->makeClock("alpha_clk", nullptr, false, 10.0, wave1, nullptr);
|
|
|
|
FloatSeq *wave2 = new FloatSeq;
|
|
wave2->push_back(0.0);
|
|
wave2->push_back(2.5);
|
|
sta_->makeClock("beta_clk", nullptr, false, 5.0, wave2, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *alpha = sdc->findClock("alpha_clk");
|
|
Clock *beta = sdc->findClock("beta_clk");
|
|
|
|
ClockNameLess less;
|
|
EXPECT_TRUE(less(alpha, beta));
|
|
EXPECT_FALSE(less(beta, alpha));
|
|
|
|
ClkNameLess clk_less;
|
|
EXPECT_TRUE(clk_less(alpha, beta));
|
|
EXPECT_FALSE(clk_less(beta, alpha));
|
|
}
|
|
|
|
// InterClockUncertaintyLess
|
|
TEST_F(SdcInitTest, InterClockUncertaintyLessComparison) {
|
|
FloatSeq *wave1 = new FloatSeq;
|
|
wave1->push_back(0.0);
|
|
wave1->push_back(5.0);
|
|
sta_->makeClock("icul_clk1", nullptr, false, 10.0, wave1, nullptr);
|
|
|
|
FloatSeq *wave2 = new FloatSeq;
|
|
wave2->push_back(0.0);
|
|
wave2->push_back(2.5);
|
|
sta_->makeClock("icul_clk2", nullptr, false, 5.0, wave2, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk1 = sdc->findClock("icul_clk1");
|
|
Clock *clk2 = sdc->findClock("icul_clk2");
|
|
|
|
InterClockUncertainty icu1(clk1, clk2);
|
|
InterClockUncertainty icu2(clk2, clk1);
|
|
|
|
InterClockUncertaintyLess less;
|
|
bool r1 = less(&icu1, &icu2);
|
|
bool r2 = less(&icu2, &icu1);
|
|
// Different order should give opposite results
|
|
EXPECT_NE(r1, r2);
|
|
}
|
|
|
|
// sortByName for ClockSet
|
|
TEST_F(SdcInitTest, ClockSortByName) {
|
|
FloatSeq *wave1 = new FloatSeq;
|
|
wave1->push_back(0.0);
|
|
wave1->push_back(5.0);
|
|
sta_->makeClock("zz_clk", nullptr, false, 10.0, wave1, nullptr);
|
|
|
|
FloatSeq *wave2 = new FloatSeq;
|
|
wave2->push_back(0.0);
|
|
wave2->push_back(2.5);
|
|
sta_->makeClock("aa_clk", nullptr, false, 5.0, wave2, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *zz = sdc->findClock("zz_clk");
|
|
Clock *aa = sdc->findClock("aa_clk");
|
|
|
|
ClockSet clk_set;
|
|
clk_set.insert(zz);
|
|
clk_set.insert(aa);
|
|
ClockSeq sorted = sortByName(&clk_set);
|
|
EXPECT_EQ(sorted.size(), 2u);
|
|
EXPECT_STREQ(sorted[0]->name(), "aa_clk");
|
|
EXPECT_STREQ(sorted[1]->name(), "zz_clk");
|
|
}
|
|
|
|
// logicValueString
|
|
TEST_F(SdcInitTest, LogicValueStringTest) {
|
|
char c0 = logicValueString(LogicValue::zero);
|
|
char c1 = logicValueString(LogicValue::one);
|
|
char cx = logicValueString(LogicValue::unknown);
|
|
EXPECT_EQ(c0, '0');
|
|
EXPECT_EQ(c1, '1');
|
|
EXPECT_NE(cx, '0');
|
|
EXPECT_NE(cx, '1');
|
|
}
|
|
|
|
// Sdc: makeFilterPath
|
|
TEST_F(SdcInitTest, SdcMakeFilterPath) {
|
|
Sdc *sdc = sta_->sdc();
|
|
FilterPath *fp = sdc->makeFilterPath(nullptr, nullptr, nullptr);
|
|
EXPECT_NE(fp, nullptr);
|
|
EXPECT_TRUE(fp->isFilter());
|
|
}
|
|
|
|
// FilterPath resetMatch always returns false
|
|
TEST_F(SdcInitTest, FilterPathResetMatch) {
|
|
FilterPath flp(nullptr, nullptr, nullptr, true);
|
|
bool result = flp.resetMatch(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
sta_->cmdNetwork());
|
|
EXPECT_FALSE(result);
|
|
}
|
|
|
|
// ExceptionPath hash with missing pt
|
|
TEST_F(SdcInitTest, ExceptionPathHashMissingPt) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
size_t h = fp.hash(nullptr);
|
|
EXPECT_GE(h, 0u);
|
|
}
|
|
|
|
// Clock: setSlew/slew/removeSlew
|
|
TEST_F(SdcInitTest, ClockSetSlew) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("slew_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("slew_clk");
|
|
clk->setSlew(RiseFallBoth::riseFall(), MinMaxAll::all(), 0.5);
|
|
float slew;
|
|
bool exists;
|
|
clk->slew(RiseFall::rise(), MinMax::max(), slew, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(slew, 0.5f);
|
|
clk->removeSlew();
|
|
clk->slew(RiseFall::rise(), MinMax::max(), slew, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
// Clock: setUncertainty/removeUncertainty
|
|
TEST_F(SdcInitTest, ClockSetUncertainty) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("unc_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("unc_clk");
|
|
clk->setUncertainty(MinMax::max(), 0.1f);
|
|
float unc;
|
|
bool exists;
|
|
clk->uncertainty(MinMax::max(), unc, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(unc, 0.1f);
|
|
clk->removeUncertainty(MinMaxAll::all());
|
|
clk->uncertainty(MinMax::max(), unc, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
// Clock: setSlewLimit/slewLimit
|
|
TEST_F(SdcInitTest, ClockSetSlewLimit) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("sl_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("sl_clk");
|
|
clk->setSlewLimit(RiseFallBoth::riseFall(), PathClkOrData::clk,
|
|
MinMax::max(), 1.5);
|
|
float slew;
|
|
bool exists;
|
|
clk->slewLimit(RiseFall::rise(), PathClkOrData::clk, MinMax::max(),
|
|
slew, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(slew, 1.5f);
|
|
}
|
|
|
|
// Clock: isGenerated/isIdeal
|
|
TEST_F(SdcInitTest, ClockIsGeneratedFalse) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("gen_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("gen_clk");
|
|
EXPECT_FALSE(clk->isGenerated());
|
|
}
|
|
|
|
// ClockEdge: constructor, opposite, pulseWidth, transition
|
|
TEST_F(SdcInitTest, ClockEdgeProperties) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("edge_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("edge_clk");
|
|
ClockEdge *rise_edge = clk->edge(RiseFall::rise());
|
|
ClockEdge *fall_edge = clk->edge(RiseFall::fall());
|
|
EXPECT_NE(rise_edge, nullptr);
|
|
EXPECT_NE(fall_edge, nullptr);
|
|
EXPECT_EQ(rise_edge->opposite(), fall_edge);
|
|
EXPECT_EQ(fall_edge->opposite(), rise_edge);
|
|
EXPECT_EQ(rise_edge->transition(), RiseFall::rise());
|
|
EXPECT_EQ(fall_edge->transition(), RiseFall::fall());
|
|
float pw = rise_edge->pulseWidth();
|
|
EXPECT_GT(pw, 0.0f);
|
|
}
|
|
|
|
// clkEdgeCmp/clkEdgeLess
|
|
TEST_F(SdcInitTest, ClkEdgeCmpLess) {
|
|
FloatSeq *waveform1 = new FloatSeq;
|
|
waveform1->push_back(0.0);
|
|
waveform1->push_back(2.5);
|
|
sta_->makeClock("cmp_clk1", nullptr, false, 5.0, waveform1, nullptr);
|
|
FloatSeq *waveform2 = new FloatSeq;
|
|
waveform2->push_back(0.0);
|
|
waveform2->push_back(5.0);
|
|
sta_->makeClock("cmp_clk2", nullptr, false, 10.0, waveform2, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk1 = sdc->findClock("cmp_clk1");
|
|
Clock *clk2 = sdc->findClock("cmp_clk2");
|
|
ClockEdge *e1 = clk1->edge(RiseFall::rise());
|
|
ClockEdge *e2 = clk2->edge(RiseFall::rise());
|
|
int cmp_result = clkEdgeCmp(e1, e2);
|
|
// Just verify it doesn't crash and returns a value
|
|
(void)cmp_result;
|
|
bool less_result = clkEdgeLess(e1, e2);
|
|
(void)less_result;
|
|
}
|
|
|
|
// InterClockUncertainty
|
|
TEST_F(SdcInitTest, InterClockUncertaintyOps) {
|
|
FloatSeq *waveform1 = new FloatSeq;
|
|
waveform1->push_back(0.0);
|
|
waveform1->push_back(2.5);
|
|
sta_->makeClock("icu_clk1", nullptr, false, 5.0, waveform1, nullptr);
|
|
FloatSeq *waveform2 = new FloatSeq;
|
|
waveform2->push_back(0.0);
|
|
waveform2->push_back(5.0);
|
|
sta_->makeClock("icu_clk2", nullptr, false, 10.0, waveform2, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk1 = sdc->findClock("icu_clk1");
|
|
Clock *clk2 = sdc->findClock("icu_clk2");
|
|
InterClockUncertainty icu(clk1, clk2);
|
|
EXPECT_TRUE(icu.empty());
|
|
icu.setUncertainty(RiseFallBoth::riseFall(), RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), 0.2f);
|
|
EXPECT_FALSE(icu.empty());
|
|
float val;
|
|
bool exists;
|
|
icu.uncertainty(RiseFall::rise(), RiseFall::rise(), MinMax::max(),
|
|
val, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(val, 0.2f);
|
|
const RiseFallMinMax *rfmm = icu.uncertainties(RiseFall::rise());
|
|
EXPECT_NE(rfmm, nullptr);
|
|
icu.removeUncertainty(RiseFallBoth::riseFall(), RiseFallBoth::riseFall(),
|
|
MinMaxAll::all());
|
|
icu.uncertainty(RiseFall::rise(), RiseFall::rise(), MinMax::max(),
|
|
val, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
// ExceptionPathLess comparator
|
|
TEST_F(SdcInitTest, ExceptionPathLessComparator) {
|
|
ExceptionPathLess less(sta_->cmdNetwork());
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
fp1.setId(1);
|
|
fp2.setId(2);
|
|
bool result = less(&fp1, &fp2);
|
|
(void)result;
|
|
}
|
|
|
|
// ExceptionPtIterator with thrus
|
|
TEST_F(SdcInitTest, ExceptionPtIteratorWithThrus) {
|
|
ExceptionThruSeq *thrus = new ExceptionThruSeq;
|
|
thrus->push_back(new ExceptionThru(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(), true, nullptr));
|
|
FalsePath fp(nullptr, thrus, nullptr, MinMaxAll::all(), true, nullptr);
|
|
ExceptionPtIterator iter(&fp);
|
|
int count = 0;
|
|
while (iter.hasNext()) {
|
|
ExceptionPt *pt = iter.next();
|
|
EXPECT_NE(pt, nullptr);
|
|
count++;
|
|
}
|
|
EXPECT_EQ(count, 1);
|
|
}
|
|
|
|
// ClockIndexLess
|
|
TEST_F(SdcInitTest, ClockIndexLessComparator) {
|
|
FloatSeq *waveform1 = new FloatSeq;
|
|
waveform1->push_back(0.0);
|
|
waveform1->push_back(2.5);
|
|
sta_->makeClock("idx_clk1", nullptr, false, 5.0, waveform1, nullptr);
|
|
FloatSeq *waveform2 = new FloatSeq;
|
|
waveform2->push_back(0.0);
|
|
waveform2->push_back(5.0);
|
|
sta_->makeClock("idx_clk2", nullptr, false, 10.0, waveform2, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk1 = sdc->findClock("idx_clk1");
|
|
Clock *clk2 = sdc->findClock("idx_clk2");
|
|
ClockIndexLess idx_less;
|
|
bool result = idx_less(clk1, clk2);
|
|
(void)result;
|
|
}
|
|
|
|
// DeratingFactors: setFactor/factor (no TimingDerateType param)
|
|
TEST_F(SdcInitTest, DeratingFactorsSetGet) {
|
|
DeratingFactors factors;
|
|
factors.setFactor(PathClkOrData::clk,
|
|
RiseFallBoth::riseFall(), EarlyLate::early(), 0.95f);
|
|
float val;
|
|
bool exists;
|
|
factors.factor(PathClkOrData::clk,
|
|
RiseFall::rise(), EarlyLate::early(), val, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(val, 0.95f);
|
|
EXPECT_TRUE(factors.hasValue());
|
|
}
|
|
|
|
// DeratingFactors: clear
|
|
TEST_F(SdcInitTest, DeratingFactorsClear) {
|
|
DeratingFactors factors;
|
|
factors.setFactor(PathClkOrData::data,
|
|
RiseFallBoth::riseFall(), EarlyLate::late(), 1.05f);
|
|
EXPECT_TRUE(factors.hasValue());
|
|
factors.clear();
|
|
}
|
|
|
|
// DeratingFactors: isOneValue with EarlyLate
|
|
TEST_F(SdcInitTest, DeratingFactorsIsOneValue) {
|
|
DeratingFactors factors;
|
|
factors.setFactor(PathClkOrData::clk,
|
|
RiseFallBoth::riseFall(), EarlyLate::early(), 1.0f);
|
|
bool is_one;
|
|
float value;
|
|
factors.isOneValue(EarlyLate::early(), is_one, value);
|
|
(void)is_one;
|
|
(void)value;
|
|
}
|
|
|
|
// DeratingFactors: isOneValue with PathClkOrData
|
|
TEST_F(SdcInitTest, DeratingFactorsIsOneValueClkData) {
|
|
DeratingFactors factors;
|
|
factors.setFactor(PathClkOrData::clk,
|
|
RiseFallBoth::riseFall(), EarlyLate::early(), 1.0f);
|
|
bool is_one;
|
|
float value;
|
|
factors.isOneValue(PathClkOrData::clk, EarlyLate::early(), is_one, value);
|
|
(void)is_one;
|
|
(void)value;
|
|
}
|
|
|
|
// DeratingFactorsGlobal: setFactor/factor
|
|
TEST_F(SdcInitTest, DeratingFactorsGlobalOps) {
|
|
DeratingFactorsGlobal factors;
|
|
factors.setFactor(TimingDerateType::cell_delay, PathClkOrData::clk,
|
|
RiseFallBoth::riseFall(), EarlyLate::early(), 1.0f);
|
|
float val;
|
|
bool exists;
|
|
factors.factor(TimingDerateType::cell_delay, PathClkOrData::clk,
|
|
RiseFall::rise(), EarlyLate::early(), val, exists);
|
|
EXPECT_TRUE(exists);
|
|
DeratingFactors *f = factors.factors(TimingDerateType::cell_delay);
|
|
EXPECT_NE(f, nullptr);
|
|
}
|
|
|
|
// DeratingFactorsGlobal: clear
|
|
TEST_F(SdcInitTest, DeratingFactorsGlobalClear) {
|
|
DeratingFactorsGlobal factors;
|
|
factors.setFactor(TimingDerateType::net_delay, PathClkOrData::data,
|
|
RiseFallBoth::riseFall(), EarlyLate::late(), 0.9f);
|
|
factors.clear();
|
|
}
|
|
|
|
// DeratingFactorsCell: setFactor/factor
|
|
TEST_F(SdcInitTest, DeratingFactorsCellOps) {
|
|
DeratingFactorsCell factors;
|
|
factors.setFactor(TimingDerateCellType::cell_delay, PathClkOrData::clk,
|
|
RiseFallBoth::riseFall(), EarlyLate::early(), 0.9f);
|
|
float val;
|
|
bool exists;
|
|
factors.factor(TimingDerateCellType::cell_delay, PathClkOrData::clk,
|
|
RiseFall::rise(), EarlyLate::early(), val, exists);
|
|
EXPECT_TRUE(exists);
|
|
DeratingFactors *f = factors.factors(TimingDerateCellType::cell_delay);
|
|
EXPECT_NE(f, nullptr);
|
|
}
|
|
|
|
// DeratingFactorsCell: isOneValue
|
|
TEST_F(SdcInitTest, DeratingFactorsCellIsOneValue) {
|
|
DeratingFactorsCell factors;
|
|
factors.setFactor(TimingDerateCellType::cell_delay, PathClkOrData::clk,
|
|
RiseFallBoth::riseFall(), EarlyLate::early(), 1.0f);
|
|
bool is_one;
|
|
float value;
|
|
factors.isOneValue(EarlyLate::early(), is_one, value);
|
|
(void)is_one;
|
|
(void)value;
|
|
}
|
|
|
|
// DeratingFactorsCell: clear
|
|
TEST_F(SdcInitTest, DeratingFactorsCellClear) {
|
|
DeratingFactorsCell factors;
|
|
factors.setFactor(TimingDerateCellType::cell_check, PathClkOrData::data,
|
|
RiseFallBoth::riseFall(), EarlyLate::late(), 1.1f);
|
|
factors.clear();
|
|
}
|
|
|
|
// DeratingFactorsNet: inherits DeratingFactors
|
|
TEST_F(SdcInitTest, DeratingFactorsNetOps) {
|
|
DeratingFactorsNet factors;
|
|
factors.setFactor(PathClkOrData::data,
|
|
RiseFallBoth::riseFall(), EarlyLate::late(), 1.1f);
|
|
EXPECT_TRUE(factors.hasValue());
|
|
}
|
|
|
|
// CycleAccting: operations
|
|
TEST_F(SdcInitTest, CycleAcctingEdges) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("ca_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("ca_clk");
|
|
ClockEdge *rise = clk->edge(RiseFall::rise());
|
|
ClockEdge *fall = clk->edge(RiseFall::fall());
|
|
CycleAccting ca(rise, fall);
|
|
EXPECT_EQ(ca.src(), rise);
|
|
EXPECT_EQ(ca.target(), fall);
|
|
EXPECT_FALSE(ca.maxCyclesExceeded());
|
|
}
|
|
|
|
// CycleAccting: findDefaultArrivalSrcDelays
|
|
TEST_F(SdcInitTest, CycleAcctingDefaultArrival) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("ca2_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("ca2_clk");
|
|
ClockEdge *rise = clk->edge(RiseFall::rise());
|
|
ClockEdge *fall = clk->edge(RiseFall::fall());
|
|
CycleAccting ca(rise, fall);
|
|
ca.findDefaultArrivalSrcDelays();
|
|
}
|
|
|
|
// CycleAcctingHash/Equal/Less
|
|
TEST_F(SdcInitTest, CycleAcctingHashEqualLess) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("cah_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("cah_clk");
|
|
ClockEdge *rise = clk->edge(RiseFall::rise());
|
|
ClockEdge *fall = clk->edge(RiseFall::fall());
|
|
CycleAccting ca1(rise, fall);
|
|
CycleAccting ca2(rise, rise);
|
|
CycleAcctingHash hash;
|
|
size_t h1 = hash(&ca1);
|
|
size_t h2 = hash(&ca2);
|
|
(void)h1; (void)h2;
|
|
CycleAcctingEqual eq;
|
|
EXPECT_TRUE(eq(&ca1, &ca1));
|
|
CycleAcctingLess less;
|
|
bool r = less(&ca1, &ca2);
|
|
(void)r;
|
|
}
|
|
|
|
// DisabledPorts constructors and methods
|
|
TEST_F(SdcInitTest, DisabledPortsConstructors) {
|
|
DisabledPorts dp;
|
|
EXPECT_FALSE(dp.all());
|
|
EXPECT_EQ(dp.from(), nullptr);
|
|
EXPECT_EQ(dp.to(), nullptr);
|
|
EXPECT_EQ(dp.fromTo(), nullptr);
|
|
}
|
|
|
|
// DisabledPorts: setDisabledAll
|
|
TEST_F(SdcInitTest, DisabledPortsSetAll) {
|
|
DisabledPorts dp;
|
|
dp.setDisabledAll();
|
|
EXPECT_TRUE(dp.all());
|
|
dp.removeDisabledAll();
|
|
EXPECT_FALSE(dp.all());
|
|
}
|
|
|
|
// PortExtCap: operations (needs Port* constructor)
|
|
TEST_F(SdcInitTest, PortExtCapSetGet) {
|
|
// Need a port to construct PortExtCap
|
|
Network *network = sta_->cmdNetwork();
|
|
// PortExtCap needs a Port*, just pass nullptr as we won't use it for lookup
|
|
PortExtCap pec(nullptr);
|
|
pec.setPinCap(0.1f, RiseFall::rise(), MinMax::max());
|
|
float cap;
|
|
bool exists;
|
|
pec.pinCap(RiseFall::rise(), MinMax::max(), cap, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(cap, 0.1f);
|
|
}
|
|
|
|
// PortExtCap: wire cap
|
|
TEST_F(SdcInitTest, PortExtCapWireCap) {
|
|
PortExtCap pec(nullptr);
|
|
pec.setWireCap(0.2f, RiseFall::fall(), MinMax::min());
|
|
float cap;
|
|
bool exists;
|
|
pec.wireCap(RiseFall::fall(), MinMax::min(), cap, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(cap, 0.2f);
|
|
}
|
|
|
|
// PortExtCap: fanout
|
|
TEST_F(SdcInitTest, PortExtCapFanout) {
|
|
PortExtCap pec(nullptr);
|
|
pec.setFanout(4, MinMax::max());
|
|
int fan;
|
|
bool exists;
|
|
pec.fanout(MinMax::max(), fan, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_EQ(fan, 4);
|
|
}
|
|
|
|
// PortExtCap: port accessor
|
|
TEST_F(SdcInitTest, PortExtCapPort) {
|
|
PortExtCap pec(nullptr);
|
|
EXPECT_EQ(pec.port(), nullptr);
|
|
}
|
|
|
|
// InputDrive: driveResistance/hasDriveResistance
|
|
TEST_F(SdcInitTest, InputDriveResistanceGetSet) {
|
|
InputDrive drive;
|
|
drive.setDriveResistance(RiseFallBoth::riseFall(), MinMaxAll::all(), 100.0f);
|
|
float res;
|
|
bool exists;
|
|
drive.driveResistance(RiseFall::rise(), MinMax::max(), res, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(res, 100.0f);
|
|
EXPECT_TRUE(drive.hasDriveResistance(RiseFall::rise(), MinMax::max()));
|
|
}
|
|
|
|
// InputDrive: slew accessor
|
|
TEST_F(SdcInitTest, InputDriveSlewGetSet) {
|
|
InputDrive drive;
|
|
drive.setSlew(RiseFallBoth::riseFall(), MinMaxAll::all(), 0.5f);
|
|
float slew;
|
|
bool exists;
|
|
drive.slew(RiseFall::rise(), MinMax::max(), slew, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(slew, 0.5f);
|
|
}
|
|
|
|
// InputDrive: setDriveCell/driveCell/hasDriveCell
|
|
TEST_F(SdcInitTest, InputDriveCellGetSet) {
|
|
InputDrive drive;
|
|
float from_slews[2] = {0.1f, 0.2f};
|
|
drive.setDriveCell(nullptr, nullptr, nullptr, from_slews, nullptr,
|
|
RiseFallBoth::riseFall(), MinMaxAll::all());
|
|
EXPECT_TRUE(drive.hasDriveCell(RiseFall::rise(), MinMax::max()));
|
|
InputDriveCell *dc = drive.driveCell(RiseFall::rise(), MinMax::max());
|
|
EXPECT_NE(dc, nullptr);
|
|
const LibertyCell *cell;
|
|
const LibertyPort *from_port;
|
|
float *slews;
|
|
const LibertyPort *to_port;
|
|
drive.driveCell(RiseFall::rise(), MinMax::max(),
|
|
cell, from_port, slews, to_port);
|
|
EXPECT_EQ(cell, nullptr);
|
|
}
|
|
|
|
// Sdc: clkHpinDisablesInvalid (unique name)
|
|
TEST_F(SdcInitTest, SdcClkHpinDisablesViaInvalid) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->clkHpinDisablesInvalid();
|
|
// exercises clkHpinDisablesInvalid
|
|
}
|
|
|
|
// Sdc: setTimingDerate (global variant)
|
|
TEST_F(SdcInitTest, SdcSetTimingDerateGlobal) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setTimingDerate(TimingDerateType::cell_delay, PathClkOrData::clk,
|
|
RiseFallBoth::riseFall(), EarlyLate::early(), 0.95f);
|
|
// exercises setTimingDerate global
|
|
}
|
|
|
|
// Sdc: unsetTimingDerate
|
|
TEST_F(SdcInitTest, SdcUnsetTimingDerate) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setTimingDerate(TimingDerateType::cell_delay, PathClkOrData::clk,
|
|
RiseFallBoth::riseFall(), EarlyLate::early(), 0.95f);
|
|
sdc->unsetTimingDerate();
|
|
}
|
|
|
|
// PinPairLess
|
|
TEST_F(SdcInitTest, PinPairLessConstruct) {
|
|
Network *network = sta_->cmdNetwork();
|
|
PinPairLess less(network);
|
|
// Just construction
|
|
}
|
|
|
|
// PinPairSet with network
|
|
TEST_F(SdcInitTest, PinPairSetConstruct) {
|
|
Network *network = sta_->cmdNetwork();
|
|
PinPairSet pps(network);
|
|
EXPECT_TRUE(pps.empty());
|
|
}
|
|
|
|
// PinPairHash with network
|
|
TEST_F(SdcInitTest, PinPairHashConstruct) {
|
|
Network *network = sta_->cmdNetwork();
|
|
PinPairHash hash(network);
|
|
// Just construction
|
|
}
|
|
|
|
// Sdc: dataChecksFrom/dataChecksTo (need Pin* arg)
|
|
TEST_F(SdcInitTest, SdcDataChecksFromNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
DataCheckSet *checks = sdc->dataChecksFrom(nullptr);
|
|
EXPECT_EQ(checks, nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, SdcDataChecksToNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
DataCheckSet *checks = sdc->dataChecksTo(nullptr);
|
|
EXPECT_EQ(checks, nullptr);
|
|
}
|
|
|
|
// Sdc: inputDelays/outputDelays
|
|
TEST_F(SdcInitTest, PortDelayMaps) {
|
|
Sdc *sdc = sta_->sdc();
|
|
const auto &id = sdc->inputDelays();
|
|
const auto &od = sdc->outputDelays();
|
|
EXPECT_TRUE(id.empty());
|
|
EXPECT_TRUE(od.empty());
|
|
}
|
|
|
|
// Sdc: clockGatingMargin global
|
|
TEST_F(SdcInitTest, SdcClockGatingMarginGlobal) {
|
|
Sdc *sdc = sta_->sdc();
|
|
bool exists;
|
|
float margin;
|
|
sdc->clockGatingMargin(RiseFall::rise(), SetupHold::max(), exists, margin);
|
|
// No crash - margin may or may not exist
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// Round 2: Deep coverage tests for uncovered SDC functions
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// Variables constructor and all setters
|
|
TEST_F(SdcInitTest, VariablesDefaultConstructor) {
|
|
Variables vars;
|
|
// Default CRPR enabled is true in OpenSTA
|
|
EXPECT_TRUE(vars.crprEnabled());
|
|
EXPECT_EQ(vars.crprMode(), CrprMode::same_pin);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, VariablesSetCrprEnabled) {
|
|
Variables vars;
|
|
vars.setCrprEnabled(true);
|
|
EXPECT_TRUE(vars.crprEnabled());
|
|
vars.setCrprEnabled(false);
|
|
EXPECT_FALSE(vars.crprEnabled());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, VariablesSetCrprMode) {
|
|
Variables vars;
|
|
vars.setCrprMode(CrprMode::same_transition);
|
|
EXPECT_EQ(vars.crprMode(), CrprMode::same_transition);
|
|
vars.setCrprMode(CrprMode::same_pin);
|
|
EXPECT_EQ(vars.crprMode(), CrprMode::same_pin);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, VariablesSetPropagateGatedClockEnable) {
|
|
Variables vars;
|
|
vars.setPropagateGatedClockEnable(true);
|
|
EXPECT_TRUE(vars.propagateGatedClockEnable());
|
|
vars.setPropagateGatedClockEnable(false);
|
|
EXPECT_FALSE(vars.propagateGatedClockEnable());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, VariablesSetPresetClrArcsEnabled) {
|
|
Variables vars;
|
|
vars.setPresetClrArcsEnabled(true);
|
|
EXPECT_TRUE(vars.presetClrArcsEnabled());
|
|
vars.setPresetClrArcsEnabled(false);
|
|
EXPECT_FALSE(vars.presetClrArcsEnabled());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, VariablesSetCondDefaultArcsEnabled) {
|
|
Variables vars;
|
|
vars.setCondDefaultArcsEnabled(true);
|
|
EXPECT_TRUE(vars.condDefaultArcsEnabled());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, VariablesSetBidirectInstPathsEnabled) {
|
|
Variables vars;
|
|
vars.setBidirectInstPathsEnabled(true);
|
|
EXPECT_TRUE(vars.bidirectInstPathsEnabled());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, VariablesSetBidirectNetPathsEnabled) {
|
|
Variables vars;
|
|
vars.setBidirectNetPathsEnabled(true);
|
|
EXPECT_TRUE(vars.bidirectNetPathsEnabled());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, VariablesSetRecoveryRemovalChecksEnabled) {
|
|
Variables vars;
|
|
vars.setRecoveryRemovalChecksEnabled(true);
|
|
EXPECT_TRUE(vars.recoveryRemovalChecksEnabled());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, VariablesSetGatedClkChecksEnabled) {
|
|
Variables vars;
|
|
vars.setGatedClkChecksEnabled(true);
|
|
EXPECT_TRUE(vars.gatedClkChecksEnabled());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, VariablesSetDynamicLoopBreaking) {
|
|
Variables vars;
|
|
vars.setDynamicLoopBreaking(true);
|
|
EXPECT_TRUE(vars.dynamicLoopBreaking());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, VariablesSetPropagateAllClocks) {
|
|
Variables vars;
|
|
vars.setPropagateAllClocks(true);
|
|
EXPECT_TRUE(vars.propagateAllClocks());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, VariablesSetClkThruTristateEnabled) {
|
|
Variables vars;
|
|
vars.setClkThruTristateEnabled(true);
|
|
EXPECT_TRUE(vars.clkThruTristateEnabled());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, VariablesSetUseDefaultArrivalClock) {
|
|
Variables vars;
|
|
vars.setUseDefaultArrivalClock(true);
|
|
EXPECT_TRUE(vars.useDefaultArrivalClock());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, VariablesSetPocvEnabled) {
|
|
Variables vars;
|
|
vars.setPocvEnabled(true);
|
|
EXPECT_TRUE(vars.pocvEnabled());
|
|
}
|
|
|
|
// DeratingFactors deeper coverage
|
|
TEST_F(SdcInitTest, DeratingFactorsConstructAndSet) {
|
|
DeratingFactors df;
|
|
df.setFactor(PathClkOrData::clk, RiseFallBoth::riseFall(),
|
|
EarlyLate::early(), 0.95f);
|
|
float val;
|
|
bool exists;
|
|
df.factor(PathClkOrData::clk, RiseFall::rise(), EarlyLate::early(),
|
|
val, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(val, 0.95f);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, DeratingFactorsHasValue) {
|
|
DeratingFactors df;
|
|
EXPECT_FALSE(df.hasValue());
|
|
df.setFactor(PathClkOrData::data, RiseFallBoth::rise(),
|
|
EarlyLate::late(), 1.05f);
|
|
EXPECT_TRUE(df.hasValue());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, DeratingFactorsIsOneValueMinMax) {
|
|
DeratingFactors df;
|
|
df.setFactor(PathClkOrData::clk, RiseFallBoth::riseFall(),
|
|
EarlyLate::early(), 0.95f);
|
|
bool one_value;
|
|
float val;
|
|
df.isOneValue(EarlyLate::early(), one_value, val);
|
|
}
|
|
|
|
// DeratingFactorsGlobal
|
|
TEST_F(SdcInitTest, DeratingFactorsGlobalConstAndSet) {
|
|
DeratingFactorsGlobal dfg;
|
|
dfg.setFactor(TimingDerateType::cell_delay, PathClkOrData::clk,
|
|
RiseFallBoth::riseFall(), EarlyLate::early(), 0.92f);
|
|
float val;
|
|
bool exists;
|
|
dfg.factor(TimingDerateType::cell_delay, PathClkOrData::clk,
|
|
RiseFall::rise(), EarlyLate::early(), val, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(val, 0.92f);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, DeratingFactorsGlobalFactors) {
|
|
DeratingFactorsGlobal dfg;
|
|
DeratingFactors *f = dfg.factors(TimingDerateType::cell_delay);
|
|
EXPECT_NE(f, nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, DeratingFactorsGlobalCellTypeOverload) {
|
|
DeratingFactorsGlobal dfg;
|
|
// Set via cell type overload
|
|
dfg.setFactor(TimingDerateType::cell_delay, PathClkOrData::clk,
|
|
RiseFallBoth::riseFall(), EarlyLate::early(), 0.9f);
|
|
float val;
|
|
bool exists;
|
|
dfg.factor(TimingDerateCellType::cell_delay, PathClkOrData::clk,
|
|
RiseFall::rise(), EarlyLate::early(), val, exists);
|
|
EXPECT_TRUE(exists);
|
|
}
|
|
|
|
// DeratingFactorsCell
|
|
TEST_F(SdcInitTest, DeratingFactorsCellConstAndSet) {
|
|
DeratingFactorsCell dfc;
|
|
dfc.setFactor(TimingDerateCellType::cell_delay, PathClkOrData::data,
|
|
RiseFallBoth::riseFall(), EarlyLate::late(), 1.05f);
|
|
float val;
|
|
bool exists;
|
|
dfc.factor(TimingDerateCellType::cell_delay, PathClkOrData::data,
|
|
RiseFall::fall(), EarlyLate::late(), val, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(val, 1.05f);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, DeratingFactorsCellFactors) {
|
|
DeratingFactorsCell dfc;
|
|
DeratingFactors *f = dfc.factors(TimingDerateCellType::cell_delay);
|
|
EXPECT_NE(f, nullptr);
|
|
}
|
|
|
|
// DeratingFactorsNet
|
|
TEST_F(SdcInitTest, DeratingFactorsNetConstruct) {
|
|
DeratingFactorsNet dfn;
|
|
EXPECT_FALSE(dfn.hasValue());
|
|
}
|
|
|
|
// SdcCmdComment
|
|
// ClockGatingCheck
|
|
TEST_F(SdcInitTest, ClockGatingCheckDefault) {
|
|
ClockGatingCheck cgc;
|
|
// Default constructor should work
|
|
}
|
|
|
|
TEST_F(SdcInitTest, ClockGatingCheckSetActiveValue) {
|
|
ClockGatingCheck cgc;
|
|
cgc.setActiveValue(LogicValue::one);
|
|
}
|
|
|
|
// NetWireCaps
|
|
TEST_F(SdcInitTest, NetWireCapsDefault) {
|
|
NetWireCaps nwc;
|
|
EXPECT_FALSE(nwc.subtractPinCap(MinMax::min()));
|
|
EXPECT_FALSE(nwc.subtractPinCap(MinMax::max()));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, NetWireCapsSetSubtractPinCap) {
|
|
NetWireCaps nwc;
|
|
nwc.setSubtractPinCap(true, MinMax::min());
|
|
EXPECT_TRUE(nwc.subtractPinCap(MinMax::min()));
|
|
EXPECT_FALSE(nwc.subtractPinCap(MinMax::max()));
|
|
}
|
|
|
|
// PortExtCap deeper coverage
|
|
TEST_F(SdcInitTest, PortExtCapSetAndGet) {
|
|
PortExtCap pec(nullptr);
|
|
pec.setPinCap(1.5f, RiseFall::rise(), MinMax::max());
|
|
float val;
|
|
bool exists;
|
|
pec.pinCap(RiseFall::rise(), MinMax::max(), val, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(val, 1.5f);
|
|
}
|
|
|
|
// CycleAccting
|
|
TEST_F(SdcInitTest, CycleAcctingConstruct) {
|
|
// Make a clock to get clock edges
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("ca_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("ca_clk");
|
|
EXPECT_NE(clk, nullptr);
|
|
const ClockEdge *rise_edge = clk->edge(RiseFall::rise());
|
|
const ClockEdge *fall_edge = clk->edge(RiseFall::fall());
|
|
EXPECT_NE(rise_edge, nullptr);
|
|
EXPECT_NE(fall_edge, nullptr);
|
|
CycleAccting ca(rise_edge, fall_edge);
|
|
ca.findDefaultArrivalSrcDelays();
|
|
}
|
|
|
|
// CycleAccting via setAccting
|
|
// Clock creation and queries (deeper)
|
|
TEST_F(SdcInitTest, ClockIsVirtual) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("virt_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("virt_clk");
|
|
EXPECT_NE(clk, nullptr);
|
|
// Virtual clock has no pins
|
|
EXPECT_TRUE(clk->isVirtual());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, ClockDefaultPin) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("dp_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("dp_clk");
|
|
const Pin *dp = clk->defaultPin();
|
|
// No default pin for virtual clock
|
|
(void)dp;
|
|
}
|
|
|
|
// ClockLatency
|
|
TEST_F(SdcInitTest, ClockLatencyConstruct) {
|
|
ClockLatency cl(nullptr, nullptr);
|
|
cl.setDelay(RiseFallBoth::riseFall(), MinMaxAll::all(), 1.5f);
|
|
float val;
|
|
bool exists;
|
|
cl.delay(RiseFall::rise(), MinMax::max(), val, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(val, 1.5f);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, ClockLatencyDelayScalar) {
|
|
ClockLatency cl(nullptr, nullptr);
|
|
cl.setDelay(RiseFallBoth::rise(), MinMaxAll::max(), 2.0f);
|
|
float d = cl.delay(RiseFall::rise(), MinMax::max());
|
|
EXPECT_FLOAT_EQ(d, 2.0f);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, ClockLatencyDelays) {
|
|
ClockLatency cl(nullptr, nullptr);
|
|
cl.setDelay(RiseFallBoth::riseFall(), MinMaxAll::all(), 0.5f);
|
|
RiseFallMinMax *delays = cl.delays();
|
|
EXPECT_NE(delays, nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, ClockLatencySetDelays) {
|
|
ClockLatency cl(nullptr, nullptr);
|
|
RiseFallMinMax rfmm;
|
|
rfmm.setValue(RiseFallBoth::riseFall(), MinMaxAll::all(), 1.0f);
|
|
cl.setDelays(&rfmm);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, ClockLatencySetDelayScalar) {
|
|
ClockLatency cl(nullptr, nullptr);
|
|
cl.setDelay(RiseFall::rise(), MinMax::max(), 3.0f);
|
|
float val;
|
|
bool exists;
|
|
cl.delay(RiseFall::rise(), MinMax::max(), val, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(val, 3.0f);
|
|
}
|
|
|
|
// ClockInsertion
|
|
TEST_F(SdcInitTest, ClockInsertionConstruct) {
|
|
ClockInsertion ci(nullptr, nullptr);
|
|
ci.setDelay(RiseFallBoth::riseFall(), MinMaxAll::all(), MinMaxAll::all(), 0.5f);
|
|
float val;
|
|
bool exists;
|
|
ci.delay(RiseFall::rise(), MinMax::max(), MinMax::max(), val, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(val, 0.5f);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, ClockInsertionDelayScalar) {
|
|
ClockInsertion ci(nullptr, nullptr);
|
|
ci.setDelay(RiseFallBoth::riseFall(), MinMaxAll::all(), MinMaxAll::all(), 1.0f);
|
|
float d = ci.delay(RiseFall::rise(), MinMax::max(), MinMax::max());
|
|
EXPECT_FLOAT_EQ(d, 1.0f);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, ClockInsertionDelays) {
|
|
ClockInsertion ci(nullptr, nullptr);
|
|
ci.setDelay(RiseFallBoth::riseFall(), MinMaxAll::all(), MinMaxAll::all(), 0.3f);
|
|
RiseFallMinMax *d = ci.delays(MinMax::max());
|
|
EXPECT_NE(d, nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, ClockInsertionSetDelays) {
|
|
ClockInsertion ci(nullptr, nullptr);
|
|
RiseFallMinMax rfmm;
|
|
rfmm.setValue(RiseFallBoth::riseFall(), MinMaxAll::all(), 0.7f);
|
|
ci.setDelays(&rfmm);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, ClockInsertionSetDelayScalar) {
|
|
ClockInsertion ci(nullptr, nullptr);
|
|
ci.setDelay(RiseFall::rise(), MinMax::max(), MinMax::max(), 2.0f);
|
|
float val;
|
|
bool exists;
|
|
ci.delay(RiseFall::rise(), MinMax::max(), MinMax::max(), val, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(val, 2.0f);
|
|
}
|
|
|
|
// DataCheck
|
|
TEST_F(SdcInitTest, DataCheckConstruct) {
|
|
DataCheck dc(nullptr, nullptr, nullptr);
|
|
EXPECT_TRUE(dc.empty());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, DataCheckSetAndGetMargin) {
|
|
DataCheck dc(nullptr, nullptr, nullptr);
|
|
dc.setMargin(RiseFallBoth::riseFall(), RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), 0.5f);
|
|
EXPECT_FALSE(dc.empty());
|
|
float val;
|
|
bool exists;
|
|
dc.margin(RiseFall::rise(), RiseFall::rise(), MinMax::max(), val, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(val, 0.5f);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, DataCheckRemoveMargin) {
|
|
DataCheck dc(nullptr, nullptr, nullptr);
|
|
dc.setMargin(RiseFallBoth::riseFall(), RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), 0.3f);
|
|
dc.removeMargin(RiseFallBoth::riseFall(), RiseFallBoth::riseFall(),
|
|
MinMaxAll::all());
|
|
EXPECT_TRUE(dc.empty());
|
|
}
|
|
|
|
// DataCheckLess
|
|
// ClockGroups via Sdc
|
|
TEST_F(SdcInitTest, SdcRemoveClockGroups) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->makeClockGroups("grp2", false, true, false, false, "comment");
|
|
sdc->removeClockGroups("grp2");
|
|
}
|
|
|
|
TEST_F(SdcInitTest, SdcRemoveClockGroupsLogicallyExclusive) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->makeClockGroups("le_grp", true, false, false, false, nullptr);
|
|
sdc->removeClockGroupsLogicallyExclusive("le_grp");
|
|
}
|
|
|
|
TEST_F(SdcInitTest, SdcRemoveClockGroupsPhysicallyExclusive) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->makeClockGroups("pe_grp", false, true, false, false, nullptr);
|
|
sdc->removeClockGroupsPhysicallyExclusive("pe_grp");
|
|
}
|
|
|
|
TEST_F(SdcInitTest, SdcRemoveClockGroupsAsynchronous) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->makeClockGroups("async_grp", false, false, true, false, nullptr);
|
|
sdc->removeClockGroupsAsynchronous("async_grp");
|
|
}
|
|
|
|
// ClockGroups direct
|
|
// Sdc: setMaxArea/maxArea
|
|
TEST_F(SdcInitTest, SdcSetMaxArea) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setMaxArea(100.0f);
|
|
EXPECT_FLOAT_EQ(sdc->maxArea(), 100.0f);
|
|
}
|
|
|
|
// Sdc: setWireloadMode/wireloadMode
|
|
TEST_F(SdcInitTest, SdcSetWireloadMode) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setWireloadMode(WireloadMode::top);
|
|
EXPECT_EQ(sdc->wireloadMode(), WireloadMode::top);
|
|
sdc->setWireloadMode(WireloadMode::enclosed);
|
|
EXPECT_EQ(sdc->wireloadMode(), WireloadMode::enclosed);
|
|
sdc->setWireloadMode(WireloadMode::segmented);
|
|
EXPECT_EQ(sdc->wireloadMode(), WireloadMode::segmented);
|
|
}
|
|
|
|
// Sdc: wireload/setWireload
|
|
TEST_F(SdcInitTest, SdcWireloadNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
// No wireload set
|
|
auto *wl = sdc->wireload(MinMax::max());
|
|
EXPECT_EQ(wl, nullptr);
|
|
}
|
|
|
|
// Sdc: wireloadSelection
|
|
TEST_F(SdcInitTest, SdcWireloadSelectionNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
auto *ws = sdc->wireloadSelection(MinMax::max());
|
|
EXPECT_EQ(ws, nullptr);
|
|
}
|
|
|
|
// Sdc: setAnalysisType
|
|
TEST_F(SdcInitTest, SdcSetAnalysisTypeSingle) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setAnalysisType(AnalysisType::single);
|
|
EXPECT_EQ(sdc->analysisType(), AnalysisType::single);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, SdcSetAnalysisTypeBcWc) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setAnalysisType(AnalysisType::bc_wc);
|
|
EXPECT_EQ(sdc->analysisType(), AnalysisType::bc_wc);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, SdcSetAnalysisTypeOcv) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setAnalysisType(AnalysisType::ocv);
|
|
EXPECT_EQ(sdc->analysisType(), AnalysisType::ocv);
|
|
}
|
|
|
|
// Sdc: isConstrained
|
|
TEST_F(SdcInitTest, SdcIsConstrainedInstNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_FALSE(sdc->isConstrained((const Instance*)nullptr));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, SdcIsConstrainedNetNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_FALSE(sdc->isConstrained((const Net*)nullptr));
|
|
}
|
|
|
|
// Sdc: haveClkSlewLimits
|
|
TEST_F(SdcInitTest, SdcHaveClkSlewLimits) {
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_FALSE(sdc->haveClkSlewLimits());
|
|
}
|
|
|
|
// Sdc: hasClockLatency
|
|
TEST_F(SdcInitTest, SdcHasClockLatencyNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_FALSE(sdc->hasClockLatency(nullptr));
|
|
}
|
|
|
|
// Sdc: clockLatencies
|
|
TEST_F(SdcInitTest, SdcClockLatenciesAccess) {
|
|
Sdc *sdc = sta_->sdc();
|
|
auto *cl = sdc->clockLatencies();
|
|
EXPECT_NE(cl, nullptr);
|
|
}
|
|
|
|
// Sdc: clockInsertions
|
|
TEST_F(SdcInitTest, SdcClockInsertionsAccess) {
|
|
Sdc *sdc = sta_->sdc();
|
|
const auto &ci = sdc->clockInsertions();
|
|
EXPECT_TRUE(ci.empty());
|
|
}
|
|
|
|
// Sdc: hasClockInsertion
|
|
TEST_F(SdcInitTest, SdcHasClockInsertionNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_FALSE(sdc->hasClockInsertion(nullptr));
|
|
}
|
|
|
|
// Sdc: defaultArrivalClockEdge
|
|
TEST_F(SdcInitTest, SdcDefaultArrivalClockEdge) {
|
|
Sdc *sdc = sta_->sdc();
|
|
const ClockEdge *edge = sdc->defaultArrivalClockEdge();
|
|
// May be null before searchPreamble
|
|
(void)edge;
|
|
}
|
|
|
|
// Sdc: sortedClocks
|
|
// Sdc: searchPreamble
|
|
TEST_F(SdcInitTest, SdcSearchPreambleNoDesign) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->searchPreamble();
|
|
}
|
|
|
|
// Sdc: makeDefaultArrivalClock
|
|
TEST_F(SdcInitTest, SdcMakeDefaultArrivalClock) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->searchPreamble();
|
|
const ClockEdge *edge = sdc->defaultArrivalClockEdge();
|
|
EXPECT_NE(edge, nullptr);
|
|
}
|
|
|
|
// Sdc: invalidateGeneratedClks
|
|
TEST_F(SdcInitTest, SdcInvalidateGenClks) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->invalidateGeneratedClks();
|
|
}
|
|
|
|
// Sdc: setClockSlew/removeClockSlew
|
|
TEST_F(SdcInitTest, SdcSetClockSlew) {
|
|
Sdc *sdc = sta_->sdc();
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("slew_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Clock *clk = sdc->findClock("slew_clk");
|
|
sdc->setClockSlew(clk, RiseFallBoth::riseFall(), MinMaxAll::all(), 0.1f);
|
|
sdc->removeClockSlew(clk);
|
|
}
|
|
|
|
// Sdc: setClockLatency/removeClockLatency
|
|
TEST_F(SdcInitTest, SdcSetClockLatency) {
|
|
Sdc *sdc = sta_->sdc();
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("lat_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Clock *clk = sdc->findClock("lat_clk");
|
|
sdc->setClockLatency(clk, nullptr, RiseFallBoth::riseFall(), MinMaxAll::all(), 0.5f);
|
|
sdc->removeClockLatency(clk, nullptr);
|
|
}
|
|
|
|
// Sdc: clockLatency (Clock*, RiseFall*, MinMax*)
|
|
TEST_F(SdcInitTest, SdcClockLatencyQuery) {
|
|
Sdc *sdc = sta_->sdc();
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("latq_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Clock *clk = sdc->findClock("latq_clk");
|
|
sdc->setClockLatency(clk, nullptr, RiseFallBoth::riseFall(), MinMaxAll::all(), 1.0f);
|
|
float lat = sdc->clockLatency(clk, RiseFall::rise(), MinMax::max());
|
|
EXPECT_FLOAT_EQ(lat, 1.0f);
|
|
}
|
|
|
|
// Sdc: setClockInsertion/removeClockInsertion
|
|
TEST_F(SdcInitTest, SdcSetClockInsertion) {
|
|
Sdc *sdc = sta_->sdc();
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("ins_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Clock *clk = sdc->findClock("ins_clk");
|
|
sdc->setClockInsertion(clk, nullptr, RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), EarlyLateAll::all(), 0.2f);
|
|
EXPECT_FALSE(sdc->clockInsertions().empty());
|
|
sdc->removeClockInsertion(clk, nullptr);
|
|
}
|
|
|
|
// Sdc: clockInsertion query
|
|
TEST_F(SdcInitTest, SdcClockInsertionQuery) {
|
|
Sdc *sdc = sta_->sdc();
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("insq_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Clock *clk = sdc->findClock("insq_clk");
|
|
sdc->setClockInsertion(clk, nullptr, RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), EarlyLateAll::all(), 0.3f);
|
|
float ins = sdc->clockInsertion(clk, RiseFall::rise(), MinMax::max(),
|
|
EarlyLate::early());
|
|
EXPECT_FLOAT_EQ(ins, 0.3f);
|
|
}
|
|
|
|
// Sdc: setClockUncertainty/removeClockUncertainty
|
|
TEST_F(SdcInitTest, SdcSetInterClockUncertainty) {
|
|
Sdc *sdc = sta_->sdc();
|
|
FloatSeq *waveform1 = new FloatSeq;
|
|
waveform1->push_back(0.0);
|
|
waveform1->push_back(5.0);
|
|
sta_->makeClock("unc_clk1", nullptr, false, 10.0, waveform1, nullptr);
|
|
FloatSeq *waveform2 = new FloatSeq;
|
|
waveform2->push_back(0.0);
|
|
waveform2->push_back(2.5);
|
|
sta_->makeClock("unc_clk2", nullptr, false, 5.0, waveform2, nullptr);
|
|
Clock *clk1 = sdc->findClock("unc_clk1");
|
|
Clock *clk2 = sdc->findClock("unc_clk2");
|
|
sdc->setClockUncertainty(clk1, RiseFallBoth::riseFall(),
|
|
clk2, RiseFallBoth::riseFall(),
|
|
SetupHoldAll::all(), 0.1f);
|
|
sdc->removeClockUncertainty(clk1, RiseFallBoth::riseFall(),
|
|
clk2, RiseFallBoth::riseFall(),
|
|
SetupHoldAll::all());
|
|
}
|
|
|
|
// Sdc: sameClockGroup
|
|
TEST_F(SdcInitTest, SdcSameClockGroupNoGroups) {
|
|
Sdc *sdc = sta_->sdc();
|
|
FloatSeq *waveform1 = new FloatSeq;
|
|
waveform1->push_back(0.0);
|
|
waveform1->push_back(5.0);
|
|
sta_->makeClock("scg_c1", nullptr, false, 10.0, waveform1, nullptr);
|
|
FloatSeq *waveform2 = new FloatSeq;
|
|
waveform2->push_back(0.0);
|
|
waveform2->push_back(5.0);
|
|
sta_->makeClock("scg_c2", nullptr, false, 10.0, waveform2, nullptr);
|
|
Clock *c1 = sdc->findClock("scg_c1");
|
|
Clock *c2 = sdc->findClock("scg_c2");
|
|
// Without groups, clocks are in same group
|
|
bool same = sdc->sameClockGroup(c1, c2);
|
|
EXPECT_TRUE(same);
|
|
}
|
|
|
|
// Sdc: setClockGatingCheck (global)
|
|
// Sdc: setClockGatingCheck (clock)
|
|
// Sdc: setDataCheck/dataChecksFrom/dataChecksTo
|
|
TEST_F(SdcInitTest, SdcSetDataCheck) {
|
|
Sdc *sdc = sta_->sdc();
|
|
// Can't set data check without real pins, but test the query on null
|
|
DataCheckSet *from = sdc->dataChecksFrom(nullptr);
|
|
DataCheckSet *to = sdc->dataChecksTo(nullptr);
|
|
EXPECT_EQ(from, nullptr);
|
|
EXPECT_EQ(to, nullptr);
|
|
}
|
|
|
|
// Sdc: setTimingDerate (all variants)
|
|
TEST_F(SdcInitTest, SdcSetTimingDerateGlobalNet) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setTimingDerate(TimingDerateType::net_delay, PathClkOrData::data,
|
|
RiseFallBoth::riseFall(), EarlyLate::late(), 1.05f);
|
|
}
|
|
|
|
// Sdc: swapDeratingFactors
|
|
TEST_F(SdcInitTest, SdcSwapDeratingFactors) {
|
|
Sdc *sdc = sta_->sdc();
|
|
// Create another Sta to get a second Sdc
|
|
// Actually we can just swap with itself (no-op)
|
|
Sdc::swapDeratingFactors(sdc, sdc);
|
|
}
|
|
|
|
// Sdc: deleteDeratingFactors
|
|
// Sdc: allInputs/allOutputs
|
|
// Sdc: findClocksMatching
|
|
// Sdc: isGroupPathName
|
|
TEST_F(SdcInitTest, SdcIsGroupPathNameEmpty) {
|
|
Sdc *sdc = sta_->sdc();
|
|
// Suppress deprecation warning -- we intentionally test deprecated API
|
|
#pragma GCC diagnostic push
|
|
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
|
bool is_group = sdc->isGroupPathName("nonexistent");
|
|
#pragma GCC diagnostic pop
|
|
EXPECT_FALSE(is_group);
|
|
}
|
|
|
|
// Sdc: setVoltage
|
|
TEST_F(SdcInitTest, SdcSetVoltageGlobal) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setVoltage(MinMax::max(), 1.0f);
|
|
}
|
|
|
|
// Sdc: setLatchBorrowLimit
|
|
TEST_F(SdcInitTest, SdcSetLatchBorrowLimitClock) {
|
|
Sdc *sdc = sta_->sdc();
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("lbl_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Clock *clk = sdc->findClock("lbl_clk");
|
|
sdc->setLatchBorrowLimit(clk, 3.0f);
|
|
}
|
|
|
|
// Sdc: setMinPulseWidth on clock
|
|
TEST_F(SdcInitTest, SdcSetMinPulseWidthClock) {
|
|
Sdc *sdc = sta_->sdc();
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("mpw_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Clock *clk = sdc->findClock("mpw_clk");
|
|
sdc->setMinPulseWidth(clk, RiseFallBoth::riseFall(), 1.0f);
|
|
}
|
|
|
|
// Sdc: makeCornersAfter/makeCornersBefore
|
|
TEST_F(SdcInitTest, SdcMakeCornersBefore) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->makeCornersBefore();
|
|
sdc->makeCornersAfter(sta_->corners());
|
|
}
|
|
|
|
// Sdc: removeNetLoadCaps
|
|
// Sdc: initVariables
|
|
// Sdc: swapPortExtCaps
|
|
TEST_F(SdcInitTest, SdcSwapPortExtCaps) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Sdc::swapPortExtCaps(sdc, sdc);
|
|
}
|
|
|
|
// Sdc: swapClockInsertions
|
|
TEST_F(SdcInitTest, SdcSwapClockInsertions) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Sdc::swapClockInsertions(sdc, sdc);
|
|
}
|
|
|
|
// ExceptionPath type queries
|
|
TEST_F(SdcExceptionPathTest, FalsePathIsFalse) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
EXPECT_TRUE(fp.isFalse());
|
|
EXPECT_FALSE(fp.isMultiCycle());
|
|
EXPECT_FALSE(fp.isPathDelay());
|
|
EXPECT_FALSE(fp.isGroupPath());
|
|
EXPECT_FALSE(fp.isFilter());
|
|
EXPECT_FALSE(fp.isLoop());
|
|
EXPECT_FALSE(fp.isDefault());
|
|
EXPECT_EQ(fp.type(), ExceptionPathType::false_path);
|
|
}
|
|
|
|
TEST_F(SdcExceptionPathTest, MultiCyclePathIsMultiCycle) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
false, 2, true, nullptr);
|
|
EXPECT_TRUE(mcp.isMultiCycle());
|
|
EXPECT_FALSE(mcp.isFalse());
|
|
EXPECT_EQ(mcp.pathMultiplier(), 2);
|
|
EXPECT_EQ(mcp.type(), ExceptionPathType::multi_cycle);
|
|
}
|
|
|
|
TEST_F(SdcExceptionPathTest, MultiCyclePathUseEndClk) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, nullptr);
|
|
EXPECT_TRUE(mcp.useEndClk());
|
|
}
|
|
|
|
TEST_F(SdcExceptionPathTest, PathDelayIsPathDelay) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
5.0e-9f, true, nullptr);
|
|
EXPECT_TRUE(pd.isPathDelay());
|
|
EXPECT_FALSE(pd.isFalse());
|
|
EXPECT_FLOAT_EQ(pd.delay(), 5.0e-9f);
|
|
EXPECT_FALSE(pd.ignoreClkLatency());
|
|
EXPECT_FALSE(pd.breakPath());
|
|
EXPECT_EQ(pd.type(), ExceptionPathType::path_delay);
|
|
}
|
|
|
|
TEST_F(SdcExceptionPathTest, PathDelayBreakPath) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(), false, true,
|
|
1.0e-9f, true, nullptr);
|
|
EXPECT_TRUE(pd.breakPath());
|
|
}
|
|
|
|
TEST_F(SdcExceptionPathTest, PathDelayIgnoreClkLatency) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(), true, false,
|
|
1.0e-9f, true, nullptr);
|
|
EXPECT_TRUE(pd.ignoreClkLatency());
|
|
}
|
|
|
|
TEST_F(SdcExceptionPathTest, GroupPathIsGroupPath) {
|
|
GroupPath gp("grp", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
EXPECT_TRUE(gp.isGroupPath());
|
|
EXPECT_FALSE(gp.isFalse());
|
|
EXPECT_STREQ(gp.name(), "grp");
|
|
EXPECT_FALSE(gp.isDefault());
|
|
EXPECT_EQ(gp.type(), ExceptionPathType::group_path);
|
|
}
|
|
|
|
TEST_F(SdcExceptionPathTest, GroupPathDefault) {
|
|
GroupPath gp("grp_def", true, nullptr, nullptr, nullptr, true, nullptr);
|
|
EXPECT_TRUE(gp.isDefault());
|
|
}
|
|
|
|
// ExceptionPath: priority and hash
|
|
TEST_F(SdcExceptionPathTest, ExceptionPathPriority) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
int prio = fp.priority(MinMax::max());
|
|
// FalsePath has well-defined priority
|
|
EXPECT_GT(prio, 0);
|
|
}
|
|
|
|
// ExceptionPtIterator
|
|
TEST_F(SdcExceptionPathTest, ExceptionPtIteratorEmpty) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
ExceptionPtIterator iter(&fp);
|
|
// With all nullptr from/thru/to, should have no points
|
|
EXPECT_FALSE(iter.hasNext());
|
|
}
|
|
|
|
// InputDrive deeper
|
|
TEST_F(SdcInitTest, InputDriveConstructDestruct) {
|
|
InputDrive *id = new InputDrive;
|
|
EXPECT_FALSE(id->hasDriveResistance(RiseFall::rise(), MinMax::max()));
|
|
EXPECT_FALSE(id->hasDriveCell(RiseFall::rise(), MinMax::max()));
|
|
delete id;
|
|
}
|
|
|
|
TEST_F(SdcInitTest, InputDriveSetDriveResistance) {
|
|
InputDrive id;
|
|
id.setDriveResistance(RiseFallBoth::riseFall(), MinMaxAll::all(), 100.0f);
|
|
EXPECT_TRUE(id.hasDriveResistance(RiseFall::rise(), MinMax::max()));
|
|
float res;
|
|
bool exists;
|
|
id.driveResistance(RiseFall::rise(), MinMax::max(), res, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(res, 100.0f);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, InputDriveDriveResistanceMinMaxEqual) {
|
|
InputDrive id;
|
|
id.setDriveResistance(RiseFallBoth::riseFall(), MinMaxAll::all(), 50.0f);
|
|
bool eq = id.driveResistanceMinMaxEqual(RiseFall::rise());
|
|
EXPECT_TRUE(eq);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, InputDriveDriveCellNull) {
|
|
InputDrive id;
|
|
const InputDriveCell *dc = id.driveCell(RiseFall::rise(), MinMax::max());
|
|
EXPECT_EQ(dc, nullptr);
|
|
}
|
|
|
|
// DisabledPorts deeper
|
|
// DisabledInstancePorts
|
|
TEST_F(SdcInitTest, DisabledInstancePortsConstruct) {
|
|
DisabledInstancePorts dip(nullptr);
|
|
EXPECT_FALSE(dip.all());
|
|
}
|
|
|
|
// Sdc: setClockSense
|
|
// Sdc: hasNetWireCap
|
|
TEST_F(SdcInitTest, SdcHasNetWireCapNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_FALSE(sdc->hasNetWireCap(nullptr));
|
|
}
|
|
|
|
// Sdc: hasPortExtCap
|
|
TEST_F(SdcInitTest, SdcHasPortExtCapNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_FALSE(sdc->hasPortExtCap(nullptr));
|
|
}
|
|
|
|
// Sdc: isExceptionStartpoint/isExceptionEndpoint
|
|
// Sdc: isPropagatedClock
|
|
TEST_F(SdcInitTest, SdcIsPropagatedClockNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_FALSE(sdc->isPropagatedClock(nullptr));
|
|
}
|
|
|
|
// Sdc: hasLogicValue
|
|
TEST_F(SdcInitTest, SdcHasLogicValueNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_FALSE(sdc->hasLogicValue(nullptr));
|
|
}
|
|
|
|
// Sdc: isPathDelayInternalFrom/To
|
|
TEST_F(SdcInitTest, SdcIsPathDelayInternalFromNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_FALSE(sdc->isPathDelayInternalFrom(nullptr));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, SdcIsPathDelayInternalFromBreakNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_FALSE(sdc->isPathDelayInternalFromBreak(nullptr));
|
|
}
|
|
|
|
// Sdc: pathDelayInternalFrom
|
|
TEST_F(SdcInitTest, SdcPathDelayInternalFrom) {
|
|
Sdc *sdc = sta_->sdc();
|
|
const auto &pins = sdc->pathDelayInternalFrom();
|
|
EXPECT_TRUE(pins.empty());
|
|
}
|
|
|
|
// Sdc: disabledCellPorts/disabledInstancePorts
|
|
TEST_F(SdcInitTest, SdcDisabledCellPorts) {
|
|
Sdc *sdc = sta_->sdc();
|
|
auto *dcp = sdc->disabledCellPorts();
|
|
EXPECT_NE(dcp, nullptr);
|
|
}
|
|
|
|
// Sdc: isDisabled on TimingArcSet (nullptr)
|
|
// Sdc: isDisabledPin (nullptr)
|
|
// ClockPairLess
|
|
TEST_F(SdcInitTest, ClockPairLessOp) {
|
|
Sdc *sdc = sta_->sdc();
|
|
FloatSeq *w1 = new FloatSeq;
|
|
w1->push_back(0.0);
|
|
w1->push_back(5.0);
|
|
sta_->makeClock("cpl_c1", nullptr, false, 10.0, w1, nullptr);
|
|
FloatSeq *w2 = new FloatSeq;
|
|
w2->push_back(0.0);
|
|
w2->push_back(5.0);
|
|
sta_->makeClock("cpl_c2", nullptr, false, 10.0, w2, nullptr);
|
|
Clock *c1 = sdc->findClock("cpl_c1");
|
|
Clock *c2 = sdc->findClock("cpl_c2");
|
|
ClockPairLess cpl;
|
|
ClockPair p1(c1, c2);
|
|
ClockPair p2(c2, c1);
|
|
bool result = cpl(p1, p2);
|
|
(void)result;
|
|
}
|
|
|
|
// InputDriveCell
|
|
// PortDelay (direct)
|
|
// PortDelayLess
|
|
// Sdc: setClockLatency on pin
|
|
TEST_F(SdcInitTest, SdcClockLatencyOnPin) {
|
|
Sdc *sdc = sta_->sdc();
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("clp_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Clock *clk = sdc->findClock("clp_clk");
|
|
// Set latency on clock (no pin)
|
|
sdc->setClockLatency(clk, nullptr, RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), 0.5f);
|
|
bool exists;
|
|
float lat;
|
|
sdc->clockLatency(clk, RiseFall::rise(), MinMax::max(), lat, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(lat, 0.5f);
|
|
}
|
|
|
|
// Sdc: setClockInsertion on pin
|
|
TEST_F(SdcInitTest, SdcClockInsertionOnPin) {
|
|
Sdc *sdc = sta_->sdc();
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("cip_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Clock *clk = sdc->findClock("cip_clk");
|
|
sdc->setClockInsertion(clk, nullptr, RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), EarlyLateAll::all(), 0.4f);
|
|
float ins;
|
|
bool exists;
|
|
sdc->clockInsertion(clk, nullptr, RiseFall::rise(), MinMax::max(),
|
|
EarlyLate::early(), ins, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(ins, 0.4f);
|
|
}
|
|
|
|
// Sdc: setClockInsertion scalar form
|
|
TEST_F(SdcInitTest, SdcClockInsertionScalarForm) {
|
|
Sdc *sdc = sta_->sdc();
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("cis_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Clock *clk = sdc->findClock("cis_clk");
|
|
sdc->setClockInsertion(clk, nullptr, RiseFall::rise(), MinMax::max(),
|
|
EarlyLate::early(), 0.6f);
|
|
}
|
|
|
|
// Sdc: removeGraphAnnotations
|
|
// Sdc: annotateGraph (no graph)
|
|
// Sdc: pathDelayFrom/pathDelayTo (null)
|
|
// Sdc: isPathDelayInternalTo
|
|
TEST_F(SdcInitTest, SdcIsPathDelayInternalToNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_FALSE(sdc->isPathDelayInternalTo(nullptr));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, SdcIsPathDelayInternalToBreakNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_FALSE(sdc->isPathDelayInternalToBreak(nullptr));
|
|
}
|
|
|
|
// Sdc: portMembers
|
|
// Sdc: clockLatency on clock (pair overload)
|
|
// ClockSetLess
|
|
// Sdc: makeExceptionThru/makeExceptionTo
|
|
// ClkHpinDisableLess
|
|
TEST_F(SdcInitTest, ClkHpinDisableLessConstruct) {
|
|
Network *network = sta_->cmdNetwork();
|
|
ClkHpinDisableLess less(network);
|
|
}
|
|
|
|
// PinClockPairLess
|
|
TEST_F(SdcInitTest, PinClockPairLessConstruct) {
|
|
Network *network = sta_->cmdNetwork();
|
|
PinClockPairLess less(network);
|
|
}
|
|
|
|
// ClockInsertionkLess
|
|
TEST_F(SdcInitTest, ClockInsertionkLessConstruct) {
|
|
Network *network = sta_->cmdNetwork();
|
|
ClockInsertionkLess less(network);
|
|
}
|
|
|
|
// ClockLatencyLess
|
|
TEST_F(SdcInitTest, ClockLatencyLessConstruct) {
|
|
Network *network = sta_->cmdNetwork();
|
|
ClockLatencyLess less(network);
|
|
}
|
|
|
|
// DisabledInstPortsLess
|
|
// Sdc: deleteLoopExceptions
|
|
TEST_F(SdcInitTest, SdcDeleteLoopExceptions) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->deleteLoopExceptions();
|
|
}
|
|
|
|
// Sdc: makeFalsePath
|
|
TEST_F(SdcInitTest, SdcMakeFalsePath) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->makeFalsePath(nullptr, nullptr, nullptr, MinMaxAll::all(), nullptr);
|
|
}
|
|
|
|
// Sdc: makeMulticyclePath
|
|
TEST_F(SdcInitTest, SdcMakeMulticyclePath) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->makeMulticyclePath(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
false, 2, nullptr);
|
|
}
|
|
|
|
// Sdc: makePathDelay
|
|
// Sdc: sameClockGroupExplicit
|
|
TEST_F(SdcInitTest, SdcSameClockGroupExplicit) {
|
|
Sdc *sdc = sta_->sdc();
|
|
FloatSeq *w1 = new FloatSeq;
|
|
w1->push_back(0.0);
|
|
w1->push_back(5.0);
|
|
sta_->makeClock("scge_c1", nullptr, false, 10.0, w1, nullptr);
|
|
FloatSeq *w2 = new FloatSeq;
|
|
w2->push_back(0.0);
|
|
w2->push_back(5.0);
|
|
sta_->makeClock("scge_c2", nullptr, false, 10.0, w2, nullptr);
|
|
Clock *c1 = sdc->findClock("scge_c1");
|
|
Clock *c2 = sdc->findClock("scge_c2");
|
|
bool same = sdc->sameClockGroupExplicit(c1, c2);
|
|
EXPECT_FALSE(same);
|
|
}
|
|
|
|
// Sdc: makeFilterPath
|
|
// Sdc: resistance
|
|
TEST_F(SdcInitTest, SdcResistanceNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
float res;
|
|
bool exists;
|
|
sdc->resistance(nullptr, MinMax::max(), res, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
// Sdc: setResistance
|
|
TEST_F(SdcInitTest, SdcSetResistanceNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setResistance(nullptr, MinMaxAll::all(), 10.0f);
|
|
}
|
|
|
|
// Sdc: voltage
|
|
TEST_F(SdcInitTest, SdcVoltageNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
float volt;
|
|
bool exists;
|
|
sdc->voltage(nullptr, MinMax::max(), volt, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
// Sdc: setVoltage on net
|
|
TEST_F(SdcInitTest, SdcSetVoltageOnNet) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setVoltage(nullptr, MinMax::max(), 1.0f);
|
|
}
|
|
|
|
// Sdc: clkStopPropagation
|
|
// Sdc: isDisableClockGatingCheck
|
|
TEST_F(SdcInitTest, SdcIsDisableClockGatingCheckInstNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_FALSE(sdc->isDisableClockGatingCheck(static_cast<const Instance*>(nullptr)));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, SdcIsDisableClockGatingCheckPinNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_FALSE(sdc->isDisableClockGatingCheck(static_cast<const Pin*>(nullptr)));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R5_ Tests - New tests for coverage improvement
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// Clock::addPin with nullptr - covers Clock::addPin
|
|
TEST_F(SdcInitTest, R5_ClockAddPinNull) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->makeClock("clk_addpin", nullptr, false, 10.0,
|
|
waveform, nullptr);
|
|
ASSERT_NE(clk, nullptr);
|
|
// addPin with nullptr - after adding null, isVirtual becomes false
|
|
// because the pins set becomes non-empty
|
|
clk->addPin(nullptr);
|
|
EXPECT_FALSE(clk->isVirtual());
|
|
}
|
|
|
|
// Clock::setSlew - covers Clock::setSlew(rf, min_max, float)
|
|
TEST_F(SdcInitTest, R5_ClockSetSlewRfMinMax) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->makeClock("clk_slew", nullptr, false, 10.0,
|
|
waveform, nullptr);
|
|
ASSERT_NE(clk, nullptr);
|
|
clk->setSlew(RiseFall::rise(), MinMax::max(), 0.5f);
|
|
float slew;
|
|
bool exists;
|
|
clk->slew(RiseFall::rise(), MinMax::max(), slew, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(slew, 0.5f);
|
|
}
|
|
|
|
// ClockEdge::setTime - covers ClockEdge::setTime
|
|
// Note: setTime is private/friend, but we can check after clock operations
|
|
TEST_F(SdcInitTest, R5_ClockEdgeTime) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->makeClock("clk_edge", nullptr, false, 10.0,
|
|
waveform, nullptr);
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockEdge *rise_edge = clk->edge(RiseFall::rise());
|
|
ClockEdge *fall_edge = clk->edge(RiseFall::fall());
|
|
ASSERT_NE(rise_edge, nullptr);
|
|
ASSERT_NE(fall_edge, nullptr);
|
|
EXPECT_FLOAT_EQ(rise_edge->time(), 0.0f);
|
|
EXPECT_FLOAT_EQ(fall_edge->time(), 5.0f);
|
|
}
|
|
|
|
// ClockEdge opposite
|
|
TEST_F(SdcInitTest, R5_ClockEdgeOpposite) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->makeClock("clk_opp", nullptr, false, 10.0,
|
|
waveform, nullptr);
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockEdge *rise_edge = clk->edge(RiseFall::rise());
|
|
ClockEdge *fall_edge = clk->edge(RiseFall::fall());
|
|
ASSERT_NE(rise_edge, nullptr);
|
|
ASSERT_NE(fall_edge, nullptr);
|
|
EXPECT_EQ(rise_edge->opposite(), fall_edge);
|
|
EXPECT_EQ(fall_edge->opposite(), rise_edge);
|
|
}
|
|
|
|
// ClockEdge pulseWidth
|
|
TEST_F(SdcInitTest, R5_ClockEdgePulseWidth) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(4.0);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->makeClock("clk_pw", nullptr, false, 10.0,
|
|
waveform, nullptr);
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockEdge *rise_edge = clk->edge(RiseFall::rise());
|
|
ASSERT_NE(rise_edge, nullptr);
|
|
float pw = rise_edge->pulseWidth();
|
|
EXPECT_FLOAT_EQ(pw, 4.0f); // duty is 4ns high, 6ns low
|
|
}
|
|
|
|
// ClockEdge name and index
|
|
TEST_F(SdcInitTest, R5_ClockEdgeNameIndex) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->makeClock("clk_ni", nullptr, false, 10.0,
|
|
waveform, nullptr);
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockEdge *rise_edge = clk->edge(RiseFall::rise());
|
|
ASSERT_NE(rise_edge, nullptr);
|
|
EXPECT_NE(rise_edge->name(), nullptr);
|
|
int idx = rise_edge->index();
|
|
(void)idx;
|
|
}
|
|
|
|
// DisabledCellPorts - covers constructor/destructor and methods
|
|
TEST_F(SdcInitTest, R5_DisabledCellPortsBasic) {
|
|
// We need a real liberty cell
|
|
LibertyLibrary *lib = sta_->readLiberty("test/nangate45/Nangate45_typ.lib",
|
|
sta_->cmdCorner(),
|
|
MinMaxAll::min(), false);
|
|
ASSERT_NE(lib, nullptr);
|
|
LibertyCell *buf = lib->findLibertyCell("BUF_X1");
|
|
ASSERT_NE(buf, nullptr);
|
|
DisabledCellPorts dcp(buf);
|
|
EXPECT_EQ(dcp.cell(), buf);
|
|
EXPECT_FALSE(dcp.all());
|
|
}
|
|
|
|
// DisabledCellPorts setDisabled/removeDisabled with TimingArcSet
|
|
TEST_F(SdcInitTest, R5_DisabledCellPortsTimingArcSet) {
|
|
LibertyLibrary *lib = sta_->readLiberty("test/nangate45/Nangate45_typ.lib",
|
|
sta_->cmdCorner(),
|
|
MinMaxAll::min(), false);
|
|
ASSERT_NE(lib, nullptr);
|
|
LibertyCell *buf = lib->findLibertyCell("BUF_X1");
|
|
ASSERT_NE(buf, nullptr);
|
|
const auto &arc_sets = buf->timingArcSets();
|
|
ASSERT_GT(arc_sets.size(), 0u);
|
|
DisabledCellPorts dcp(buf);
|
|
TimingArcSet *as = arc_sets[0];
|
|
dcp.setDisabled(as);
|
|
EXPECT_TRUE(dcp.isDisabled(as));
|
|
dcp.removeDisabled(as);
|
|
EXPECT_FALSE(dcp.isDisabled(as));
|
|
}
|
|
|
|
// DisabledCellPorts isDisabled for from/to/role
|
|
TEST_F(SdcInitTest, R5_DisabledCellPortsIsDisabled) {
|
|
LibertyLibrary *lib = sta_->readLiberty("test/nangate45/Nangate45_typ.lib",
|
|
sta_->cmdCorner(),
|
|
MinMaxAll::min(), false);
|
|
ASSERT_NE(lib, nullptr);
|
|
LibertyCell *buf = lib->findLibertyCell("BUF_X1");
|
|
ASSERT_NE(buf, nullptr);
|
|
LibertyPort *a = buf->findLibertyPort("A");
|
|
LibertyPort *z = buf->findLibertyPort("Z");
|
|
ASSERT_NE(a, nullptr);
|
|
ASSERT_NE(z, nullptr);
|
|
DisabledCellPorts dcp(buf);
|
|
// Initially nothing disabled
|
|
EXPECT_FALSE(dcp.isDisabled(a, z, TimingRole::combinational()));
|
|
// Disable all
|
|
dcp.setDisabledAll();
|
|
EXPECT_TRUE(dcp.all());
|
|
EXPECT_TRUE(dcp.isDisabled(a, z, TimingRole::combinational()));
|
|
dcp.removeDisabledAll();
|
|
EXPECT_FALSE(dcp.all());
|
|
}
|
|
|
|
// ExceptionPath::typeString via various subclasses
|
|
TEST_F(SdcInitTest, R5_FalsePathTypeString) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
EXPECT_NE(fp.typeString(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_PathDelayTypeString) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, true, nullptr);
|
|
EXPECT_NE(pd.typeString(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_MultiCyclePathTypeString) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, nullptr);
|
|
EXPECT_NE(mcp.typeString(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_FilterPathTypeString) {
|
|
FilterPath fp(nullptr, nullptr, nullptr, true);
|
|
EXPECT_NE(fp.typeString(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_GroupPathTypeString) {
|
|
GroupPath gp("grp1", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
EXPECT_NE(gp.typeString(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_LoopPathTypeString) {
|
|
LoopPath lp(nullptr, true);
|
|
EXPECT_NE(lp.typeString(), nullptr);
|
|
}
|
|
|
|
// ExceptionPath::mergeable tests
|
|
TEST_F(SdcInitTest, R5_FalsePathMergeable) {
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
EXPECT_TRUE(fp1.mergeable(&fp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_PathDelayMergeable) {
|
|
PathDelay pd1(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, true, nullptr);
|
|
PathDelay pd2(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, true, nullptr);
|
|
EXPECT_TRUE(pd1.mergeable(&pd2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_PathDelayMergeableDifferentDelay) {
|
|
PathDelay pd1(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, true, nullptr);
|
|
PathDelay pd2(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 10.0f, true, nullptr);
|
|
EXPECT_FALSE(pd1.mergeable(&pd2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_MultiCyclePathMergeable) {
|
|
MultiCyclePath mcp1(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, nullptr);
|
|
MultiCyclePath mcp2(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, nullptr);
|
|
EXPECT_TRUE(mcp1.mergeable(&mcp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_GroupPathMergeable) {
|
|
GroupPath gp1("grp1", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
GroupPath gp2("grp1", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
EXPECT_TRUE(gp1.mergeable(&gp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_GroupPathNotMergeable) {
|
|
GroupPath gp1("grp1", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
GroupPath gp2("grp2", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
EXPECT_FALSE(gp1.mergeable(&gp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_LoopPathNotMergeable) {
|
|
LoopPath lp1(nullptr, true);
|
|
LoopPath lp2(nullptr, true);
|
|
EXPECT_FALSE(lp1.mergeable(&lp2));
|
|
}
|
|
|
|
// ExceptionPath::overrides tests
|
|
TEST_F(SdcInitTest, R5_FalsePathOverrides) {
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
EXPECT_TRUE(fp1.overrides(&fp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_PathDelayOverrides) {
|
|
PathDelay pd1(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, true, nullptr);
|
|
PathDelay pd2(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, true, nullptr);
|
|
EXPECT_TRUE(pd1.overrides(&pd2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_MultiCyclePathOverrides) {
|
|
MultiCyclePath mcp1(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, nullptr);
|
|
MultiCyclePath mcp2(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, nullptr);
|
|
EXPECT_TRUE(mcp1.overrides(&mcp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_FilterPathOverrides) {
|
|
FilterPath fp1(nullptr, nullptr, nullptr, true);
|
|
FilterPath fp2(nullptr, nullptr, nullptr, true);
|
|
// FilterPath::overrides always returns false
|
|
EXPECT_FALSE(fp1.overrides(&fp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_GroupPathOverrides) {
|
|
GroupPath gp1("grp1", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
GroupPath gp2("grp1", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
EXPECT_TRUE(gp1.overrides(&gp2));
|
|
}
|
|
|
|
// ExceptionPath::matches with min_max
|
|
TEST_F(SdcInitTest, R5_MultiCyclePathMatches) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, nullptr);
|
|
EXPECT_TRUE(mcp.matches(MinMax::max(), false));
|
|
EXPECT_TRUE(mcp.matches(MinMax::min(), false));
|
|
}
|
|
|
|
// ExceptionPath type priorities
|
|
TEST_F(SdcInitTest, R5_ExceptionPathStaticPriorities) {
|
|
EXPECT_EQ(ExceptionPath::falsePathPriority(), 4000);
|
|
EXPECT_EQ(ExceptionPath::pathDelayPriority(), 3000);
|
|
EXPECT_EQ(ExceptionPath::multiCyclePathPriority(), 2000);
|
|
EXPECT_EQ(ExceptionPath::filterPathPriority(), 1000);
|
|
EXPECT_EQ(ExceptionPath::groupPathPriority(), 0);
|
|
}
|
|
|
|
// ExceptionPath fromThruToPriority
|
|
TEST_F(SdcInitTest, R5_ExceptionFromThruToPriority) {
|
|
int p = ExceptionPath::fromThruToPriority(nullptr, nullptr, nullptr);
|
|
EXPECT_EQ(p, 0);
|
|
}
|
|
|
|
// PathDelay specific getters
|
|
TEST_F(SdcInitTest, R5_PathDelayGetters) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(),
|
|
true, true, 5.0f, true, nullptr);
|
|
EXPECT_FLOAT_EQ(pd.delay(), 5.0f);
|
|
EXPECT_TRUE(pd.ignoreClkLatency());
|
|
EXPECT_TRUE(pd.breakPath());
|
|
EXPECT_TRUE(pd.isPathDelay());
|
|
EXPECT_FALSE(pd.isFalse());
|
|
EXPECT_FALSE(pd.isMultiCycle());
|
|
EXPECT_FALSE(pd.isFilter());
|
|
EXPECT_FALSE(pd.isGroupPath());
|
|
EXPECT_FALSE(pd.isLoop());
|
|
}
|
|
|
|
// MultiCyclePath specific getters
|
|
TEST_F(SdcInitTest, R5_MultiCyclePathGetters) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::max(),
|
|
true, 5, true, nullptr);
|
|
EXPECT_EQ(mcp.pathMultiplier(), 5);
|
|
EXPECT_TRUE(mcp.useEndClk());
|
|
EXPECT_TRUE(mcp.isMultiCycle());
|
|
}
|
|
|
|
// MultiCyclePath pathMultiplier with MinMax
|
|
TEST_F(SdcInitTest, R5_MultiCyclePathMultiplierMinMax) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::max(),
|
|
true, 5, true, nullptr);
|
|
int mult_max = mcp.pathMultiplier(MinMax::max());
|
|
EXPECT_EQ(mult_max, 5);
|
|
}
|
|
|
|
// MultiCyclePath priority with MinMax
|
|
TEST_F(SdcInitTest, R5_MultiCyclePathPriorityMinMax) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::max(),
|
|
true, 5, true, nullptr);
|
|
int p = mcp.priority(MinMax::max());
|
|
EXPECT_GT(p, 0);
|
|
}
|
|
|
|
// GroupPath name and isDefault
|
|
TEST_F(SdcInitTest, R5_GroupPathName) {
|
|
GroupPath gp("test_group", true, nullptr, nullptr, nullptr, true, nullptr);
|
|
EXPECT_STREQ(gp.name(), "test_group");
|
|
EXPECT_TRUE(gp.isDefault());
|
|
}
|
|
|
|
// FilterPath basic
|
|
TEST_F(SdcInitTest, R5_FilterPathBasic) {
|
|
FilterPath fp(nullptr, nullptr, nullptr, true);
|
|
EXPECT_TRUE(fp.isFilter());
|
|
EXPECT_FALSE(fp.isFalse());
|
|
EXPECT_FALSE(fp.isPathDelay());
|
|
EXPECT_FALSE(fp.isMultiCycle());
|
|
EXPECT_FALSE(fp.isGroupPath());
|
|
EXPECT_FALSE(fp.isLoop());
|
|
}
|
|
|
|
// FalsePath with priority
|
|
TEST_F(SdcInitTest, R5_FalsePathWithPriority) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true,
|
|
4500, nullptr);
|
|
EXPECT_EQ(fp.priority(), 4500);
|
|
}
|
|
|
|
// LoopPath basic
|
|
TEST_F(SdcInitTest, R5_LoopPathBasicProps) {
|
|
LoopPath lp(nullptr, true);
|
|
EXPECT_TRUE(lp.isLoop());
|
|
EXPECT_TRUE(lp.isFalse());
|
|
EXPECT_FALSE(lp.isPathDelay());
|
|
EXPECT_FALSE(lp.isMultiCycle());
|
|
}
|
|
|
|
// Exception hash
|
|
TEST_F(SdcInitTest, R5_ExceptionPathHash) {
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
size_t h1 = fp1.hash();
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
size_t h2 = fp2.hash();
|
|
EXPECT_EQ(h1, h2);
|
|
}
|
|
|
|
// ExceptionPath clone tests
|
|
TEST_F(SdcInitTest, R5_FalsePathCloneAndCheck) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
ExceptionPath *clone = fp.clone(nullptr, nullptr, nullptr, true);
|
|
ASSERT_NE(clone, nullptr);
|
|
EXPECT_TRUE(clone->isFalse());
|
|
delete clone;
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_PathDelayCloneAndCheck) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, true, nullptr);
|
|
ExceptionPath *clone = pd.clone(nullptr, nullptr, nullptr, true);
|
|
ASSERT_NE(clone, nullptr);
|
|
EXPECT_TRUE(clone->isPathDelay());
|
|
EXPECT_FLOAT_EQ(clone->delay(), 5.0f);
|
|
delete clone;
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_MultiCyclePathCloneAndCheck) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 4, true, nullptr);
|
|
ExceptionPath *clone = mcp.clone(nullptr, nullptr, nullptr, true);
|
|
ASSERT_NE(clone, nullptr);
|
|
EXPECT_TRUE(clone->isMultiCycle());
|
|
EXPECT_EQ(clone->pathMultiplier(), 4);
|
|
delete clone;
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_GroupPathCloneAndCheck) {
|
|
GroupPath gp("grp", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
ExceptionPath *clone = gp.clone(nullptr, nullptr, nullptr, true);
|
|
ASSERT_NE(clone, nullptr);
|
|
EXPECT_TRUE(clone->isGroupPath());
|
|
EXPECT_STREQ(clone->name(), "grp");
|
|
delete clone;
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_FilterPathCloneAndCheck) {
|
|
FilterPath fp(nullptr, nullptr, nullptr, true);
|
|
ExceptionPath *clone = fp.clone(nullptr, nullptr, nullptr, true);
|
|
ASSERT_NE(clone, nullptr);
|
|
EXPECT_TRUE(clone->isFilter());
|
|
delete clone;
|
|
}
|
|
|
|
// ExceptionState constructor
|
|
TEST_F(SdcInitTest, R5_ExceptionState) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
ExceptionState state(&fp, nullptr, 0);
|
|
EXPECT_EQ(state.exception(), &fp);
|
|
EXPECT_EQ(state.nextThru(), nullptr);
|
|
EXPECT_EQ(state.index(), 0);
|
|
EXPECT_TRUE(state.isComplete());
|
|
}
|
|
|
|
// ExceptionState setNextState
|
|
TEST_F(SdcInitTest, R5_ExceptionStateSetNextState) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
ExceptionState state1(&fp, nullptr, 0);
|
|
ExceptionState state2(&fp, nullptr, 1);
|
|
state1.setNextState(&state2);
|
|
EXPECT_EQ(state1.nextState(), &state2);
|
|
}
|
|
|
|
// ExceptionState hash
|
|
TEST_F(SdcInitTest, R5_ExceptionStateHash) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
ExceptionState state(&fp, nullptr, 0);
|
|
size_t h = state.hash();
|
|
(void)h;
|
|
}
|
|
|
|
// exceptionStateLess
|
|
TEST_F(SdcInitTest, R5_ExceptionStateLess) {
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
ExceptionState state1(&fp1, nullptr, 0);
|
|
ExceptionState state2(&fp2, nullptr, 0);
|
|
// Just exercise the comparator
|
|
exceptionStateLess(&state1, &state2);
|
|
}
|
|
|
|
// Sdc::setOperatingConditions(op_cond, MinMaxAll*)
|
|
TEST_F(SdcInitTest, R5_SdcSetOperatingConditionsMinMaxAll) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setOperatingConditions(nullptr, MinMaxAll::all());
|
|
}
|
|
|
|
// Sdc::disable/removeDisable for LibertyPort
|
|
TEST_F(SdcInitTest, R5_SdcDisableLibertyPort) {
|
|
LibertyLibrary *lib = sta_->readLiberty("test/nangate45/Nangate45_typ.lib",
|
|
sta_->cmdCorner(),
|
|
MinMaxAll::min(), false);
|
|
ASSERT_NE(lib, nullptr);
|
|
LibertyCell *buf = lib->findLibertyCell("BUF_X1");
|
|
ASSERT_NE(buf, nullptr);
|
|
LibertyPort *port_a = buf->findLibertyPort("A");
|
|
ASSERT_NE(port_a, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->disable(port_a);
|
|
sdc->removeDisable(port_a);
|
|
}
|
|
|
|
// Sdc::disable/removeDisable for TimingArcSet
|
|
TEST_F(SdcInitTest, R5_SdcDisableTimingArcSet) {
|
|
LibertyLibrary *lib = sta_->readLiberty("test/nangate45/Nangate45_typ.lib",
|
|
sta_->cmdCorner(),
|
|
MinMaxAll::min(), false);
|
|
ASSERT_NE(lib, nullptr);
|
|
LibertyCell *buf = lib->findLibertyCell("BUF_X1");
|
|
ASSERT_NE(buf, nullptr);
|
|
const TimingArcSetSeq &arc_sets = buf->timingArcSets();
|
|
ASSERT_GT(arc_sets.size(), 0u);
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->disable(arc_sets[0]);
|
|
sdc->removeDisable(arc_sets[0]);
|
|
}
|
|
|
|
// Sdc clock querying via findClock
|
|
TEST_F(SdcInitTest, R5_SdcFindClockNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("nonexistent_clk");
|
|
EXPECT_EQ(clk, nullptr);
|
|
}
|
|
|
|
// Sdc latch borrow limit on clock
|
|
TEST_F(SdcInitTest, R5_SdcLatchBorrowLimitOnClock) {
|
|
Sdc *sdc = sta_->sdc();
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Clock *clk = sdc->makeClock("clk_lbl", nullptr, false, 10.0,
|
|
waveform, nullptr);
|
|
ASSERT_NE(clk, nullptr);
|
|
sdc->setLatchBorrowLimit(clk, 2.0f);
|
|
// Just exercise - borrow limit is set
|
|
}
|
|
|
|
// InterClockUncertainty more thorough
|
|
TEST_F(SdcInitTest, R5_InterClockUncertaintyEmpty) {
|
|
FloatSeq *waveform1 = new FloatSeq;
|
|
waveform1->push_back(0.0);
|
|
waveform1->push_back(5.0);
|
|
FloatSeq *waveform2 = new FloatSeq;
|
|
waveform2->push_back(0.0);
|
|
waveform2->push_back(3.0);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk1 = sdc->makeClock("clk_icu1", nullptr, false, 10.0,
|
|
waveform1, nullptr);
|
|
Clock *clk2 = sdc->makeClock("clk_icu2", nullptr, false, 6.0,
|
|
waveform2, nullptr);
|
|
InterClockUncertainty icu(clk1, clk2);
|
|
EXPECT_TRUE(icu.empty());
|
|
EXPECT_EQ(icu.src(), clk1);
|
|
EXPECT_EQ(icu.target(), clk2);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_InterClockUncertaintySetAndGet) {
|
|
FloatSeq *waveform1 = new FloatSeq;
|
|
waveform1->push_back(0.0);
|
|
waveform1->push_back(5.0);
|
|
FloatSeq *waveform2 = new FloatSeq;
|
|
waveform2->push_back(0.0);
|
|
waveform2->push_back(3.0);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk1 = sdc->makeClock("clk_icu3", nullptr, false, 10.0,
|
|
waveform1, nullptr);
|
|
Clock *clk2 = sdc->makeClock("clk_icu4", nullptr, false, 6.0,
|
|
waveform2, nullptr);
|
|
InterClockUncertainty icu(clk1, clk2);
|
|
icu.setUncertainty(RiseFallBoth::riseFall(), RiseFallBoth::riseFall(),
|
|
SetupHoldAll::all(), 0.1f);
|
|
EXPECT_FALSE(icu.empty());
|
|
float unc;
|
|
bool exists;
|
|
icu.uncertainty(RiseFall::rise(), RiseFall::rise(),
|
|
SetupHold::min(), unc, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(unc, 0.1f);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_InterClockUncertaintyRemove) {
|
|
FloatSeq *waveform1 = new FloatSeq;
|
|
waveform1->push_back(0.0);
|
|
waveform1->push_back(5.0);
|
|
FloatSeq *waveform2 = new FloatSeq;
|
|
waveform2->push_back(0.0);
|
|
waveform2->push_back(3.0);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk1 = sdc->makeClock("clk_icu5", nullptr, false, 10.0,
|
|
waveform1, nullptr);
|
|
Clock *clk2 = sdc->makeClock("clk_icu6", nullptr, false, 6.0,
|
|
waveform2, nullptr);
|
|
InterClockUncertainty icu(clk1, clk2);
|
|
icu.setUncertainty(RiseFallBoth::riseFall(), RiseFallBoth::riseFall(),
|
|
SetupHoldAll::all(), 0.2f);
|
|
icu.removeUncertainty(RiseFallBoth::riseFall(), RiseFallBoth::riseFall(),
|
|
SetupHoldAll::all());
|
|
EXPECT_TRUE(icu.empty());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_InterClockUncertaintyUncertainties) {
|
|
FloatSeq *waveform1 = new FloatSeq;
|
|
waveform1->push_back(0.0);
|
|
waveform1->push_back(5.0);
|
|
FloatSeq *waveform2 = new FloatSeq;
|
|
waveform2->push_back(0.0);
|
|
waveform2->push_back(3.0);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk1 = sdc->makeClock("clk_icu7", nullptr, false, 10.0,
|
|
waveform1, nullptr);
|
|
Clock *clk2 = sdc->makeClock("clk_icu8", nullptr, false, 6.0,
|
|
waveform2, nullptr);
|
|
InterClockUncertainty icu(clk1, clk2);
|
|
const RiseFallMinMax *rfmm = icu.uncertainties(RiseFall::rise());
|
|
EXPECT_NE(rfmm, nullptr);
|
|
}
|
|
|
|
// CycleAccting exercises
|
|
TEST_F(SdcInitTest, R5_CycleAcctingConstruct) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->makeClock("clk_ca", nullptr, false, 10.0,
|
|
waveform, nullptr);
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockEdge *rise = clk->edge(RiseFall::rise());
|
|
ClockEdge *fall = clk->edge(RiseFall::fall());
|
|
CycleAccting ca(rise, fall);
|
|
EXPECT_EQ(ca.src(), rise);
|
|
EXPECT_EQ(ca.target(), fall);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R5_CycleAcctingFindDefaultArrivalSrcDelays) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->makeClock("clk_ca2", nullptr, false, 10.0,
|
|
waveform, nullptr);
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockEdge *rise = clk->edge(RiseFall::rise());
|
|
ClockEdge *fall = clk->edge(RiseFall::fall());
|
|
CycleAccting ca(rise, fall);
|
|
ca.findDefaultArrivalSrcDelays();
|
|
// Should not crash
|
|
}
|
|
|
|
// DisabledPorts from/to operations
|
|
TEST_F(SdcInitTest, R5_DisabledPortsFromToOps) {
|
|
LibertyLibrary *lib = sta_->readLiberty("test/nangate45/Nangate45_typ.lib",
|
|
sta_->cmdCorner(),
|
|
MinMaxAll::min(), false);
|
|
ASSERT_NE(lib, nullptr);
|
|
LibertyCell *buf = lib->findLibertyCell("BUF_X1");
|
|
ASSERT_NE(buf, nullptr);
|
|
LibertyPort *a = buf->findLibertyPort("A");
|
|
LibertyPort *z = buf->findLibertyPort("Z");
|
|
ASSERT_NE(a, nullptr);
|
|
ASSERT_NE(z, nullptr);
|
|
DisabledPorts dp;
|
|
dp.setDisabledFrom(a);
|
|
EXPECT_NE(dp.from(), nullptr);
|
|
dp.setDisabledTo(z);
|
|
EXPECT_NE(dp.to(), nullptr);
|
|
dp.setDisabledFromTo(a, z);
|
|
EXPECT_NE(dp.fromTo(), nullptr);
|
|
dp.removeDisabledFrom(a);
|
|
dp.removeDisabledTo(z);
|
|
dp.removeDisabledFromTo(a, z);
|
|
}
|
|
|
|
// ClockCompareSet
|
|
TEST_F(SdcInitTest, R5_ClockSetCompare) {
|
|
FloatSeq *waveform1 = new FloatSeq;
|
|
waveform1->push_back(0.0);
|
|
waveform1->push_back(5.0);
|
|
FloatSeq *waveform2 = new FloatSeq;
|
|
waveform2->push_back(0.0);
|
|
waveform2->push_back(3.0);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk1 = sdc->makeClock("clk_csc1", nullptr, false, 10.0,
|
|
waveform1, nullptr);
|
|
Clock *clk2 = sdc->makeClock("clk_csc2", nullptr, false, 6.0,
|
|
waveform2, nullptr);
|
|
ClockSet set1;
|
|
set1.insert(clk1);
|
|
ClockSet set2;
|
|
set2.insert(clk2);
|
|
int cmp = compare(&set1, &set2);
|
|
(void)cmp;
|
|
}
|
|
|
|
// Sdc::clockUncertainty on null pin
|
|
TEST_F(SdcInitTest, R5_SdcClockUncertaintyNullPin) {
|
|
Sdc *sdc = sta_->sdc();
|
|
float unc;
|
|
bool exists;
|
|
sdc->clockUncertainty(static_cast<const Pin*>(nullptr),
|
|
MinMax::max(), unc, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
// ExceptionPtIterator with from only
|
|
TEST_F(SdcInitTest, R5_ExceptionPtIteratorFromOnly) {
|
|
const Network *network = sta_->cmdNetwork();
|
|
ExceptionFrom *from = new ExceptionFrom(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(),
|
|
true, network);
|
|
FalsePath fp(from, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
ExceptionPtIterator iter(&fp);
|
|
int count = 0;
|
|
while (iter.hasNext()) {
|
|
ExceptionPt *pt = iter.next();
|
|
EXPECT_NE(pt, nullptr);
|
|
count++;
|
|
}
|
|
EXPECT_EQ(count, 1);
|
|
}
|
|
|
|
// ExceptionFrom basic properties
|
|
TEST_F(SdcInitTest, R5_ExceptionFromProperties) {
|
|
const Network *network = sta_->cmdNetwork();
|
|
ExceptionFrom *from = new ExceptionFrom(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::rise(),
|
|
true, network);
|
|
EXPECT_TRUE(from->isFrom());
|
|
EXPECT_FALSE(from->isThru());
|
|
EXPECT_FALSE(from->isTo());
|
|
EXPECT_EQ(from->transition(), RiseFallBoth::rise());
|
|
EXPECT_EQ(from->typePriority(), 0);
|
|
delete from;
|
|
}
|
|
|
|
// ExceptionTo basic properties
|
|
TEST_F(SdcInitTest, R5_ExceptionToProperties) {
|
|
const Network *network = sta_->cmdNetwork();
|
|
ExceptionTo *to = new ExceptionTo(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::fall(),
|
|
RiseFallBoth::riseFall(),
|
|
true, network);
|
|
EXPECT_TRUE(to->isTo());
|
|
EXPECT_FALSE(to->isFrom());
|
|
EXPECT_FALSE(to->isThru());
|
|
EXPECT_EQ(to->transition(), RiseFallBoth::fall());
|
|
EXPECT_EQ(to->endTransition(), RiseFallBoth::riseFall());
|
|
EXPECT_EQ(to->typePriority(), 1);
|
|
delete to;
|
|
}
|
|
|
|
// ExceptionThru basic properties
|
|
TEST_F(SdcInitTest, R5_ExceptionThruProperties) {
|
|
const Network *network = sta_->cmdNetwork();
|
|
ExceptionThru *thru = new ExceptionThru(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(),
|
|
true, network);
|
|
EXPECT_TRUE(thru->isThru());
|
|
EXPECT_FALSE(thru->isFrom());
|
|
EXPECT_FALSE(thru->isTo());
|
|
EXPECT_EQ(thru->transition(), RiseFallBoth::riseFall());
|
|
EXPECT_EQ(thru->typePriority(), 2);
|
|
EXPECT_EQ(thru->clks(), nullptr);
|
|
EXPECT_FALSE(thru->hasObjects());
|
|
delete thru;
|
|
}
|
|
|
|
// ExceptionThru objectCount
|
|
TEST_F(SdcInitTest, R5_ExceptionThruObjectCount) {
|
|
const Network *network = sta_->cmdNetwork();
|
|
ExceptionThru *thru = new ExceptionThru(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(),
|
|
true, network);
|
|
EXPECT_EQ(thru->objectCount(), 0u);
|
|
delete thru;
|
|
}
|
|
|
|
// ExceptionFromTo objectCount
|
|
TEST_F(SdcInitTest, R5_ExceptionFromToObjectCount) {
|
|
const Network *network = sta_->cmdNetwork();
|
|
ExceptionFrom *from = new ExceptionFrom(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(),
|
|
true, network);
|
|
EXPECT_EQ(from->objectCount(), 0u);
|
|
delete from;
|
|
}
|
|
|
|
// ExceptionPt hash
|
|
TEST_F(SdcInitTest, R5_ExceptionPtHash) {
|
|
const Network *network = sta_->cmdNetwork();
|
|
ExceptionFrom *from = new ExceptionFrom(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(),
|
|
true, network);
|
|
size_t h = from->hash();
|
|
(void)h;
|
|
delete from;
|
|
}
|
|
|
|
// ExceptionFrom::findHash (called during construction)
|
|
TEST_F(SdcInitTest, R5_ExceptionFromFindHash) {
|
|
const Network *network = sta_->cmdNetwork();
|
|
ExceptionFrom *from = new ExceptionFrom(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::rise(),
|
|
true, network);
|
|
// Hash should be computed during construction
|
|
size_t h = from->hash();
|
|
EXPECT_GE(h, 0u);
|
|
delete from;
|
|
}
|
|
|
|
// checkFromThrusTo with nulls should not throw
|
|
TEST_F(SdcInitTest, R5_CheckFromThrusToAllNull) {
|
|
// All nullptr should not throw EmptyExceptionPt
|
|
checkFromThrusTo(nullptr, nullptr, nullptr);
|
|
}
|
|
|
|
// EmptyExceptionPt what
|
|
TEST_F(SdcInitTest, R5_EmptyExceptionPtWhat) {
|
|
EmptyExpceptionPt e;
|
|
const char *msg = e.what();
|
|
EXPECT_NE(msg, nullptr);
|
|
}
|
|
|
|
// ExceptionPathLess comparator
|
|
TEST_F(SdcInitTest, R5_ExceptionPathLessComparator) {
|
|
const Network *network = sta_->cmdNetwork();
|
|
ExceptionPathLess less(network);
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
// Should not crash
|
|
less(&fp1, &fp2);
|
|
}
|
|
|
|
|
|
// Sdc::isLeafPinNonGeneratedClock with null
|
|
TEST_F(SdcInitTest, R5_SdcIsLeafPinNonGeneratedClockNull) {
|
|
Sdc *sdc = sta_->sdc();
|
|
bool result = sdc->isLeafPinNonGeneratedClock(nullptr);
|
|
EXPECT_FALSE(result);
|
|
}
|
|
|
|
// Clock removeSlew
|
|
TEST_F(SdcInitTest, R5_ClockRemoveSlew) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->makeClock("clk_rs", nullptr, false, 10.0,
|
|
waveform, nullptr);
|
|
ASSERT_NE(clk, nullptr);
|
|
clk->setSlew(RiseFallBoth::riseFall(), MinMaxAll::all(), 0.5f);
|
|
clk->removeSlew();
|
|
float slew;
|
|
bool exists;
|
|
clk->slew(RiseFall::rise(), MinMax::max(), slew, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
// Clock slews accessor
|
|
TEST_F(SdcInitTest, R5_ClockSlewsAccessor) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->makeClock("clk_sa", nullptr, false, 10.0,
|
|
waveform, nullptr);
|
|
ASSERT_NE(clk, nullptr);
|
|
const RiseFallMinMax &slews = clk->slews();
|
|
(void)slews; // just exercise
|
|
}
|
|
|
|
// Clock uncertainties
|
|
TEST_F(SdcInitTest, R5_ClockUncertaintiesAccessor) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->makeClock("clk_ua", nullptr, false, 10.0,
|
|
waveform, nullptr);
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockUncertainties *unc = clk->uncertainties();
|
|
(void)unc;
|
|
}
|
|
|
|
// Clock setUncertainty and removeUncertainty
|
|
TEST_F(SdcInitTest, R5_ClockSetRemoveUncertainty) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->makeClock("clk_sru", nullptr, false, 10.0,
|
|
waveform, nullptr);
|
|
ASSERT_NE(clk, nullptr);
|
|
clk->setUncertainty(SetupHoldAll::all(), 0.1f);
|
|
float unc;
|
|
bool exists;
|
|
clk->uncertainty(SetupHold::min(), unc, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(unc, 0.1f);
|
|
clk->removeUncertainty(SetupHoldAll::all());
|
|
clk->uncertainty(SetupHold::min(), unc, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
// Clock generated properties
|
|
TEST_F(SdcInitTest, R5_ClockGeneratedProperties) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->makeClock("clk_gp", nullptr, false, 10.0,
|
|
waveform, nullptr);
|
|
ASSERT_NE(clk, nullptr);
|
|
EXPECT_FALSE(clk->isGenerated());
|
|
EXPECT_EQ(clk->masterClk(), nullptr);
|
|
EXPECT_EQ(clk->srcPin(), nullptr);
|
|
EXPECT_EQ(clk->divideBy(), 0);
|
|
EXPECT_EQ(clk->multiplyBy(), 0);
|
|
}
|
|
|
|
// ClkNameLess comparator
|
|
TEST_F(SdcInitTest, R5_ClkNameLess) {
|
|
FloatSeq *waveform1 = new FloatSeq;
|
|
waveform1->push_back(0.0);
|
|
waveform1->push_back(5.0);
|
|
FloatSeq *waveform2 = new FloatSeq;
|
|
waveform2->push_back(0.0);
|
|
waveform2->push_back(3.0);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clkA = sdc->makeClock("alpha", nullptr, false, 10.0,
|
|
waveform1, nullptr);
|
|
Clock *clkB = sdc->makeClock("beta", nullptr, false, 6.0,
|
|
waveform2, nullptr);
|
|
ClkNameLess less;
|
|
EXPECT_TRUE(less(clkA, clkB));
|
|
EXPECT_FALSE(less(clkB, clkA));
|
|
}
|
|
|
|
// CycleAcctings
|
|
TEST_F(SdcInitTest, R5_CycleAcctings) {
|
|
Sdc *sdc = sta_->sdc();
|
|
CycleAcctings acctings(sdc);
|
|
// Clear should not crash
|
|
acctings.clear();
|
|
}
|
|
|
|
// Clock setPropagated / removePropagated
|
|
TEST_F(SdcInitTest, R5_ClockPropagation) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->makeClock("clk_prop", nullptr, false, 10.0,
|
|
waveform, nullptr);
|
|
ASSERT_NE(clk, nullptr);
|
|
EXPECT_FALSE(clk->isPropagated());
|
|
sdc->setPropagatedClock(clk);
|
|
EXPECT_TRUE(clk->isPropagated());
|
|
sdc->removePropagatedClock(clk);
|
|
EXPECT_FALSE(clk->isPropagated());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: DisabledPorts from/to operations
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_DisabledPortsAllState) {
|
|
DisabledPorts dp;
|
|
EXPECT_FALSE(dp.all());
|
|
dp.setDisabledAll();
|
|
EXPECT_TRUE(dp.all());
|
|
dp.removeDisabledAll();
|
|
EXPECT_FALSE(dp.all());
|
|
// Verify from/to/fromTo are still nullptr
|
|
EXPECT_EQ(dp.from(), nullptr);
|
|
EXPECT_EQ(dp.to(), nullptr);
|
|
EXPECT_EQ(dp.fromTo(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_DisabledCellPortsConstruct) {
|
|
// DisabledCellPorts requires a LibertyCell; use nullptr since
|
|
// we only exercise the constructor path
|
|
LibertyLibrary lib("test_lib", "test.lib");
|
|
LibertyCell *cell = lib.makeScaledCell("test_cell", "test.lib");
|
|
DisabledCellPorts dcp(cell);
|
|
EXPECT_EQ(dcp.cell(), cell);
|
|
EXPECT_FALSE(dcp.all());
|
|
delete cell;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Sdc public accessors
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_SdcAnalysisType) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setAnalysisType(AnalysisType::single);
|
|
EXPECT_EQ(sdc->analysisType(), AnalysisType::single);
|
|
sdc->setAnalysisType(AnalysisType::bc_wc);
|
|
EXPECT_EQ(sdc->analysisType(), AnalysisType::bc_wc);
|
|
sdc->setAnalysisType(AnalysisType::ocv);
|
|
EXPECT_EQ(sdc->analysisType(), AnalysisType::ocv);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_SdcMaxArea) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setMaxArea(500.0);
|
|
EXPECT_FLOAT_EQ(sdc->maxArea(), 500.0f);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Sdc setOperatingConditions
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_SdcSetOperatingConditions) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setOperatingConditions(nullptr, MinMax::max());
|
|
sdc->setOperatingConditions(nullptr, MinMax::min());
|
|
EXPECT_EQ(sdc->operatingConditions(MinMax::max()), nullptr);
|
|
EXPECT_EQ(sdc->operatingConditions(MinMax::min()), nullptr);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Sdc wireload mode
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_SdcWireloadMode) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setWireloadMode(WireloadMode::top);
|
|
EXPECT_EQ(sdc->wireloadMode(), WireloadMode::top);
|
|
sdc->setWireloadMode(WireloadMode::enclosed);
|
|
EXPECT_EQ(sdc->wireloadMode(), WireloadMode::enclosed);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: ExceptionPath mergeable between same types
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_FalsePathMergeableSame) {
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
EXPECT_TRUE(fp1.mergeable(&fp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_FalsePathNotMergeableDiffMinMax) {
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::min(), true, nullptr);
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::max(), true, nullptr);
|
|
EXPECT_FALSE(fp1.mergeable(&fp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_FalsePathNotMergeableDiffType) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
1.0e-9f, true, nullptr);
|
|
EXPECT_FALSE(fp.mergeable(&pd));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: PathDelay min direction
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_PathDelayMinDirection) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::min(), false, false,
|
|
5.0e-9f, true, nullptr);
|
|
EXPECT_TRUE(pd.matches(MinMax::min(), false));
|
|
EXPECT_FALSE(pd.matches(MinMax::max(), false));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_PathDelayTighterMin) {
|
|
PathDelay pd1(nullptr, nullptr, nullptr, MinMax::min(), false, false,
|
|
5.0e-9f, true, nullptr);
|
|
PathDelay pd2(nullptr, nullptr, nullptr, MinMax::min(), false, false,
|
|
2.0e-9f, true, nullptr);
|
|
// For min, larger delay is tighter
|
|
EXPECT_TRUE(pd1.tighterThan(&pd2));
|
|
EXPECT_FALSE(pd2.tighterThan(&pd1));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: ExceptionPath hash
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_PathDelayHash) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
5.0e-9f, true, nullptr);
|
|
size_t h = pd.hash();
|
|
EXPECT_GE(h, 0u);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_MultiCyclePathHash) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, nullptr);
|
|
size_t h = mcp.hash();
|
|
EXPECT_GE(h, 0u);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_GroupPathHash) {
|
|
GroupPath gp("grp", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
size_t h = gp.hash();
|
|
EXPECT_GE(h, 0u);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_FilterPathHash) {
|
|
FilterPath flp(nullptr, nullptr, nullptr, true);
|
|
size_t h = flp.hash();
|
|
EXPECT_GE(h, 0u);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_LoopPathHash) {
|
|
LoopPath lp(nullptr, true);
|
|
size_t h = lp.hash();
|
|
EXPECT_GE(h, 0u);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: ExceptionPath typeString
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_FalsePathTypeString) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, nullptr);
|
|
const char *ts = fp.typeString();
|
|
EXPECT_NE(ts, nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_PathDelayTypeString) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
1.0e-9f, true, nullptr);
|
|
const char *ts = pd.typeString();
|
|
EXPECT_NE(ts, nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_MultiCyclePathTypeString) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 2, true, nullptr);
|
|
const char *ts = mcp.typeString();
|
|
EXPECT_NE(ts, nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_GroupPathTypeString) {
|
|
GroupPath gp("g", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
const char *ts = gp.typeString();
|
|
EXPECT_NE(ts, nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_FilterPathTypeString) {
|
|
FilterPath flp(nullptr, nullptr, nullptr, true);
|
|
const char *ts = flp.typeString();
|
|
EXPECT_NE(ts, nullptr);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Clock operations
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_ClockEdgeTimeAccess) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("et_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("et_clk");
|
|
ClockEdge *rise_edge = clk->edge(RiseFall::rise());
|
|
ClockEdge *fall_edge = clk->edge(RiseFall::fall());
|
|
EXPECT_FLOAT_EQ(rise_edge->time(), 0.0);
|
|
EXPECT_FLOAT_EQ(fall_edge->time(), 5.0);
|
|
EXPECT_EQ(rise_edge->clock(), clk);
|
|
EXPECT_EQ(fall_edge->clock(), clk);
|
|
EXPECT_NE(rise_edge->name(), nullptr);
|
|
EXPECT_NE(fall_edge->name(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_ClockMakeClock) {
|
|
Sdc *sdc = sta_->sdc();
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Clock *clk = sdc->makeClock("direct_clk", nullptr, false, 10.0,
|
|
waveform, nullptr);
|
|
EXPECT_NE(clk, nullptr);
|
|
EXPECT_STREQ(clk->name(), "direct_clk");
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_ClockLeafPins) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("lp_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("lp_clk");
|
|
const PinSet &pins = clk->leafPins();
|
|
EXPECT_TRUE(pins.empty());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Sdc exception operations
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_SdcMakeAndDeleteException) {
|
|
sta_->makeFalsePath(nullptr, nullptr, nullptr, MinMaxAll::all(), nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_FALSE(sdc->exceptions().empty());
|
|
sdc->deleteExceptions();
|
|
EXPECT_TRUE(sdc->exceptions().empty());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_SdcMultiCyclePathWithEndClk) {
|
|
sta_->makeMulticyclePath(nullptr, nullptr, nullptr,
|
|
MinMaxAll::max(),
|
|
true, 3, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_FALSE(sdc->exceptions().empty());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_SdcMultiCyclePathWithStartClk) {
|
|
sta_->makeMulticyclePath(nullptr, nullptr, nullptr,
|
|
MinMaxAll::min(),
|
|
false, 2, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_FALSE(sdc->exceptions().empty());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Sdc constraint accessors
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_SdcClockGatingCheckGlobal) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setClockGatingCheck(RiseFallBoth::rise(), SetupHold::min(), 0.3);
|
|
sdc->setClockGatingCheck(RiseFallBoth::fall(), SetupHold::max(), 0.7);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_SdcClockGatingCheckGlobalRiseFall) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setClockGatingCheck(RiseFallBoth::riseFall(), SetupHold::min(), 0.5);
|
|
sdc->setClockGatingCheck(RiseFallBoth::riseFall(), SetupHold::max(), 0.8);
|
|
float margin;
|
|
bool exists;
|
|
sdc->clockGatingMargin(RiseFall::rise(), SetupHold::min(), exists, margin);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(margin, 0.5f);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_SdcVoltageAccess) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setVoltage(MinMax::min(), 0.9);
|
|
sdc->setVoltage(MinMax::max(), 1.1);
|
|
float v_min, v_max;
|
|
bool e_min, e_max;
|
|
sdc->voltage(MinMax::min(), v_min, e_min);
|
|
sdc->voltage(MinMax::max(), v_max, e_max);
|
|
EXPECT_TRUE(e_min);
|
|
EXPECT_TRUE(e_max);
|
|
EXPECT_FLOAT_EQ(v_min, 0.9f);
|
|
EXPECT_FLOAT_EQ(v_max, 1.1f);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: ExceptionPt construction
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_ExceptionFromRiseFall) {
|
|
ExceptionFrom from(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::rise(), true,
|
|
sta_->cmdNetwork());
|
|
EXPECT_NE(from.transition(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_ExceptionFromHasObjects) {
|
|
ExceptionFrom from(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(), true,
|
|
sta_->cmdNetwork());
|
|
// No objects were provided
|
|
EXPECT_FALSE(from.hasObjects());
|
|
EXPECT_FALSE(from.hasPins());
|
|
EXPECT_FALSE(from.hasClocks());
|
|
EXPECT_FALSE(from.hasInstances());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Clock group operations
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_ClockGroupsPhysicallyExclusive) {
|
|
FloatSeq *wave = new FloatSeq;
|
|
wave->push_back(0.0);
|
|
wave->push_back(5.0);
|
|
sta_->makeClock("pe_clk", nullptr, false, 10.0, wave, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("pe_clk");
|
|
|
|
ClockGroups *groups = sta_->makeClockGroups("pe_grp", false, true, false, false, nullptr);
|
|
ClockSet *clk_set = new ClockSet;
|
|
clk_set->insert(clk);
|
|
sta_->makeClockGroup(groups, clk_set);
|
|
sta_->removeClockGroupsPhysicallyExclusive("pe_grp");
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_ClockGroupsAsynchronous) {
|
|
FloatSeq *wave = new FloatSeq;
|
|
wave->push_back(0.0);
|
|
wave->push_back(5.0);
|
|
sta_->makeClock("async_clk", nullptr, false, 10.0, wave, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("async_clk");
|
|
|
|
ClockGroups *groups = sta_->makeClockGroups("async_grp", false, false, true, false, nullptr);
|
|
ClockSet *clk_set = new ClockSet;
|
|
clk_set->insert(clk);
|
|
sta_->makeClockGroup(groups, clk_set);
|
|
sta_->removeClockGroupsAsynchronous("async_grp");
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Sdc Latch borrow limits
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_SdcMinPulseWidth) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setMinPulseWidth(RiseFallBoth::riseFall(), 0.5);
|
|
// Just exercise the code path - no assertion needed
|
|
// (MinPulseWidth query requires pin data)
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Clock uncertainty with MinMax
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_ClockSetUncertaintyMinMax) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("unc_mm_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("unc_mm_clk");
|
|
clk->setUncertainty(MinMax::min(), 0.05f);
|
|
clk->setUncertainty(MinMax::max(), 0.15f);
|
|
float unc;
|
|
bool exists;
|
|
clk->uncertainty(MinMax::min(), unc, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(unc, 0.05f);
|
|
clk->uncertainty(MinMax::max(), unc, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(unc, 0.15f);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Additional ExceptionPath coverage
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_LoopPathClone) {
|
|
LoopPath lp(nullptr, true);
|
|
ExceptionPath *cloned = lp.clone(nullptr, nullptr, nullptr, true);
|
|
EXPECT_NE(cloned, nullptr);
|
|
// clone() on LoopPath returns FalsePath (inherited from FalsePath::clone)
|
|
EXPECT_TRUE(cloned->isFalse());
|
|
delete cloned;
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_LoopPathOverrides) {
|
|
LoopPath lp1(nullptr, true);
|
|
LoopPath lp2(nullptr, true);
|
|
EXPECT_TRUE(lp1.overrides(&lp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_LoopPathTighterThan) {
|
|
LoopPath lp1(nullptr, true);
|
|
LoopPath lp2(nullptr, true);
|
|
EXPECT_FALSE(lp1.tighterThan(&lp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_GroupPathAsString) {
|
|
GroupPath gp("grp", false, nullptr, nullptr, nullptr, true, nullptr);
|
|
const char *str = gp.asString(sta_->cmdNetwork());
|
|
EXPECT_NE(str, nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_FilterPathAsString) {
|
|
FilterPath flp(nullptr, nullptr, nullptr, true);
|
|
const char *str = flp.asString(sta_->cmdNetwork());
|
|
EXPECT_NE(str, nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_LoopPathAsString) {
|
|
LoopPath lp(nullptr, true);
|
|
const char *str = lp.asString(sta_->cmdNetwork());
|
|
EXPECT_NE(str, nullptr);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: PatternMatch for clocks
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_FindClocksMatchingWildcard) {
|
|
FloatSeq *wave1 = new FloatSeq;
|
|
wave1->push_back(0.0);
|
|
wave1->push_back(5.0);
|
|
sta_->makeClock("sys_clk_a", nullptr, false, 10.0, wave1, nullptr);
|
|
|
|
FloatSeq *wave2 = new FloatSeq;
|
|
wave2->push_back(0.0);
|
|
wave2->push_back(2.5);
|
|
sta_->makeClock("sys_clk_b", nullptr, false, 5.0, wave2, nullptr);
|
|
|
|
FloatSeq *wave3 = new FloatSeq;
|
|
wave3->push_back(0.0);
|
|
wave3->push_back(1.0);
|
|
sta_->makeClock("io_clk", nullptr, false, 2.0, wave3, nullptr);
|
|
|
|
Sdc *sdc = sta_->sdc();
|
|
PatternMatch pattern("sys_*");
|
|
ClockSeq matches = sdc->findClocksMatching(&pattern);
|
|
EXPECT_EQ(matches.size(), 2u);
|
|
|
|
PatternMatch pattern2("*");
|
|
ClockSeq all_matches = sdc->findClocksMatching(&pattern2);
|
|
EXPECT_EQ(all_matches.size(), 3u);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Sdc pathDelaysWithoutTo after adding delay
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_SdcPathDelaysWithoutToAfterAdd) {
|
|
// Add a path delay without a "to" endpoint
|
|
sta_->makePathDelay(nullptr, nullptr, nullptr,
|
|
MinMax::max(), false, false, 5.0e-9, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
EXPECT_TRUE(sdc->pathDelaysWithoutTo());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Sdc multiple operations in sequence
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_SdcComplexSequence) {
|
|
Sdc *sdc = sta_->sdc();
|
|
|
|
// Create clocks
|
|
FloatSeq *w1 = new FloatSeq;
|
|
w1->push_back(0.0);
|
|
w1->push_back(5.0);
|
|
sta_->makeClock("seq_clk1", nullptr, false, 10.0, w1, nullptr);
|
|
|
|
FloatSeq *w2 = new FloatSeq;
|
|
w2->push_back(0.0);
|
|
w2->push_back(2.5);
|
|
sta_->makeClock("seq_clk2", nullptr, false, 5.0, w2, nullptr);
|
|
|
|
// Set various constraints
|
|
sdc->setMaxArea(1000.0);
|
|
EXPECT_FLOAT_EQ(sdc->maxArea(), 1000.0f);
|
|
|
|
sdc->setWireloadMode(WireloadMode::top);
|
|
EXPECT_EQ(sdc->wireloadMode(), WireloadMode::top);
|
|
|
|
sdc->setAnalysisType(AnalysisType::ocv);
|
|
EXPECT_EQ(sdc->analysisType(), AnalysisType::ocv);
|
|
|
|
// Make exception paths
|
|
sta_->makeFalsePath(nullptr, nullptr, nullptr, MinMaxAll::all(), nullptr);
|
|
sta_->makeMulticyclePath(nullptr, nullptr, nullptr,
|
|
MinMaxAll::all(), true, 4, nullptr);
|
|
sta_->makeGroupPath("test_grp", false, nullptr, nullptr, nullptr, nullptr);
|
|
|
|
EXPECT_FALSE(sdc->exceptions().empty());
|
|
EXPECT_TRUE(sta_->isPathGroupName("test_grp"));
|
|
|
|
// Clear
|
|
sdc->clear();
|
|
EXPECT_TRUE(sdc->exceptions().empty());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Clock properties after propagation
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_ClockPropagateCycle) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("prop_cycle_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("prop_cycle_clk");
|
|
|
|
EXPECT_TRUE(clk->isIdeal());
|
|
sta_->setPropagatedClock(clk);
|
|
EXPECT_TRUE(clk->isPropagated());
|
|
EXPECT_FALSE(clk->isIdeal());
|
|
sta_->removePropagatedClock(clk);
|
|
EXPECT_FALSE(clk->isPropagated());
|
|
EXPECT_TRUE(clk->isIdeal());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: InterClockUncertainty hash
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_InterClockUncertaintySetGet) {
|
|
FloatSeq *w1 = new FloatSeq;
|
|
w1->push_back(0.0);
|
|
w1->push_back(5.0);
|
|
sta_->makeClock("icu_clk1", nullptr, false, 10.0, w1, nullptr);
|
|
FloatSeq *w2 = new FloatSeq;
|
|
w2->push_back(0.0);
|
|
w2->push_back(2.5);
|
|
sta_->makeClock("icu_clk2", nullptr, false, 5.0, w2, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk1 = sdc->findClock("icu_clk1");
|
|
Clock *clk2 = sdc->findClock("icu_clk2");
|
|
InterClockUncertainty icu(clk1, clk2);
|
|
icu.setUncertainty(RiseFallBoth::riseFall(), RiseFallBoth::riseFall(),
|
|
SetupHoldAll::all(), 0.5f);
|
|
EXPECT_EQ(icu.src(), clk1);
|
|
EXPECT_EQ(icu.target(), clk2);
|
|
float unc;
|
|
bool exists;
|
|
icu.uncertainty(RiseFall::rise(), RiseFall::rise(), SetupHold::min(),
|
|
unc, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(unc, 0.5f);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: DeratingFactorsCell isOneValue edge cases
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_DeratingFactorsCellSetAndGet) {
|
|
DeratingFactorsCell dfc;
|
|
dfc.setFactor(TimingDerateCellType::cell_delay,
|
|
PathClkOrData::clk,
|
|
RiseFallBoth::riseFall(),
|
|
EarlyLate::early(), 0.95f);
|
|
float factor;
|
|
bool exists;
|
|
dfc.factor(TimingDerateCellType::cell_delay,
|
|
PathClkOrData::clk,
|
|
RiseFall::rise(),
|
|
EarlyLate::early(), factor, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(factor, 0.95f);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: RiseFallMinMax additional
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_RiseFallMinMaxEqual) {
|
|
RiseFallMinMax rfmm1(5.0f);
|
|
RiseFallMinMax rfmm2(5.0f);
|
|
EXPECT_TRUE(rfmm1.equal(&rfmm2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_RiseFallMinMaxNotEqual) {
|
|
RiseFallMinMax rfmm1(5.0f);
|
|
RiseFallMinMax rfmm2(3.0f);
|
|
EXPECT_FALSE(rfmm1.equal(&rfmm2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_RiseFallMinMaxIsOneValue) {
|
|
RiseFallMinMax rfmm(7.0f);
|
|
float val;
|
|
bool is_one = rfmm.isOneValue(val);
|
|
EXPECT_TRUE(is_one);
|
|
EXPECT_FLOAT_EQ(val, 7.0f);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_RiseFallMinMaxIsOneValueFalse) {
|
|
RiseFallMinMax rfmm;
|
|
rfmm.setValue(RiseFall::rise(), MinMax::min(), 1.0f);
|
|
rfmm.setValue(RiseFall::rise(), MinMax::max(), 2.0f);
|
|
rfmm.setValue(RiseFall::fall(), MinMax::min(), 1.0f);
|
|
rfmm.setValue(RiseFall::fall(), MinMax::max(), 2.0f);
|
|
float val;
|
|
bool is_one = rfmm.isOneValue(val);
|
|
EXPECT_FALSE(is_one);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Variables toggle all booleans back and forth
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_VariablesAllToggles) {
|
|
Variables vars;
|
|
vars.setCrprEnabled(false);
|
|
EXPECT_FALSE(vars.crprEnabled());
|
|
vars.setCrprEnabled(true);
|
|
EXPECT_TRUE(vars.crprEnabled());
|
|
|
|
vars.setPocvEnabled(true);
|
|
EXPECT_TRUE(vars.pocvEnabled());
|
|
vars.setPocvEnabled(false);
|
|
EXPECT_FALSE(vars.pocvEnabled());
|
|
|
|
vars.setDynamicLoopBreaking(true);
|
|
EXPECT_TRUE(vars.dynamicLoopBreaking());
|
|
vars.setDynamicLoopBreaking(false);
|
|
EXPECT_FALSE(vars.dynamicLoopBreaking());
|
|
|
|
vars.setPropagateAllClocks(true);
|
|
EXPECT_TRUE(vars.propagateAllClocks());
|
|
vars.setPropagateAllClocks(false);
|
|
EXPECT_FALSE(vars.propagateAllClocks());
|
|
|
|
vars.setUseDefaultArrivalClock(true);
|
|
EXPECT_TRUE(vars.useDefaultArrivalClock());
|
|
vars.setUseDefaultArrivalClock(false);
|
|
EXPECT_FALSE(vars.useDefaultArrivalClock());
|
|
|
|
vars.setClkThruTristateEnabled(true);
|
|
EXPECT_TRUE(vars.clkThruTristateEnabled());
|
|
vars.setClkThruTristateEnabled(false);
|
|
EXPECT_FALSE(vars.clkThruTristateEnabled());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Additional Variables coverage
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_VariablesCrprMode) {
|
|
Variables vars;
|
|
vars.setCrprMode(CrprMode::same_pin);
|
|
EXPECT_EQ(vars.crprMode(), CrprMode::same_pin);
|
|
vars.setCrprMode(CrprMode::same_transition);
|
|
EXPECT_EQ(vars.crprMode(), CrprMode::same_transition);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_VariablesPropagateGatedClockEnable) {
|
|
Variables vars;
|
|
vars.setPropagateGatedClockEnable(true);
|
|
EXPECT_TRUE(vars.propagateGatedClockEnable());
|
|
vars.setPropagateGatedClockEnable(false);
|
|
EXPECT_FALSE(vars.propagateGatedClockEnable());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_VariablesPresetClrArcsEnabled) {
|
|
Variables vars;
|
|
vars.setPresetClrArcsEnabled(true);
|
|
EXPECT_TRUE(vars.presetClrArcsEnabled());
|
|
vars.setPresetClrArcsEnabled(false);
|
|
EXPECT_FALSE(vars.presetClrArcsEnabled());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_VariablesCondDefaultArcsEnabled) {
|
|
Variables vars;
|
|
vars.setCondDefaultArcsEnabled(false);
|
|
EXPECT_FALSE(vars.condDefaultArcsEnabled());
|
|
vars.setCondDefaultArcsEnabled(true);
|
|
EXPECT_TRUE(vars.condDefaultArcsEnabled());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_VariablesBidirectInstPathsEnabled) {
|
|
Variables vars;
|
|
vars.setBidirectInstPathsEnabled(true);
|
|
EXPECT_TRUE(vars.bidirectInstPathsEnabled());
|
|
vars.setBidirectInstPathsEnabled(false);
|
|
EXPECT_FALSE(vars.bidirectInstPathsEnabled());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_VariablesBidirectNetPathsEnabled) {
|
|
Variables vars;
|
|
vars.setBidirectNetPathsEnabled(true);
|
|
EXPECT_TRUE(vars.bidirectNetPathsEnabled());
|
|
vars.setBidirectNetPathsEnabled(false);
|
|
EXPECT_FALSE(vars.bidirectNetPathsEnabled());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_VariablesRecoveryRemovalChecksEnabled) {
|
|
Variables vars;
|
|
vars.setRecoveryRemovalChecksEnabled(false);
|
|
EXPECT_FALSE(vars.recoveryRemovalChecksEnabled());
|
|
vars.setRecoveryRemovalChecksEnabled(true);
|
|
EXPECT_TRUE(vars.recoveryRemovalChecksEnabled());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_VariablesGatedClkChecksEnabled) {
|
|
Variables vars;
|
|
vars.setGatedClkChecksEnabled(false);
|
|
EXPECT_FALSE(vars.gatedClkChecksEnabled());
|
|
vars.setGatedClkChecksEnabled(true);
|
|
EXPECT_TRUE(vars.gatedClkChecksEnabled());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: ClockLatency
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_ClockLatencyConstruction) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("lat_clk", nullptr, false, 10.0, waveform, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("lat_clk");
|
|
ClockLatency lat(clk, nullptr);
|
|
EXPECT_EQ(lat.clock(), clk);
|
|
EXPECT_EQ(lat.pin(), nullptr);
|
|
lat.setDelay(RiseFall::rise(), MinMax::max(), 0.5f);
|
|
float delay;
|
|
bool exists;
|
|
lat.delay(RiseFall::rise(), MinMax::max(), delay, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(delay, 0.5f);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: InputDrive
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_InputDriveConstruction) {
|
|
InputDrive drive;
|
|
drive.setSlew(RiseFallBoth::riseFall(), MinMaxAll::all(), 0.1f);
|
|
drive.setDriveResistance(RiseFallBoth::riseFall(), MinMaxAll::all(), 50.0f);
|
|
float res;
|
|
bool exists;
|
|
drive.driveResistance(RiseFall::rise(), MinMax::max(), res, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(res, 50.0f);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_InputDriveResistanceMinMaxEqual) {
|
|
InputDrive drive;
|
|
drive.setDriveResistance(RiseFallBoth::rise(), MinMaxAll::all(), 100.0f);
|
|
EXPECT_TRUE(drive.driveResistanceMinMaxEqual(RiseFall::rise()));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: RiseFallMinMax more coverage
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, R6_RiseFallMinMaxHasValue) {
|
|
RiseFallMinMax rfmm;
|
|
EXPECT_FALSE(rfmm.hasValue());
|
|
rfmm.setValue(RiseFall::rise(), MinMax::max(), 1.0f);
|
|
EXPECT_TRUE(rfmm.hasValue());
|
|
EXPECT_TRUE(rfmm.hasValue(RiseFall::rise(), MinMax::max()));
|
|
EXPECT_FALSE(rfmm.hasValue(RiseFall::fall(), MinMax::min()));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_RiseFallMinMaxRemoveValue) {
|
|
RiseFallMinMax rfmm(5.0f);
|
|
rfmm.removeValue(RiseFallBoth::rise(), MinMaxAll::max());
|
|
EXPECT_FALSE(rfmm.hasValue(RiseFall::rise(), MinMax::max()));
|
|
EXPECT_TRUE(rfmm.hasValue(RiseFall::rise(), MinMax::min()));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_RiseFallMinMaxMergeValue) {
|
|
RiseFallMinMax rfmm;
|
|
rfmm.setValue(RiseFall::rise(), MinMax::max(), 1.0f);
|
|
rfmm.mergeValue(RiseFall::rise(), MinMax::max(), 2.0f);
|
|
EXPECT_FLOAT_EQ(rfmm.value(RiseFall::rise(), MinMax::max()), 2.0f);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, R6_RiseFallMinMaxMaxValue) {
|
|
RiseFallMinMax rfmm;
|
|
rfmm.setValue(RiseFall::rise(), MinMax::max(), 3.0f);
|
|
rfmm.setValue(RiseFall::fall(), MinMax::max(), 7.0f);
|
|
float max_val;
|
|
bool exists;
|
|
rfmm.maxValue(max_val, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(max_val, 7.0f);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R8_ prefix tests for SDC module coverage
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// DeratingFactors default construction
|
|
TEST_F(SdcInitTest, R8_DeratingFactorsDefault) {
|
|
DeratingFactors df;
|
|
EXPECT_FALSE(df.hasValue());
|
|
}
|
|
|
|
// DeratingFactors set and get
|
|
TEST_F(SdcInitTest, R8_DeratingFactorsSetGet) {
|
|
DeratingFactors df;
|
|
df.setFactor(PathClkOrData::clk, RiseFallBoth::rise(),
|
|
EarlyLate::early(), 0.95f);
|
|
float factor;
|
|
bool exists;
|
|
df.factor(PathClkOrData::clk, RiseFall::rise(),
|
|
EarlyLate::early(), factor, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(factor, 0.95f);
|
|
}
|
|
|
|
// DeratingFactors::clear
|
|
TEST_F(SdcInitTest, R8_DeratingFactorsClear) {
|
|
DeratingFactors df;
|
|
df.setFactor(PathClkOrData::data, RiseFallBoth::riseFall(),
|
|
EarlyLate::late(), 1.05f);
|
|
EXPECT_TRUE(df.hasValue());
|
|
df.clear();
|
|
EXPECT_FALSE(df.hasValue());
|
|
}
|
|
|
|
// DeratingFactors::isOneValue
|
|
TEST_F(SdcInitTest, R8_DeratingFactorsIsOneValue) {
|
|
DeratingFactors df;
|
|
df.setFactor(PathClkOrData::clk, RiseFallBoth::riseFall(),
|
|
EarlyLate::early(), 0.9f);
|
|
df.setFactor(PathClkOrData::data, RiseFallBoth::riseFall(),
|
|
EarlyLate::early(), 0.9f);
|
|
bool is_one_value;
|
|
float value;
|
|
df.isOneValue(EarlyLate::early(), is_one_value, value);
|
|
if (is_one_value)
|
|
EXPECT_FLOAT_EQ(value, 0.9f);
|
|
}
|
|
|
|
// DeratingFactors isOneValue per clk_data
|
|
TEST_F(SdcInitTest, R8_DeratingFactorsIsOneValueClkData) {
|
|
DeratingFactors df;
|
|
df.setFactor(PathClkOrData::clk, RiseFallBoth::riseFall(),
|
|
EarlyLate::early(), 0.95f);
|
|
bool is_one_value;
|
|
float value;
|
|
df.isOneValue(PathClkOrData::clk, EarlyLate::early(),
|
|
is_one_value, value);
|
|
if (is_one_value)
|
|
EXPECT_FLOAT_EQ(value, 0.95f);
|
|
}
|
|
|
|
// DeratingFactorsGlobal
|
|
TEST_F(SdcInitTest, R8_DeratingFactorsGlobalDefault) {
|
|
DeratingFactorsGlobal dfg;
|
|
float factor;
|
|
bool exists;
|
|
dfg.factor(TimingDerateType::cell_delay, PathClkOrData::clk,
|
|
RiseFall::rise(), EarlyLate::early(), factor, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
// DeratingFactorsGlobal set and get
|
|
TEST_F(SdcInitTest, R8_DeratingFactorsGlobalSetGet) {
|
|
DeratingFactorsGlobal dfg;
|
|
dfg.setFactor(TimingDerateType::cell_delay, PathClkOrData::clk,
|
|
RiseFallBoth::rise(), EarlyLate::early(), 0.98f);
|
|
float factor;
|
|
bool exists;
|
|
dfg.factor(TimingDerateType::cell_delay, PathClkOrData::clk,
|
|
RiseFall::rise(), EarlyLate::early(), factor, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(factor, 0.98f);
|
|
}
|
|
|
|
// DeratingFactorsGlobal clear
|
|
TEST_F(SdcInitTest, R8_DeratingFactorsGlobalClear) {
|
|
DeratingFactorsGlobal dfg;
|
|
dfg.setFactor(TimingDerateType::net_delay, PathClkOrData::data,
|
|
RiseFallBoth::riseFall(), EarlyLate::late(), 1.05f);
|
|
dfg.clear();
|
|
float factor;
|
|
bool exists;
|
|
dfg.factor(TimingDerateType::net_delay, PathClkOrData::data,
|
|
RiseFall::rise(), EarlyLate::late(), factor, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
// DeratingFactorsGlobal factors accessor
|
|
TEST_F(SdcInitTest, R8_DeratingFactorsGlobalFactorsAccessor) {
|
|
DeratingFactorsGlobal dfg;
|
|
DeratingFactors *df = dfg.factors(TimingDerateType::cell_check);
|
|
EXPECT_NE(df, nullptr);
|
|
}
|
|
|
|
// DeratingFactorsGlobal with TimingDerateCellType
|
|
TEST_F(SdcInitTest, R8_DeratingFactorsGlobalCellType) {
|
|
DeratingFactorsGlobal dfg;
|
|
dfg.setFactor(TimingDerateType::cell_check, PathClkOrData::data,
|
|
RiseFallBoth::fall(), EarlyLate::late(), 1.02f);
|
|
float factor;
|
|
bool exists;
|
|
dfg.factor(TimingDerateCellType::cell_check, PathClkOrData::data,
|
|
RiseFall::fall(), EarlyLate::late(), factor, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(factor, 1.02f);
|
|
}
|
|
|
|
// DeratingFactorsCell
|
|
TEST_F(SdcInitTest, R8_DeratingFactorsCellDefault) {
|
|
DeratingFactorsCell dfc;
|
|
float factor;
|
|
bool exists;
|
|
dfc.factor(TimingDerateCellType::cell_delay, PathClkOrData::clk,
|
|
RiseFall::rise(), EarlyLate::early(), factor, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
// DeratingFactorsCell set and get
|
|
TEST_F(SdcInitTest, R8_DeratingFactorsCellSetGet) {
|
|
DeratingFactorsCell dfc;
|
|
dfc.setFactor(TimingDerateCellType::cell_delay, PathClkOrData::data,
|
|
RiseFallBoth::riseFall(), EarlyLate::early(), 0.97f);
|
|
float factor;
|
|
bool exists;
|
|
dfc.factor(TimingDerateCellType::cell_delay, PathClkOrData::data,
|
|
RiseFall::rise(), EarlyLate::early(), factor, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(factor, 0.97f);
|
|
}
|
|
|
|
// DeratingFactorsCell clear
|
|
TEST_F(SdcInitTest, R8_DeratingFactorsCellClear) {
|
|
DeratingFactorsCell dfc;
|
|
dfc.setFactor(TimingDerateCellType::cell_check, PathClkOrData::clk,
|
|
RiseFallBoth::rise(), EarlyLate::late(), 1.1f);
|
|
dfc.clear();
|
|
float factor;
|
|
bool exists;
|
|
dfc.factor(TimingDerateCellType::cell_check, PathClkOrData::clk,
|
|
RiseFall::rise(), EarlyLate::late(), factor, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
// DeratingFactorsCell factors accessor
|
|
TEST_F(SdcInitTest, R8_DeratingFactorsCellFactorsAccessor) {
|
|
DeratingFactorsCell dfc;
|
|
DeratingFactors *df = dfc.factors(TimingDerateCellType::cell_delay);
|
|
EXPECT_NE(df, nullptr);
|
|
}
|
|
|
|
// DeratingFactorsCell isOneValue
|
|
TEST_F(SdcInitTest, R8_DeratingFactorsCellIsOneValue) {
|
|
DeratingFactorsCell dfc;
|
|
dfc.setFactor(TimingDerateCellType::cell_delay, PathClkOrData::clk,
|
|
RiseFallBoth::riseFall(), EarlyLate::early(), 0.95f);
|
|
dfc.setFactor(TimingDerateCellType::cell_delay, PathClkOrData::data,
|
|
RiseFallBoth::riseFall(), EarlyLate::early(), 0.95f);
|
|
dfc.setFactor(TimingDerateCellType::cell_check, PathClkOrData::clk,
|
|
RiseFallBoth::riseFall(), EarlyLate::early(), 0.95f);
|
|
dfc.setFactor(TimingDerateCellType::cell_check, PathClkOrData::data,
|
|
RiseFallBoth::riseFall(), EarlyLate::early(), 0.95f);
|
|
bool is_one;
|
|
float val;
|
|
dfc.isOneValue(EarlyLate::early(), is_one, val);
|
|
if (is_one)
|
|
EXPECT_FLOAT_EQ(val, 0.95f);
|
|
}
|
|
|
|
// DeratingFactorsNet
|
|
TEST_F(SdcInitTest, R8_DeratingFactorsNetDefault) {
|
|
DeratingFactorsNet dfn;
|
|
EXPECT_FALSE(dfn.hasValue());
|
|
}
|
|
|
|
// DeratingFactorsNet set and get
|
|
TEST_F(SdcInitTest, R8_DeratingFactorsNetSetGet) {
|
|
DeratingFactorsNet dfn;
|
|
dfn.setFactor(PathClkOrData::data, RiseFallBoth::riseFall(),
|
|
EarlyLate::late(), 1.03f);
|
|
float factor;
|
|
bool exists;
|
|
dfn.factor(PathClkOrData::data, RiseFall::fall(),
|
|
EarlyLate::late(), factor, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(factor, 1.03f);
|
|
}
|
|
|
|
// ClockLatency construction
|
|
TEST_F(SdcInitTest, R8_ClockLatencyConstruct) {
|
|
ClockLatency lat(nullptr, nullptr);
|
|
EXPECT_EQ(lat.clock(), nullptr);
|
|
EXPECT_EQ(lat.pin(), nullptr);
|
|
}
|
|
|
|
// ClockLatency set and get
|
|
TEST_F(SdcInitTest, R8_ClockLatencySetGet) {
|
|
ClockLatency lat(nullptr, nullptr);
|
|
lat.setDelay(RiseFallBoth::riseFall(), MinMaxAll::all(), 1.5f);
|
|
float delay;
|
|
bool exists;
|
|
lat.delay(RiseFall::rise(), MinMax::max(), delay, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(delay, 1.5f);
|
|
}
|
|
|
|
// ClockLatency delays accessor
|
|
TEST_F(SdcInitTest, R8_ClockLatencyDelaysAccessor) {
|
|
ClockLatency lat(nullptr, nullptr);
|
|
lat.setDelay(RiseFallBoth::rise(), MinMaxAll::min(), 0.5f);
|
|
RiseFallMinMax *delays = lat.delays();
|
|
EXPECT_NE(delays, nullptr);
|
|
EXPECT_TRUE(delays->hasValue());
|
|
}
|
|
|
|
// ClockInsertion construction
|
|
TEST_F(SdcInitTest, R8_ClockInsertionConstruct) {
|
|
ClockInsertion ins(nullptr, nullptr);
|
|
EXPECT_EQ(ins.clock(), nullptr);
|
|
EXPECT_EQ(ins.pin(), nullptr);
|
|
}
|
|
|
|
// ClockInsertion set and get
|
|
TEST_F(SdcInitTest, R8_ClockInsertionSetGet) {
|
|
ClockInsertion ins(nullptr, nullptr);
|
|
ins.setDelay(RiseFallBoth::riseFall(), MinMaxAll::all(),
|
|
EarlyLateAll::all(), 2.0f);
|
|
float insertion;
|
|
bool exists;
|
|
ins.delay(RiseFall::rise(), MinMax::max(),
|
|
EarlyLate::early(), insertion, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(insertion, 2.0f);
|
|
}
|
|
|
|
// ClockInsertion delays accessor
|
|
TEST_F(SdcInitTest, R8_ClockInsertionDelaysAccessor) {
|
|
ClockInsertion ins(nullptr, nullptr);
|
|
ins.setDelay(RiseFallBoth::rise(), MinMaxAll::min(),
|
|
EarlyLateAll::early(), 0.3f);
|
|
RiseFallMinMax *delays = ins.delays(EarlyLate::early());
|
|
EXPECT_NE(delays, nullptr);
|
|
}
|
|
|
|
// ClockGatingCheck
|
|
TEST_F(SdcInitTest, R8_ClockGatingCheckConstruct) {
|
|
ClockGatingCheck cgc;
|
|
RiseFallMinMax *margins = cgc.margins();
|
|
EXPECT_NE(margins, nullptr);
|
|
}
|
|
|
|
// ClockGatingCheck active value
|
|
TEST_F(SdcInitTest, R8_ClockGatingCheckActiveValue) {
|
|
ClockGatingCheck cgc;
|
|
cgc.setActiveValue(LogicValue::one);
|
|
EXPECT_EQ(cgc.activeValue(), LogicValue::one);
|
|
cgc.setActiveValue(LogicValue::zero);
|
|
EXPECT_EQ(cgc.activeValue(), LogicValue::zero);
|
|
}
|
|
|
|
// InputDrive construction
|
|
TEST_F(SdcInitTest, R8_InputDriveConstruct) {
|
|
InputDrive drive;
|
|
float res;
|
|
bool exists;
|
|
drive.driveResistance(RiseFall::rise(), MinMax::max(), res, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
// InputDrive set slew
|
|
TEST_F(SdcInitTest, R8_InputDriveSetSlew) {
|
|
InputDrive drive;
|
|
drive.setSlew(RiseFallBoth::riseFall(), MinMaxAll::all(), 0.1f);
|
|
float slew;
|
|
bool exists;
|
|
drive.slew(RiseFall::rise(), MinMax::max(), slew, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(slew, 0.1f);
|
|
}
|
|
|
|
// InputDrive set resistance
|
|
TEST_F(SdcInitTest, R8_InputDriveSetResistance) {
|
|
InputDrive drive;
|
|
drive.setDriveResistance(RiseFallBoth::riseFall(), MinMaxAll::all(), 50.0f);
|
|
float res;
|
|
bool exists;
|
|
drive.driveResistance(RiseFall::rise(), MinMax::max(), res, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(res, 50.0f);
|
|
EXPECT_TRUE(drive.hasDriveResistance(RiseFall::rise(), MinMax::max()));
|
|
}
|
|
|
|
// InputDrive drive resistance min/max equal
|
|
TEST_F(SdcInitTest, R8_InputDriveResistanceEqual) {
|
|
InputDrive drive;
|
|
drive.setDriveResistance(RiseFallBoth::riseFall(), MinMaxAll::all(), 100.0f);
|
|
EXPECT_TRUE(drive.driveResistanceMinMaxEqual(RiseFall::rise()));
|
|
}
|
|
|
|
// InputDrive drive resistance min/max not equal
|
|
TEST_F(SdcInitTest, R8_InputDriveResistanceNotEqual) {
|
|
InputDrive drive;
|
|
drive.setDriveResistance(RiseFallBoth::rise(), MinMaxAll::min(), 50.0f);
|
|
drive.setDriveResistance(RiseFallBoth::rise(), MinMaxAll::max(), 100.0f);
|
|
EXPECT_FALSE(drive.driveResistanceMinMaxEqual(RiseFall::rise()));
|
|
}
|
|
|
|
// InputDrive no drive cell
|
|
TEST_F(SdcInitTest, R8_InputDriveNoDriveCell) {
|
|
InputDrive drive;
|
|
EXPECT_FALSE(drive.hasDriveCell(RiseFall::rise(), MinMax::max()));
|
|
}
|
|
|
|
// InputDrive slews accessor
|
|
TEST_F(SdcInitTest, R8_InputDriveSlewsAccessor) {
|
|
InputDrive drive;
|
|
drive.setSlew(RiseFallBoth::rise(), MinMaxAll::max(), 0.2f);
|
|
const RiseFallMinMax *slews = drive.slews();
|
|
EXPECT_NE(slews, nullptr);
|
|
EXPECT_TRUE(slews->hasValue());
|
|
}
|
|
|
|
// ExceptionPath priorities
|
|
TEST_F(SdcInitTest, R8_ExceptionPathPriorities) {
|
|
EXPECT_EQ(ExceptionPath::falsePathPriority(), 4000);
|
|
EXPECT_EQ(ExceptionPath::pathDelayPriority(), 3000);
|
|
EXPECT_EQ(ExceptionPath::multiCyclePathPriority(), 2000);
|
|
EXPECT_EQ(ExceptionPath::filterPathPriority(), 1000);
|
|
EXPECT_EQ(ExceptionPath::groupPathPriority(), 0);
|
|
}
|
|
|
|
// FalsePath creation and type
|
|
TEST_F(SdcInitTest, R8_FalsePathType) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, nullptr);
|
|
EXPECT_TRUE(fp.isFalse());
|
|
EXPECT_FALSE(fp.isLoop());
|
|
EXPECT_FALSE(fp.isMultiCycle());
|
|
EXPECT_FALSE(fp.isPathDelay());
|
|
EXPECT_FALSE(fp.isGroupPath());
|
|
EXPECT_FALSE(fp.isFilter());
|
|
EXPECT_EQ(fp.type(), ExceptionPathType::false_path);
|
|
}
|
|
|
|
// FalsePath priority
|
|
TEST_F(SdcInitTest, R8_FalsePathPriority) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, nullptr);
|
|
EXPECT_EQ(fp.typePriority(), ExceptionPath::falsePathPriority());
|
|
}
|
|
|
|
// PathDelay creation and type
|
|
TEST_F(SdcInitTest, R8_PathDelayType) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, false, nullptr);
|
|
EXPECT_TRUE(pd.isPathDelay());
|
|
EXPECT_FALSE(pd.isFalse());
|
|
EXPECT_EQ(pd.type(), ExceptionPathType::path_delay);
|
|
EXPECT_FLOAT_EQ(pd.delay(), 5.0f);
|
|
}
|
|
|
|
// PathDelay ignoreClkLatency
|
|
TEST_F(SdcInitTest, R8_PathDelayIgnoreClkLatency) {
|
|
PathDelay pd1(nullptr, nullptr, nullptr, MinMax::max(),
|
|
true, false, 3.0f, false, nullptr);
|
|
EXPECT_TRUE(pd1.ignoreClkLatency());
|
|
PathDelay pd2(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 3.0f, false, nullptr);
|
|
EXPECT_FALSE(pd2.ignoreClkLatency());
|
|
}
|
|
|
|
// PathDelay breakPath
|
|
TEST_F(SdcInitTest, R8_PathDelayBreakPath) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, true, 3.0f, false, nullptr);
|
|
EXPECT_TRUE(pd.breakPath());
|
|
}
|
|
|
|
// PathDelay tighterThan
|
|
TEST_F(SdcInitTest, R8_PathDelayTighterThanMin) {
|
|
PathDelay pd1(nullptr, nullptr, nullptr, MinMax::min(),
|
|
false, false, 3.0f, false, nullptr);
|
|
PathDelay pd2(nullptr, nullptr, nullptr, MinMax::min(),
|
|
false, false, 5.0f, false, nullptr);
|
|
// For min, larger delay is tighter
|
|
EXPECT_TRUE(pd2.tighterThan(&pd1));
|
|
}
|
|
|
|
// PathDelay tighterThan max
|
|
TEST_F(SdcInitTest, R8_PathDelayTighterThanMax) {
|
|
PathDelay pd1(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 3.0f, false, nullptr);
|
|
PathDelay pd2(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, false, nullptr);
|
|
// For max, smaller delay is tighter
|
|
EXPECT_TRUE(pd1.tighterThan(&pd2));
|
|
}
|
|
|
|
// MultiCyclePath creation and type
|
|
TEST_F(SdcInitTest, R8_MultiCyclePathType) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, false, nullptr);
|
|
EXPECT_TRUE(mcp.isMultiCycle());
|
|
EXPECT_EQ(mcp.type(), ExceptionPathType::multi_cycle);
|
|
EXPECT_EQ(mcp.pathMultiplier(), 3);
|
|
EXPECT_TRUE(mcp.useEndClk());
|
|
}
|
|
|
|
// MultiCyclePath with start clk
|
|
TEST_F(SdcInitTest, R8_MultiCyclePathStartClk) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
false, 2, false, nullptr);
|
|
EXPECT_FALSE(mcp.useEndClk());
|
|
EXPECT_EQ(mcp.pathMultiplier(), 2);
|
|
}
|
|
|
|
// MultiCyclePath tighterThan
|
|
TEST_F(SdcInitTest, R8_MultiCyclePathTighterThan) {
|
|
MultiCyclePath mcp1(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 2, false, nullptr);
|
|
MultiCyclePath mcp2(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 4, false, nullptr);
|
|
// For setup, larger multiplier is tighter
|
|
bool t1 = mcp1.tighterThan(&mcp2);
|
|
bool t2 = mcp2.tighterThan(&mcp1);
|
|
// One should be tighter than the other
|
|
EXPECT_NE(t1, t2);
|
|
}
|
|
|
|
// FilterPath creation and type
|
|
TEST_F(SdcInitTest, R8_FilterPathType) {
|
|
FilterPath fp(nullptr, nullptr, nullptr, false);
|
|
EXPECT_TRUE(fp.isFilter());
|
|
EXPECT_EQ(fp.type(), ExceptionPathType::filter);
|
|
}
|
|
|
|
// GroupPath creation and type
|
|
TEST_F(SdcInitTest, R8_GroupPathType) {
|
|
GroupPath gp("test_group", false, nullptr, nullptr, nullptr, false, nullptr);
|
|
EXPECT_TRUE(gp.isGroupPath());
|
|
EXPECT_EQ(gp.type(), ExceptionPathType::group_path);
|
|
EXPECT_STREQ(gp.name(), "test_group");
|
|
EXPECT_FALSE(gp.isDefault());
|
|
}
|
|
|
|
// GroupPath default
|
|
TEST_F(SdcInitTest, R8_GroupPathDefault) {
|
|
GroupPath gp("default_group", true, nullptr, nullptr, nullptr, false, nullptr);
|
|
EXPECT_TRUE(gp.isDefault());
|
|
}
|
|
|
|
// LoopPath creation
|
|
TEST_F(SdcInitTest, R8_LoopPathType) {
|
|
LoopPath lp(nullptr, false);
|
|
EXPECT_TRUE(lp.isFalse());
|
|
EXPECT_TRUE(lp.isLoop());
|
|
EXPECT_EQ(lp.type(), ExceptionPathType::loop);
|
|
}
|
|
|
|
// ExceptionPath minMax
|
|
TEST_F(SdcInitTest, R8_ExceptionPathMinMax) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::min(), false, nullptr);
|
|
EXPECT_EQ(fp.minMax(), MinMaxAll::min());
|
|
EXPECT_TRUE(fp.matches(MinMax::min(), true));
|
|
EXPECT_FALSE(fp.matches(MinMax::max(), true));
|
|
}
|
|
|
|
// ExceptionPath matches min/max all
|
|
TEST_F(SdcInitTest, R8_ExceptionPathMatchesAll) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, nullptr);
|
|
EXPECT_TRUE(fp.matches(MinMax::min(), true));
|
|
EXPECT_TRUE(fp.matches(MinMax::max(), true));
|
|
}
|
|
|
|
// FalsePath hash
|
|
TEST_F(SdcInitTest, R8_FalsePathHash) {
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::all(), false, nullptr);
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::all(), false, nullptr);
|
|
// Same structure should have same hash
|
|
EXPECT_EQ(fp1.hash(), fp2.hash());
|
|
}
|
|
|
|
// FalsePath overrides
|
|
TEST_F(SdcInitTest, R8_FalsePathOverrides) {
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::all(), false, nullptr);
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::all(), false, nullptr);
|
|
EXPECT_TRUE(fp1.overrides(&fp2));
|
|
}
|
|
|
|
// PathDelay hash
|
|
TEST_F(SdcInitTest, R8_PathDelayHashR8) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, false, nullptr);
|
|
size_t h = pd.hash();
|
|
EXPECT_GT(h, 0u);
|
|
}
|
|
|
|
// FalsePath not mergeable with PathDelay
|
|
TEST_F(SdcInitTest, R8_FalsePathNotMergeablePathDelay) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, nullptr);
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, false, nullptr);
|
|
EXPECT_FALSE(fp.mergeable(&pd));
|
|
}
|
|
|
|
// GroupPath tighterThan
|
|
TEST_F(SdcInitTest, R8_GroupPathTighterThan) {
|
|
GroupPath gp1("g1", false, nullptr, nullptr, nullptr, false, nullptr);
|
|
GroupPath gp2("g2", false, nullptr, nullptr, nullptr, false, nullptr);
|
|
// Group paths have no value to compare
|
|
bool t = gp1.tighterThan(&gp2);
|
|
(void)t;
|
|
}
|
|
|
|
// FilterPath tighterThan
|
|
TEST_F(SdcInitTest, R8_FilterPathTighterThan) {
|
|
FilterPath fp1(nullptr, nullptr, nullptr, false);
|
|
FilterPath fp2(nullptr, nullptr, nullptr, false);
|
|
bool t = fp1.tighterThan(&fp2);
|
|
(void)t;
|
|
}
|
|
|
|
// ExceptionPath id
|
|
TEST_F(SdcInitTest, R8_ExceptionPathId) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, nullptr);
|
|
fp.setId(42);
|
|
EXPECT_EQ(fp.id(), 42u);
|
|
}
|
|
|
|
// ExceptionPath setPriority
|
|
TEST_F(SdcInitTest, R8_ExceptionPathSetPriority) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, nullptr);
|
|
fp.setPriority(999);
|
|
EXPECT_EQ(fp.priority(), 999);
|
|
}
|
|
|
|
// ExceptionPath useEndClk default
|
|
TEST_F(SdcInitTest, R8_ExceptionPathUseEndClkDefault) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, nullptr);
|
|
EXPECT_FALSE(fp.useEndClk());
|
|
}
|
|
|
|
// ExceptionPath pathMultiplier default
|
|
TEST_F(SdcInitTest, R8_ExceptionPathPathMultiplierDefault) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, nullptr);
|
|
EXPECT_EQ(fp.pathMultiplier(), 0);
|
|
}
|
|
|
|
// ExceptionPath delay default
|
|
TEST_F(SdcInitTest, R8_ExceptionPathDelayDefault) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, nullptr);
|
|
EXPECT_FLOAT_EQ(fp.delay(), 0.0f);
|
|
}
|
|
|
|
// ExceptionPath name default
|
|
TEST_F(SdcInitTest, R8_ExceptionPathNameDefault) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, nullptr);
|
|
EXPECT_EQ(fp.name(), nullptr);
|
|
}
|
|
|
|
// ExceptionPath isDefault
|
|
TEST_F(SdcInitTest, R8_ExceptionPathIsDefault) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, nullptr);
|
|
EXPECT_FALSE(fp.isDefault());
|
|
}
|
|
|
|
// ExceptionPath ignoreClkLatency default
|
|
TEST_F(SdcInitTest, R8_ExceptionPathIgnoreClkLatencyDefault) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, nullptr);
|
|
EXPECT_FALSE(fp.ignoreClkLatency());
|
|
}
|
|
|
|
// ExceptionPath breakPath default
|
|
TEST_F(SdcInitTest, R8_ExceptionPathBreakPathDefault) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, nullptr);
|
|
EXPECT_FALSE(fp.breakPath());
|
|
}
|
|
|
|
// Clock slew set and get
|
|
TEST_F(SdcInitTest, R8_ClockSlewSetGet) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_slew_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_slew_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
clk->setSlew(RiseFallBoth::riseFall(), MinMaxAll::all(), 0.1f);
|
|
float slew;
|
|
bool exists;
|
|
clk->slew(RiseFall::rise(), MinMax::max(), slew, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(slew, 0.1f);
|
|
}
|
|
|
|
// Clock removeSlew
|
|
TEST_F(SdcInitTest, R8_ClockRemoveSlew) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_rslew_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_rslew_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
clk->setSlew(RiseFallBoth::riseFall(), MinMaxAll::all(), 0.2f);
|
|
clk->removeSlew();
|
|
float slew;
|
|
bool exists;
|
|
clk->slew(RiseFall::rise(), MinMax::max(), slew, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
// Clock slews accessor
|
|
TEST_F(SdcInitTest, R8_ClockSlewsAccessor) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_slews_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_slews_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
clk->setSlew(RiseFallBoth::rise(), MinMaxAll::max(), 0.15f);
|
|
const RiseFallMinMax &slews = clk->slews();
|
|
EXPECT_TRUE(slews.hasValue());
|
|
}
|
|
|
|
// Clock period
|
|
TEST_F(SdcInitTest, R8_ClockPeriod) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(10.0);
|
|
sta_->makeClock("r8_per_clk", nullptr, false, 20.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_per_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
EXPECT_FLOAT_EQ(clk->period(), 20.0f);
|
|
}
|
|
|
|
// Clock period access via makeClock
|
|
TEST_F(SdcInitTest, R8_ClockPeriodAccess) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(12.5);
|
|
sta_->makeClock("r8_pera_clk", nullptr, false, 25.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_pera_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
EXPECT_FLOAT_EQ(clk->period(), 25.0f);
|
|
}
|
|
|
|
// Clock isVirtual
|
|
TEST_F(SdcInitTest, R8_ClockIsVirtual) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_virt_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_virt_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
// Virtual clock has no pins
|
|
EXPECT_TRUE(clk->isVirtual());
|
|
}
|
|
|
|
// Clock isPropagated
|
|
TEST_F(SdcInitTest, R8_ClockIsPropagated) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_prop_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_prop_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
EXPECT_FALSE(clk->isPropagated());
|
|
clk->setIsPropagated(true);
|
|
EXPECT_TRUE(clk->isPropagated());
|
|
EXPECT_FALSE(clk->isIdeal());
|
|
}
|
|
|
|
// Clock isIdeal
|
|
TEST_F(SdcInitTest, R8_ClockIsIdeal) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_ideal_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_ideal_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
EXPECT_TRUE(clk->isIdeal());
|
|
}
|
|
|
|
// Clock edge
|
|
TEST_F(SdcInitTest, R8_ClockEdge) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_edge_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_edge_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockEdge *rise_edge = clk->edge(RiseFall::rise());
|
|
ClockEdge *fall_edge = clk->edge(RiseFall::fall());
|
|
EXPECT_NE(rise_edge, nullptr);
|
|
EXPECT_NE(fall_edge, nullptr);
|
|
EXPECT_NE(rise_edge, fall_edge);
|
|
}
|
|
|
|
// ClockEdge properties
|
|
TEST_F(SdcInitTest, R8_ClockEdgeProperties) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_edgep_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_edgep_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockEdge *rise = clk->edge(RiseFall::rise());
|
|
EXPECT_EQ(rise->clock(), clk);
|
|
EXPECT_EQ(rise->transition(), RiseFall::rise());
|
|
EXPECT_FLOAT_EQ(rise->time(), 0.0f);
|
|
EXPECT_NE(rise->name(), nullptr);
|
|
}
|
|
|
|
// ClockEdge opposite
|
|
TEST_F(SdcInitTest, R8_ClockEdgeOpposite) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_opp_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_opp_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockEdge *rise = clk->edge(RiseFall::rise());
|
|
ClockEdge *fall = clk->edge(RiseFall::fall());
|
|
EXPECT_EQ(rise->opposite(), fall);
|
|
EXPECT_EQ(fall->opposite(), rise);
|
|
}
|
|
|
|
// ClockEdge pulseWidth
|
|
TEST_F(SdcInitTest, R8_ClockEdgePulseWidth) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_pw_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_pw_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockEdge *rise = clk->edge(RiseFall::rise());
|
|
float pw = rise->pulseWidth();
|
|
EXPECT_FLOAT_EQ(pw, 5.0f); // 50% duty cycle
|
|
}
|
|
|
|
// ClockEdge index
|
|
TEST_F(SdcInitTest, R8_ClockEdgeIndex) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_idx_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_idx_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockEdge *rise = clk->edge(RiseFall::rise());
|
|
ClockEdge *fall = clk->edge(RiseFall::fall());
|
|
EXPECT_NE(rise->index(), fall->index());
|
|
}
|
|
|
|
// Clock uncertainty
|
|
TEST_F(SdcInitTest, R8_ClockUncertainty) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_unc_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_unc_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
clk->setUncertainty(SetupHoldAll::max(), 0.5f);
|
|
float unc;
|
|
bool exists;
|
|
clk->uncertainty(SetupHold::max(), unc, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(unc, 0.5f);
|
|
}
|
|
|
|
// Clock removeUncertainty
|
|
TEST_F(SdcInitTest, R8_ClockRemoveUncertainty) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_runc_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_runc_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
clk->setUncertainty(SetupHoldAll::all(), 0.3f);
|
|
clk->removeUncertainty(SetupHoldAll::all());
|
|
float unc;
|
|
bool exists;
|
|
clk->uncertainty(SetupHold::max(), unc, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
// Clock isGenerated
|
|
TEST_F(SdcInitTest, R8_ClockIsGenerated) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_gen_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_gen_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
EXPECT_FALSE(clk->isGenerated());
|
|
}
|
|
|
|
// Clock addToPins
|
|
TEST_F(SdcInitTest, R8_ClockAddToPins) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_atp_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_atp_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
clk->setAddToPins(true);
|
|
EXPECT_TRUE(clk->addToPins());
|
|
clk->setAddToPins(false);
|
|
EXPECT_FALSE(clk->addToPins());
|
|
}
|
|
|
|
// Clock waveform
|
|
TEST_F(SdcInitTest, R8_ClockWaveform) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_wf_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_wf_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
FloatSeq *wave = clk->waveform();
|
|
EXPECT_NE(wave, nullptr);
|
|
EXPECT_EQ(wave->size(), 2u);
|
|
}
|
|
|
|
// Clock index
|
|
TEST_F(SdcInitTest, R8_ClockIndex) {
|
|
FloatSeq *wf1 = new FloatSeq;
|
|
wf1->push_back(0.0);
|
|
wf1->push_back(5.0);
|
|
sta_->makeClock("r8_idx1_clk", nullptr, false, 10.0, wf1, nullptr);
|
|
FloatSeq *wf2 = new FloatSeq;
|
|
wf2->push_back(0.0);
|
|
wf2->push_back(10.0);
|
|
sta_->makeClock("r8_idx2_clk", nullptr, false, 20.0, wf2, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk1 = sdc->findClock("r8_idx1_clk");
|
|
Clock *clk2 = sdc->findClock("r8_idx2_clk");
|
|
ASSERT_NE(clk1, nullptr);
|
|
ASSERT_NE(clk2, nullptr);
|
|
EXPECT_NE(clk1->index(), clk2->index());
|
|
}
|
|
|
|
// Clock combinational
|
|
TEST_F(SdcInitTest, R8_ClockCombinational) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_comb_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_comb_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
// Non-generated clock has no combinational flag
|
|
EXPECT_FALSE(clk->combinational());
|
|
}
|
|
|
|
// InterClockUncertainty
|
|
TEST_F(SdcInitTest, R8_InterClockUncertaintyConstruct) {
|
|
FloatSeq *wf1 = new FloatSeq;
|
|
wf1->push_back(0.0);
|
|
wf1->push_back(5.0);
|
|
sta_->makeClock("r8_icus_clk", nullptr, false, 10.0, wf1, nullptr);
|
|
FloatSeq *wf2 = new FloatSeq;
|
|
wf2->push_back(0.0);
|
|
wf2->push_back(5.0);
|
|
sta_->makeClock("r8_icut_clk", nullptr, false, 10.0, wf2, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk1 = sdc->findClock("r8_icus_clk");
|
|
Clock *clk2 = sdc->findClock("r8_icut_clk");
|
|
InterClockUncertainty icu(clk1, clk2);
|
|
EXPECT_EQ(icu.src(), clk1);
|
|
EXPECT_EQ(icu.target(), clk2);
|
|
EXPECT_TRUE(icu.empty());
|
|
}
|
|
|
|
// InterClockUncertainty set and get
|
|
TEST_F(SdcInitTest, R8_InterClockUncertaintySetGet) {
|
|
FloatSeq *wf1 = new FloatSeq;
|
|
wf1->push_back(0.0);
|
|
wf1->push_back(5.0);
|
|
sta_->makeClock("r8_icu2s_clk", nullptr, false, 10.0, wf1, nullptr);
|
|
FloatSeq *wf2 = new FloatSeq;
|
|
wf2->push_back(0.0);
|
|
wf2->push_back(5.0);
|
|
sta_->makeClock("r8_icu2t_clk", nullptr, false, 10.0, wf2, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk1 = sdc->findClock("r8_icu2s_clk");
|
|
Clock *clk2 = sdc->findClock("r8_icu2t_clk");
|
|
InterClockUncertainty icu(clk1, clk2);
|
|
icu.setUncertainty(RiseFallBoth::riseFall(), RiseFallBoth::riseFall(),
|
|
SetupHoldAll::all(), 0.3f);
|
|
EXPECT_FALSE(icu.empty());
|
|
float unc;
|
|
bool exists;
|
|
icu.uncertainty(RiseFall::rise(), RiseFall::rise(),
|
|
SetupHold::max(), unc, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(unc, 0.3f);
|
|
}
|
|
|
|
// InterClockUncertainty removeUncertainty
|
|
TEST_F(SdcInitTest, R8_InterClockUncertaintyRemove) {
|
|
FloatSeq *wf1 = new FloatSeq;
|
|
wf1->push_back(0.0);
|
|
wf1->push_back(5.0);
|
|
sta_->makeClock("r8_icu3s_clk", nullptr, false, 10.0, wf1, nullptr);
|
|
FloatSeq *wf2 = new FloatSeq;
|
|
wf2->push_back(0.0);
|
|
wf2->push_back(5.0);
|
|
sta_->makeClock("r8_icu3t_clk", nullptr, false, 10.0, wf2, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk1 = sdc->findClock("r8_icu3s_clk");
|
|
Clock *clk2 = sdc->findClock("r8_icu3t_clk");
|
|
InterClockUncertainty icu(clk1, clk2);
|
|
icu.setUncertainty(RiseFallBoth::riseFall(), RiseFallBoth::riseFall(),
|
|
SetupHoldAll::all(), 0.5f);
|
|
icu.removeUncertainty(RiseFallBoth::riseFall(), RiseFallBoth::riseFall(),
|
|
SetupHoldAll::all());
|
|
EXPECT_TRUE(icu.empty());
|
|
}
|
|
|
|
// InterClockUncertainty uncertainties accessor
|
|
TEST_F(SdcInitTest, R8_InterClockUncertaintyAccessor) {
|
|
FloatSeq *wf1 = new FloatSeq;
|
|
wf1->push_back(0.0);
|
|
wf1->push_back(5.0);
|
|
sta_->makeClock("r8_icu4s_clk", nullptr, false, 10.0, wf1, nullptr);
|
|
FloatSeq *wf2 = new FloatSeq;
|
|
wf2->push_back(0.0);
|
|
wf2->push_back(5.0);
|
|
sta_->makeClock("r8_icu4t_clk", nullptr, false, 10.0, wf2, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk1 = sdc->findClock("r8_icu4s_clk");
|
|
Clock *clk2 = sdc->findClock("r8_icu4t_clk");
|
|
InterClockUncertainty icu(clk1, clk2);
|
|
icu.setUncertainty(RiseFallBoth::rise(), RiseFallBoth::rise(),
|
|
SetupHoldAll::max(), 0.2f);
|
|
const RiseFallMinMax *uncerts = icu.uncertainties(RiseFall::rise());
|
|
EXPECT_NE(uncerts, nullptr);
|
|
}
|
|
|
|
// Sdc::setTimingDerate global
|
|
TEST_F(SdcInitTest, R8_SdcSetTimingDerateGlobal) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setTimingDerate(TimingDerateType::cell_delay,
|
|
PathClkOrData::clk,
|
|
RiseFallBoth::riseFall(),
|
|
EarlyLate::early(), 0.95f);
|
|
// Should not crash
|
|
sdc->unsetTimingDerate();
|
|
}
|
|
|
|
// Sdc::setMaxArea and maxArea
|
|
TEST_F(SdcInitTest, R8_SdcSetMaxAreaR8) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setMaxArea(500.0f);
|
|
EXPECT_FLOAT_EQ(sdc->maxArea(), 500.0f);
|
|
}
|
|
|
|
// Sdc::setAnalysisType
|
|
TEST_F(SdcInitTest, R8_SdcSetAnalysisTypeR8) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setAnalysisType(AnalysisType::bc_wc);
|
|
EXPECT_EQ(sdc->analysisType(), AnalysisType::bc_wc);
|
|
sdc->setAnalysisType(AnalysisType::ocv);
|
|
EXPECT_EQ(sdc->analysisType(), AnalysisType::ocv);
|
|
sdc->setAnalysisType(AnalysisType::single);
|
|
EXPECT_EQ(sdc->analysisType(), AnalysisType::single);
|
|
}
|
|
|
|
// Sdc::setWireloadMode
|
|
TEST_F(SdcInitTest, R8_SdcSetWireloadModeR8) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setWireloadMode(WireloadMode::enclosed);
|
|
// Just verify no crash
|
|
sdc->setWireloadMode(WireloadMode::segmented);
|
|
sdc->setWireloadMode(WireloadMode::top);
|
|
}
|
|
|
|
// Sdc::setPropagatedClock / removePropagatedClock
|
|
TEST_F(SdcInitTest, R8_SdcPropagatedClock) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_propt_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_propt_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
sdc->setPropagatedClock(clk);
|
|
EXPECT_TRUE(clk->isPropagated());
|
|
sdc->removePropagatedClock(clk);
|
|
EXPECT_FALSE(clk->isPropagated());
|
|
}
|
|
|
|
// Sdc::setClockSlew
|
|
TEST_F(SdcInitTest, R8_SdcSetClockSlew) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_sslew_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_sslew_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
sdc->setClockSlew(clk, RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), 0.2f);
|
|
float slew = clk->slew(RiseFall::rise(), MinMax::max());
|
|
EXPECT_FLOAT_EQ(slew, 0.2f);
|
|
}
|
|
|
|
// Sdc::removeClockSlew
|
|
TEST_F(SdcInitTest, R8_SdcRemoveClockSlew) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_srslew_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_srslew_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
sdc->setClockSlew(clk, RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), 0.3f);
|
|
sdc->removeClockSlew(clk);
|
|
float slew = clk->slew(RiseFall::rise(), MinMax::max());
|
|
EXPECT_FLOAT_EQ(slew, 0.0f);
|
|
}
|
|
|
|
// Sdc::setClockLatency
|
|
TEST_F(SdcInitTest, R8_SdcSetClockLatency) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_slat_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_slat_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
sdc->setClockLatency(clk, nullptr, RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), 1.0f);
|
|
float latency;
|
|
bool exists;
|
|
sdc->clockLatency(clk, RiseFall::rise(), MinMax::max(),
|
|
latency, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(latency, 1.0f);
|
|
}
|
|
|
|
// Sdc::removeClockLatency
|
|
TEST_F(SdcInitTest, R8_SdcRemoveClockLatency) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_srlat_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_srlat_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
sdc->setClockLatency(clk, nullptr, RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), 2.0f);
|
|
sdc->removeClockLatency(clk, nullptr);
|
|
float latency;
|
|
bool exists;
|
|
sdc->clockLatency(clk, RiseFall::rise(), MinMax::max(),
|
|
latency, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
// Sdc::clockLatencies accessor
|
|
TEST_F(SdcInitTest, R8_SdcClockLatencies) {
|
|
Sdc *sdc = sta_->sdc();
|
|
const ClockLatencies *lats = sdc->clockLatencies();
|
|
EXPECT_NE(lats, nullptr);
|
|
}
|
|
|
|
// Sdc::clockLatency (float overload)
|
|
TEST_F(SdcInitTest, R8_SdcClockLatencyFloat) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_slatf_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_slatf_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
sdc->setClockLatency(clk, nullptr, RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), 1.5f);
|
|
float lat = sdc->clockLatency(clk, RiseFall::rise(), MinMax::max());
|
|
EXPECT_FLOAT_EQ(lat, 1.5f);
|
|
}
|
|
|
|
// Sdc::setClockInsertion and clockInsertion
|
|
TEST_F(SdcInitTest, R8_SdcClockInsertion) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_sins_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_sins_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
sdc->setClockInsertion(clk, nullptr, RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), EarlyLateAll::all(), 0.5f);
|
|
float ins = sdc->clockInsertion(clk, RiseFall::rise(),
|
|
MinMax::max(), EarlyLate::early());
|
|
EXPECT_FLOAT_EQ(ins, 0.5f);
|
|
}
|
|
|
|
// Sdc::removeClockInsertion
|
|
TEST_F(SdcInitTest, R8_SdcRemoveClockInsertion) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_srins_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_srins_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
sdc->setClockInsertion(clk, nullptr, RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), EarlyLateAll::all(), 1.0f);
|
|
sdc->removeClockInsertion(clk, nullptr);
|
|
// After removal, insertion should not exist
|
|
}
|
|
|
|
// Sdc::setMinPulseWidth
|
|
TEST_F(SdcInitTest, R8_SdcSetMinPulseWidthR8) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setMinPulseWidth(RiseFallBoth::riseFall(), 0.5f);
|
|
// Just verify no crash
|
|
}
|
|
|
|
// Sdc::setLatchBorrowLimit
|
|
TEST_F(SdcInitTest, R8_SdcSetLatchBorrowLimit) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_lbl_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_lbl_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
sdc->setLatchBorrowLimit(clk, 3.0f);
|
|
// Just verify no crash
|
|
}
|
|
|
|
// Sdc::removeClock
|
|
TEST_F(SdcInitTest, R8_SdcRemoveClock) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_rem_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_rem_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
sdc->removeClock(clk);
|
|
// Clock should be removed
|
|
}
|
|
|
|
// Sdc::defaultArrivalClock
|
|
TEST_F(SdcInitTest, R8_SdcDefaultArrivalClock) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *def_clk = sdc->defaultArrivalClock();
|
|
EXPECT_NE(def_clk, nullptr);
|
|
}
|
|
|
|
// Sdc::defaultArrivalClockEdge
|
|
TEST_F(SdcInitTest, R8_SdcDefaultArrivalClockEdge) {
|
|
Sdc *sdc = sta_->sdc();
|
|
ClockEdge *edge = sdc->defaultArrivalClockEdge();
|
|
EXPECT_NE(edge, nullptr);
|
|
}
|
|
|
|
// Sdc::haveClkSlewLimits
|
|
TEST_F(SdcInitTest, R8_SdcHaveClkSlewLimits) {
|
|
Sdc *sdc = sta_->sdc();
|
|
bool have = sdc->haveClkSlewLimits();
|
|
// Initially no limits
|
|
EXPECT_FALSE(have);
|
|
}
|
|
|
|
// Sdc::invalidateGeneratedClks
|
|
TEST_F(SdcInitTest, R8_SdcInvalidateGeneratedClks) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->invalidateGeneratedClks();
|
|
// Just verify no crash
|
|
}
|
|
|
|
// Variables toggles - more variables
|
|
TEST_F(SdcInitTest, R8_VariablesDynamicLoopBreaking) {
|
|
sta_->setDynamicLoopBreaking(true);
|
|
EXPECT_TRUE(sta_->dynamicLoopBreaking());
|
|
sta_->setDynamicLoopBreaking(false);
|
|
EXPECT_FALSE(sta_->dynamicLoopBreaking());
|
|
}
|
|
|
|
// Variables propagateAllClocks
|
|
TEST_F(SdcInitTest, R8_VariablesPropagateAllClocks) {
|
|
sta_->setPropagateAllClocks(true);
|
|
EXPECT_TRUE(sta_->propagateAllClocks());
|
|
sta_->setPropagateAllClocks(false);
|
|
EXPECT_FALSE(sta_->propagateAllClocks());
|
|
}
|
|
|
|
// Variables clkThruTristateEnabled
|
|
TEST_F(SdcInitTest, R8_VariablesClkThruTristateEnabled) {
|
|
sta_->setClkThruTristateEnabled(true);
|
|
EXPECT_TRUE(sta_->clkThruTristateEnabled());
|
|
sta_->setClkThruTristateEnabled(false);
|
|
EXPECT_FALSE(sta_->clkThruTristateEnabled());
|
|
}
|
|
|
|
// Variables useDefaultArrivalClock
|
|
TEST_F(SdcInitTest, R8_VariablesUseDefaultArrivalClock) {
|
|
sta_->setUseDefaultArrivalClock(true);
|
|
EXPECT_TRUE(sta_->useDefaultArrivalClock());
|
|
sta_->setUseDefaultArrivalClock(false);
|
|
EXPECT_FALSE(sta_->useDefaultArrivalClock());
|
|
}
|
|
|
|
// Variables pocvEnabled
|
|
TEST_F(SdcInitTest, R8_VariablesPocvEnabled) {
|
|
sta_->setPocvEnabled(true);
|
|
EXPECT_TRUE(sta_->pocvEnabled());
|
|
sta_->setPocvEnabled(false);
|
|
EXPECT_FALSE(sta_->pocvEnabled());
|
|
}
|
|
|
|
// Variables crprEnabled
|
|
TEST_F(SdcInitTest, R8_VariablesCrprEnabled) {
|
|
sta_->setCrprEnabled(true);
|
|
EXPECT_TRUE(sta_->crprEnabled());
|
|
sta_->setCrprEnabled(false);
|
|
EXPECT_FALSE(sta_->crprEnabled());
|
|
}
|
|
|
|
// RiseFallMinMax clear
|
|
TEST_F(SdcInitTest, R8_RiseFallMinMaxClear) {
|
|
RiseFallMinMax rfmm(1.0f);
|
|
EXPECT_TRUE(rfmm.hasValue());
|
|
rfmm.clear();
|
|
EXPECT_FALSE(rfmm.hasValue());
|
|
}
|
|
|
|
// RiseFallMinMax setValue individual
|
|
TEST_F(SdcInitTest, R8_RiseFallMinMaxSetValueIndividual) {
|
|
RiseFallMinMax rfmm;
|
|
rfmm.setValue(RiseFall::rise(), MinMax::min(), 1.0f);
|
|
rfmm.setValue(RiseFall::rise(), MinMax::max(), 2.0f);
|
|
rfmm.setValue(RiseFall::fall(), MinMax::min(), 3.0f);
|
|
rfmm.setValue(RiseFall::fall(), MinMax::max(), 4.0f);
|
|
EXPECT_FLOAT_EQ(rfmm.value(RiseFall::rise(), MinMax::min()), 1.0f);
|
|
EXPECT_FLOAT_EQ(rfmm.value(RiseFall::rise(), MinMax::max()), 2.0f);
|
|
EXPECT_FLOAT_EQ(rfmm.value(RiseFall::fall(), MinMax::min()), 3.0f);
|
|
EXPECT_FLOAT_EQ(rfmm.value(RiseFall::fall(), MinMax::max()), 4.0f);
|
|
}
|
|
|
|
// RiseFallMinMax setValue with RiseFallBoth and MinMaxAll
|
|
TEST_F(SdcInitTest, R8_RiseFallMinMaxSetValueBoth) {
|
|
RiseFallMinMax rfmm;
|
|
rfmm.setValue(RiseFallBoth::riseFall(), MinMaxAll::all(), 5.0f);
|
|
EXPECT_FLOAT_EQ(rfmm.value(RiseFall::rise(), MinMax::min()), 5.0f);
|
|
EXPECT_FLOAT_EQ(rfmm.value(RiseFall::rise(), MinMax::max()), 5.0f);
|
|
EXPECT_FLOAT_EQ(rfmm.value(RiseFall::fall(), MinMax::min()), 5.0f);
|
|
EXPECT_FLOAT_EQ(rfmm.value(RiseFall::fall(), MinMax::max()), 5.0f);
|
|
}
|
|
|
|
// PortExtCap
|
|
TEST_F(SdcInitTest, R8_PortExtCapConstruct) {
|
|
PortExtCap pec(nullptr);
|
|
EXPECT_EQ(pec.port(), nullptr);
|
|
float cap;
|
|
bool exists;
|
|
pec.pinCap(RiseFall::rise(), MinMax::max(), cap, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
// PortExtCap set and get pin cap
|
|
TEST_F(SdcInitTest, R8_PortExtCapSetPinCap) {
|
|
PortExtCap pec(nullptr);
|
|
pec.setPinCap(1.0f, RiseFall::rise(), MinMax::max());
|
|
float cap;
|
|
bool exists;
|
|
pec.pinCap(RiseFall::rise(), MinMax::max(), cap, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(cap, 1.0f);
|
|
}
|
|
|
|
// PortExtCap set and get wire cap
|
|
TEST_F(SdcInitTest, R8_PortExtCapSetWireCap) {
|
|
PortExtCap pec(nullptr);
|
|
pec.setWireCap(0.5f, RiseFall::fall(), MinMax::min());
|
|
float cap;
|
|
bool exists;
|
|
pec.wireCap(RiseFall::fall(), MinMax::min(), cap, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(cap, 0.5f);
|
|
}
|
|
|
|
// PortExtCap set and get fanout
|
|
TEST_F(SdcInitTest, R8_PortExtCapSetFanout) {
|
|
PortExtCap pec(nullptr);
|
|
pec.setFanout(4, MinMax::max());
|
|
int fanout;
|
|
bool exists;
|
|
pec.fanout(MinMax::max(), fanout, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_EQ(fanout, 4);
|
|
}
|
|
|
|
// PortExtCap accessors
|
|
TEST_F(SdcInitTest, R8_PortExtCapAccessors) {
|
|
PortExtCap pec(nullptr);
|
|
pec.setPinCap(1.0f, RiseFall::rise(), MinMax::max());
|
|
RiseFallMinMax *pin_cap = pec.pinCap();
|
|
EXPECT_NE(pin_cap, nullptr);
|
|
RiseFallMinMax *wire_cap = pec.wireCap();
|
|
EXPECT_NE(wire_cap, nullptr);
|
|
FanoutValues *fanout = pec.fanout();
|
|
EXPECT_NE(fanout, nullptr);
|
|
}
|
|
|
|
// clkCmp
|
|
TEST_F(SdcInitTest, R8_ClkCmp) {
|
|
FloatSeq *wf1 = new FloatSeq;
|
|
wf1->push_back(0.0);
|
|
wf1->push_back(5.0);
|
|
sta_->makeClock("r8_cmpa_clk", nullptr, false, 10.0, wf1, nullptr);
|
|
FloatSeq *wf2 = new FloatSeq;
|
|
wf2->push_back(0.0);
|
|
wf2->push_back(5.0);
|
|
sta_->makeClock("r8_cmpb_clk", nullptr, false, 10.0, wf2, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk1 = sdc->findClock("r8_cmpa_clk");
|
|
Clock *clk2 = sdc->findClock("r8_cmpb_clk");
|
|
ASSERT_NE(clk1, nullptr);
|
|
ASSERT_NE(clk2, nullptr);
|
|
int cmp = clkCmp(clk1, clk2);
|
|
// Different clocks should not be equal
|
|
EXPECT_NE(cmp, 0);
|
|
}
|
|
|
|
// clkEdgeCmp
|
|
TEST_F(SdcInitTest, R8_ClkEdgeCmp) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_ecmp_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_ecmp_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockEdge *rise = clk->edge(RiseFall::rise());
|
|
ClockEdge *fall = clk->edge(RiseFall::fall());
|
|
int cmp = clkEdgeCmp(rise, fall);
|
|
EXPECT_NE(cmp, 0);
|
|
}
|
|
|
|
// clkEdgeLess
|
|
TEST_F(SdcInitTest, R8_ClkEdgeLess) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_eless_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_eless_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockEdge *rise = clk->edge(RiseFall::rise());
|
|
ClockEdge *fall = clk->edge(RiseFall::fall());
|
|
bool less1 = clkEdgeLess(rise, fall);
|
|
bool less2 = clkEdgeLess(fall, rise);
|
|
// One should be less than the other, but not both
|
|
EXPECT_NE(less1, less2);
|
|
}
|
|
|
|
// ClockNameLess
|
|
TEST_F(SdcInitTest, R8_ClockNameLess) {
|
|
FloatSeq *wf1 = new FloatSeq;
|
|
wf1->push_back(0.0);
|
|
wf1->push_back(5.0);
|
|
sta_->makeClock("r8_aaa_clk", nullptr, false, 10.0, wf1, nullptr);
|
|
FloatSeq *wf2 = new FloatSeq;
|
|
wf2->push_back(0.0);
|
|
wf2->push_back(5.0);
|
|
sta_->makeClock("r8_zzz_clk", nullptr, false, 10.0, wf2, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk_a = sdc->findClock("r8_aaa_clk");
|
|
Clock *clk_z = sdc->findClock("r8_zzz_clk");
|
|
ClockNameLess cmp;
|
|
EXPECT_TRUE(cmp(clk_a, clk_z));
|
|
EXPECT_FALSE(cmp(clk_z, clk_a));
|
|
}
|
|
|
|
// Sdc::setClockGatingCheck (global)
|
|
TEST_F(SdcInitTest, R8_SdcClockGatingCheckGlobalR8) {
|
|
Sdc *sdc = sta_->sdc();
|
|
sdc->setClockGatingCheck(RiseFallBoth::riseFall(),
|
|
SetupHold::max(), 0.5f);
|
|
// Just verify no crash
|
|
}
|
|
|
|
// Sdc::setClockGatingCheck on clock
|
|
TEST_F(SdcInitTest, R8_SdcClockGatingCheckOnClock) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_cg_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_cg_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
sdc->setClockGatingCheck(clk, RiseFallBoth::riseFall(),
|
|
SetupHold::min(), 0.3f);
|
|
// Just verify no crash
|
|
}
|
|
|
|
// Clock slewLimit set and get
|
|
TEST_F(SdcInitTest, R8_ClockSlewLimit) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_sl_clk", nullptr, false, 10.0, wf, nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("r8_sl_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
clk->setSlewLimit(RiseFallBoth::riseFall(), PathClkOrData::clk,
|
|
MinMax::max(), 0.5f);
|
|
float slew;
|
|
bool exists;
|
|
clk->slewLimit(RiseFall::rise(), PathClkOrData::clk,
|
|
MinMax::max(), slew, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(slew, 0.5f);
|
|
}
|
|
|
|
// ExceptionPt transition
|
|
TEST_F(SdcInitTest, R8_ExceptionPtTransition) {
|
|
ExceptionFrom from(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::rise(), false, nullptr);
|
|
EXPECT_EQ(from.transition(), RiseFallBoth::rise());
|
|
EXPECT_TRUE(from.isFrom());
|
|
EXPECT_FALSE(from.isThru());
|
|
EXPECT_FALSE(from.isTo());
|
|
}
|
|
|
|
// ExceptionTo isTo
|
|
TEST_F(SdcInitTest, R8_ExceptionToIsTo) {
|
|
ExceptionTo to(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::fall(),
|
|
RiseFallBoth::riseFall(),
|
|
false, nullptr);
|
|
EXPECT_TRUE(to.isTo());
|
|
EXPECT_FALSE(to.isFrom());
|
|
}
|
|
|
|
// ExceptionFrom hasObjects (empty)
|
|
TEST_F(SdcInitTest, R8_ExceptionFromHasObjectsEmpty) {
|
|
ExceptionFrom from(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(), false, nullptr);
|
|
EXPECT_FALSE(from.hasObjects());
|
|
EXPECT_FALSE(from.hasPins());
|
|
EXPECT_FALSE(from.hasClocks());
|
|
EXPECT_FALSE(from.hasInstances());
|
|
}
|
|
|
|
// MultiCyclePath matches min/max
|
|
TEST_F(SdcInitTest, R8_MultiCyclePathMatchesMinMax) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, false, nullptr);
|
|
EXPECT_TRUE(mcp.matches(MinMax::min(), false));
|
|
EXPECT_TRUE(mcp.matches(MinMax::max(), false));
|
|
}
|
|
|
|
// MultiCyclePath pathMultiplier with min_max
|
|
TEST_F(SdcInitTest, R8_MultiCyclePathMultiplierWithMinMax) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, false, nullptr);
|
|
int mult_max = mcp.pathMultiplier(MinMax::max());
|
|
EXPECT_EQ(mult_max, 3);
|
|
}
|
|
|
|
// ExceptionPath fromThruToPriority
|
|
TEST_F(SdcInitTest, R8_ExceptionPathFromThruToPriority) {
|
|
int prio = ExceptionPath::fromThruToPriority(nullptr, nullptr, nullptr);
|
|
EXPECT_EQ(prio, 0);
|
|
}
|
|
|
|
// Sdc::disabledCellPorts
|
|
TEST_F(SdcInitTest, R8_SdcDisabledCellPorts) {
|
|
Sdc *sdc = sta_->sdc();
|
|
DisabledCellPortsMap *dcm = sdc->disabledCellPorts();
|
|
EXPECT_NE(dcm, nullptr);
|
|
}
|
|
|
|
// Sdc::disabledInstancePorts
|
|
TEST_F(SdcInitTest, R8_SdcDisabledInstancePorts) {
|
|
Sdc *sdc = sta_->sdc();
|
|
const DisabledInstancePortsMap *dim = sdc->disabledInstancePorts();
|
|
EXPECT_NE(dim, nullptr);
|
|
}
|
|
|
|
// Sdc::disabledPins
|
|
TEST_F(SdcInitTest, R8_SdcDisabledPins) {
|
|
Sdc *sdc = sta_->sdc();
|
|
const PinSet *pins = sdc->disabledPins();
|
|
EXPECT_NE(pins, nullptr);
|
|
}
|
|
|
|
// Sdc::disabledPorts
|
|
TEST_F(SdcInitTest, R8_SdcDisabledPorts) {
|
|
Sdc *sdc = sta_->sdc();
|
|
const PortSet *ports = sdc->disabledPorts();
|
|
EXPECT_NE(ports, nullptr);
|
|
}
|
|
|
|
// Sdc::disabledLibPorts
|
|
TEST_F(SdcInitTest, R8_SdcDisabledLibPorts) {
|
|
Sdc *sdc = sta_->sdc();
|
|
const LibertyPortSet *lib_ports = sdc->disabledLibPorts();
|
|
EXPECT_NE(lib_ports, nullptr);
|
|
}
|
|
|
|
// Sdc::netResistances
|
|
TEST_F(SdcInitTest, R8_SdcNetResistances) {
|
|
Sdc *sdc = sta_->sdc();
|
|
NetResistanceMap &nr = sdc->netResistances();
|
|
(void)nr.size();
|
|
}
|
|
|
|
// Sdc::clockInsertions
|
|
TEST_F(SdcInitTest, R8_SdcClockInsertions) {
|
|
Sdc *sdc = sta_->sdc();
|
|
const ClockInsertions &insertions = sdc->clockInsertions();
|
|
(void)insertions.size();
|
|
}
|
|
|
|
// ============================================================
|
|
// R10_ tests: Additional SDC coverage
|
|
// ============================================================
|
|
|
|
// --- SdcDesignTest: loads nangate45 + example1.v for SDC tests needing a design ---
|
|
|
|
class SdcDesignTest : 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_);
|
|
|
|
Corner *corner = sta_->cmdCorner();
|
|
const MinMaxAll *min_max = MinMaxAll::all();
|
|
LibertyLibrary *lib = sta_->readLiberty(
|
|
"test/nangate45/Nangate45_typ.lib", corner, min_max, false);
|
|
ASSERT_NE(lib, nullptr);
|
|
|
|
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);
|
|
|
|
PinSet *clk_pins = new PinSet(network);
|
|
clk_pins->insert(clk1);
|
|
clk_pins->insert(clk2);
|
|
clk_pins->insert(clk3);
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0f);
|
|
waveform->push_back(5.0f);
|
|
sta_->makeClock("clk", clk_pins, false, 10.0f, waveform, nullptr);
|
|
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
Clock *clk = sta_->sdc()->findClock("clk");
|
|
if (in1 && clk) {
|
|
sta_->setInputDelay(in1, RiseFallBoth::riseFall(),
|
|
clk, RiseFall::rise(), nullptr,
|
|
false, false, MinMaxAll::all(), true, 0.0f);
|
|
}
|
|
sta_->updateTiming(true);
|
|
}
|
|
|
|
void TearDown() override {
|
|
deleteAllMemory();
|
|
sta_ = nullptr;
|
|
if (interp_)
|
|
Tcl_DeleteInterp(interp_);
|
|
interp_ = nullptr;
|
|
}
|
|
|
|
Pin *findPin(const char *path_name) {
|
|
Network *network = sta_->cmdNetwork();
|
|
return network->findPin(path_name);
|
|
}
|
|
|
|
Sta *sta_;
|
|
Tcl_Interp *interp_;
|
|
};
|
|
|
|
// --- CycleAccting: sourceCycle, targetCycle via timing update ---
|
|
|
|
TEST_F(SdcDesignTest, R10_CycleAcctingSourceTargetCycle) {
|
|
// CycleAccting methods are called internally during timing
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
// Make a second clock for inter-clock cycle accounting
|
|
Network *network = sta_->network();
|
|
Instance *top = network->topInstance();
|
|
Pin *clk2 = network->findPin(top, "clk2");
|
|
if (clk2) {
|
|
PinSet *clk2_pins = new PinSet(network);
|
|
clk2_pins->insert(clk2);
|
|
FloatSeq *waveform2 = new FloatSeq;
|
|
waveform2->push_back(0.0f);
|
|
waveform2->push_back(2.5f);
|
|
sta_->makeClock("clk2", clk2_pins, false, 5.0f, waveform2, nullptr);
|
|
sta_->updateTiming(true);
|
|
// Forces CycleAccting to compute inter-clock accounting
|
|
}
|
|
}
|
|
|
|
// --- ExceptionThru: asString ---
|
|
|
|
TEST_F(SdcInitTest, R10_ExceptionThruAsString) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Network *network = sta_->cmdNetwork();
|
|
// Create ExceptionThru with no objects
|
|
ExceptionThru *thru = new ExceptionThru(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(), true, network);
|
|
const char *str = thru->asString(network);
|
|
(void)str;
|
|
delete thru;
|
|
}
|
|
|
|
// --- ExceptionTo: asString, matches, cmdKeyword ---
|
|
|
|
TEST_F(SdcInitTest, R10_ExceptionToAsString) {
|
|
Network *network = sta_->cmdNetwork();
|
|
ExceptionTo *to = new ExceptionTo(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(),
|
|
RiseFallBoth::riseFall(),
|
|
true, network);
|
|
const char *str = to->asString(network);
|
|
(void)str;
|
|
// matches with null pin and rf
|
|
bool m = to->matches(nullptr, RiseFall::rise());
|
|
(void)m;
|
|
delete to;
|
|
}
|
|
|
|
// --- ExceptionFrom: findHash ---
|
|
|
|
TEST_F(SdcInitTest, R10_ExceptionFromHash) {
|
|
Network *network = sta_->cmdNetwork();
|
|
ExceptionFrom *from = new ExceptionFrom(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(), true, network);
|
|
size_t h = from->hash();
|
|
(void)h;
|
|
delete from;
|
|
}
|
|
|
|
// --- ExceptionPath: mergeable ---
|
|
|
|
TEST_F(SdcInitTest, R10_ExceptionPathMergeable) {
|
|
Sdc *sdc = sta_->sdc();
|
|
FalsePath *fp1 = new FalsePath(nullptr, nullptr, nullptr,
|
|
MinMaxAll::all(), true, nullptr);
|
|
FalsePath *fp2 = new FalsePath(nullptr, nullptr, nullptr,
|
|
MinMaxAll::all(), true, nullptr);
|
|
bool m = fp1->mergeable(fp2);
|
|
EXPECT_TRUE(m);
|
|
// Different type should not be mergeable
|
|
PathDelay *pd = new PathDelay(nullptr, nullptr, nullptr,
|
|
MinMax::max(), false, false, 5.0, true, nullptr);
|
|
bool m2 = fp1->mergeable(pd);
|
|
EXPECT_FALSE(m2);
|
|
delete fp1;
|
|
delete fp2;
|
|
delete pd;
|
|
}
|
|
|
|
// --- ExceptionPt constructor ---
|
|
|
|
TEST_F(SdcInitTest, R10_ExceptionPtBasic) {
|
|
Network *network = sta_->cmdNetwork();
|
|
ExceptionFrom *from = new ExceptionFrom(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::rise(), true, network);
|
|
EXPECT_TRUE(from->isFrom());
|
|
EXPECT_FALSE(from->isTo());
|
|
EXPECT_FALSE(from->isThru());
|
|
delete from;
|
|
}
|
|
|
|
// --- ExceptionFromTo destructor ---
|
|
|
|
TEST_F(SdcInitTest, R10_ExceptionFromToDestructor) {
|
|
Network *network = sta_->cmdNetwork();
|
|
ExceptionFrom *from = new ExceptionFrom(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(), true, network);
|
|
delete from;
|
|
// Destructor coverage for ExceptionFromTo
|
|
}
|
|
|
|
// --- ExceptionPath destructor ---
|
|
|
|
TEST_F(SdcInitTest, R10_ExceptionPathDestructor) {
|
|
FalsePath *fp = new FalsePath(nullptr, nullptr, nullptr,
|
|
MinMaxAll::all(), true, nullptr);
|
|
delete fp;
|
|
}
|
|
|
|
// --- DisabledCellPorts: construct and accessors ---
|
|
|
|
TEST_F(SdcInitTest, R10_DisabledCellPortsConstruct) {
|
|
LibertyLibrary *lib = sta_->readLiberty("test/nangate45/Nangate45_typ.lib",
|
|
sta_->cmdCorner(),
|
|
MinMaxAll::min(), false);
|
|
if (lib) {
|
|
LibertyCell *buf = lib->findLibertyCell("BUF_X1");
|
|
if (buf) {
|
|
DisabledCellPorts dcp(buf);
|
|
EXPECT_EQ(dcp.cell(), buf);
|
|
EXPECT_FALSE(dcp.all());
|
|
dcp.setDisabledAll();
|
|
EXPECT_TRUE(dcp.all());
|
|
dcp.removeDisabledAll();
|
|
EXPECT_FALSE(dcp.all());
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- PortDelay: refTransition ---
|
|
|
|
TEST_F(SdcDesignTest, R10_PortDelayRefTransition) {
|
|
Sdc *sdc = sta_->sdc();
|
|
const InputDelaySet &delays = sdc->inputDelays();
|
|
for (InputDelay *delay : delays) {
|
|
const RiseFall *ref_rf = delay->refTransition();
|
|
(void)ref_rf;
|
|
// Also exercise other PortDelay accessors
|
|
const Pin *pin = delay->pin();
|
|
(void)pin;
|
|
const ClockEdge *ce = delay->clkEdge();
|
|
(void)ce;
|
|
bool src_lat = delay->sourceLatencyIncluded();
|
|
(void)src_lat;
|
|
bool net_lat = delay->networkLatencyIncluded();
|
|
(void)net_lat;
|
|
const Pin *ref_pin = delay->refPin();
|
|
(void)ref_pin;
|
|
int idx = delay->index();
|
|
(void)idx;
|
|
}
|
|
}
|
|
|
|
// --- ClockEdge: accessors (time, clock, transition) ---
|
|
|
|
TEST_F(SdcInitTest, R10_ClockEdgeAccessors) {
|
|
Sdc *sdc = sta_->sdc();
|
|
PinSet *clk_pins = new PinSet(sta_->cmdNetwork());
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0f);
|
|
waveform->push_back(5.0f);
|
|
sta_->makeClock("test_clk_edge", clk_pins, false, 10.0f, waveform, nullptr);
|
|
Clock *clk = sdc->findClock("test_clk_edge");
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockEdge *rise_edge = clk->edge(RiseFall::rise());
|
|
ClockEdge *fall_edge = clk->edge(RiseFall::fall());
|
|
ASSERT_NE(rise_edge, nullptr);
|
|
ASSERT_NE(fall_edge, nullptr);
|
|
// time()
|
|
EXPECT_FLOAT_EQ(rise_edge->time(), 0.0f);
|
|
EXPECT_FLOAT_EQ(fall_edge->time(), 5.0f);
|
|
// clock()
|
|
EXPECT_EQ(rise_edge->clock(), clk);
|
|
EXPECT_EQ(fall_edge->clock(), clk);
|
|
// transition()
|
|
EXPECT_EQ(rise_edge->transition(), RiseFall::rise());
|
|
EXPECT_EQ(fall_edge->transition(), RiseFall::fall());
|
|
// name()
|
|
EXPECT_NE(rise_edge->name(), nullptr);
|
|
EXPECT_NE(fall_edge->name(), nullptr);
|
|
// index()
|
|
int ri = rise_edge->index();
|
|
int fi = fall_edge->index();
|
|
EXPECT_NE(ri, fi);
|
|
}
|
|
|
|
// --- Sdc: removeDataCheck ---
|
|
|
|
TEST_F(SdcDesignTest, R10_SdcRemoveDataCheck) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *from_pin = network->findPin(top, "r1/D");
|
|
Pin *to_pin = network->findPin(top, "r1/CK");
|
|
if (from_pin && to_pin) {
|
|
sdc->setDataCheck(from_pin, RiseFallBoth::riseFall(),
|
|
to_pin, RiseFallBoth::riseFall(),
|
|
nullptr, MinMaxAll::max(), 1.0);
|
|
sdc->removeDataCheck(from_pin, RiseFallBoth::riseFall(),
|
|
to_pin, RiseFallBoth::riseFall(),
|
|
nullptr, MinMaxAll::max());
|
|
}
|
|
}
|
|
|
|
// --- Sdc: deleteInterClockUncertainty ---
|
|
|
|
TEST_F(SdcInitTest, R10_SdcInterClockUncertainty) {
|
|
Sdc *sdc = sta_->sdc();
|
|
PinSet *pins1 = new PinSet(sta_->cmdNetwork());
|
|
FloatSeq *waveform1 = new FloatSeq;
|
|
waveform1->push_back(0.0f);
|
|
waveform1->push_back(5.0f);
|
|
sta_->makeClock("clk_a", pins1, false, 10.0f, waveform1, nullptr);
|
|
PinSet *pins2 = new PinSet(sta_->cmdNetwork());
|
|
FloatSeq *waveform2 = new FloatSeq;
|
|
waveform2->push_back(0.0f);
|
|
waveform2->push_back(2.5f);
|
|
sta_->makeClock("clk_b", pins2, false, 5.0f, waveform2, nullptr);
|
|
|
|
Clock *clk_a = sdc->findClock("clk_a");
|
|
Clock *clk_b = sdc->findClock("clk_b");
|
|
ASSERT_NE(clk_a, nullptr);
|
|
ASSERT_NE(clk_b, nullptr);
|
|
|
|
sta_->setClockUncertainty(clk_a, RiseFallBoth::riseFall(),
|
|
clk_b, RiseFallBoth::riseFall(),
|
|
MinMaxAll::max(), 0.2f);
|
|
// Remove it
|
|
sta_->removeClockUncertainty(clk_a, RiseFallBoth::riseFall(),
|
|
clk_b, RiseFallBoth::riseFall(),
|
|
MinMaxAll::max());
|
|
}
|
|
|
|
// --- Sdc: clearClkGroupExclusions (via removeClockGroupsLogicallyExclusive) ---
|
|
|
|
TEST_F(SdcInitTest, R10_SdcClearClkGroupExclusions) {
|
|
ClockGroups *cg = sta_->makeClockGroups("grp_exc", true, false, false, false, nullptr);
|
|
EXPECT_NE(cg, nullptr);
|
|
sta_->removeClockGroupsLogicallyExclusive("grp_exc");
|
|
}
|
|
|
|
// --- Sdc: false path exercises pathDelayFrom/To indirectly ---
|
|
|
|
TEST_F(SdcDesignTest, R10_SdcFalsePathExercise) {
|
|
// Creating a false path from/to exercises pathDelayFrom/To code paths
|
|
// through makeFalsePath and the SDC infrastructure
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
Pin *out = network->findPin(top, "out");
|
|
if (in1 && out) {
|
|
PinSet *from_pins = new PinSet(network);
|
|
from_pins->insert(in1);
|
|
ExceptionFrom *from = sta_->makeExceptionFrom(from_pins, nullptr, nullptr,
|
|
RiseFallBoth::riseFall());
|
|
PinSet *to_pins = new PinSet(network);
|
|
to_pins->insert(out);
|
|
ExceptionTo *to = sta_->makeExceptionTo(to_pins, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(),
|
|
RiseFallBoth::riseFall());
|
|
sta_->makeFalsePath(from, nullptr, to, MinMaxAll::all(), nullptr);
|
|
// Write SDC to exercise the path delay annotation
|
|
const char *fn = "/tmp/test_sdc_r10_falsepath_exercise.sdc";
|
|
sta_->writeSdc(fn, false, false, 4, false, true);
|
|
FILE *f = fopen(fn, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
}
|
|
|
|
// --- WriteSdc via SdcDesignTest ---
|
|
|
|
TEST_F(SdcDesignTest, R10_WriteSdcBasic) {
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithOutputDelay) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *out = network->findPin(top, "out");
|
|
Clock *clk = sta_->sdc()->findClock("clk");
|
|
if (out && clk) {
|
|
sta_->setOutputDelay(out, RiseFallBoth::riseFall(),
|
|
clk, RiseFall::rise(), nullptr,
|
|
false, false, MinMaxAll::all(), true, 3.0f);
|
|
}
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_outdelay.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
TEST_F(SdcDesignTest, R10_WriteSdcNative) {
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_native.sdc";
|
|
sta_->writeSdc(filename, false, true, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithFalsePath) {
|
|
sta_->makeFalsePath(nullptr, nullptr, nullptr, MinMaxAll::all(), nullptr);
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_fp.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithDerating) {
|
|
sta_->setTimingDerate(TimingDerateType::cell_delay,
|
|
PathClkOrData::data,
|
|
RiseFallBoth::riseFall(),
|
|
EarlyLate::early(), 0.95);
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_derate.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithDisable) {
|
|
Graph *graph = sta_->graph();
|
|
Network *network = sta_->cmdNetwork();
|
|
Pin *pin = findPin("r1/D");
|
|
if (pin && graph) {
|
|
Vertex *v = graph->pinLoadVertex(pin);
|
|
if (v) {
|
|
VertexInEdgeIterator in_iter(v, graph);
|
|
if (in_iter.hasNext()) {
|
|
Edge *edge = in_iter.next();
|
|
sta_->disable(edge);
|
|
}
|
|
}
|
|
}
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_disable.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithClockLatency) {
|
|
Clock *clk = sta_->sdc()->findClock("clk");
|
|
if (clk) {
|
|
sta_->setClockLatency(clk, nullptr, RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), 0.5f);
|
|
}
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_clklat.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithInterClkUncertainty) {
|
|
Clock *clk = sta_->sdc()->findClock("clk");
|
|
if (clk) {
|
|
sta_->setClockUncertainty(clk, RiseFallBoth::riseFall(),
|
|
clk, RiseFallBoth::riseFall(),
|
|
MinMaxAll::max(), 0.1f);
|
|
}
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_interclk.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- Sdc: capacitanceLimit ---
|
|
|
|
TEST_F(SdcDesignTest, R10_SdcCapacitanceLimit) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *pin = network->findPin(top, "r1/D");
|
|
if (pin) {
|
|
float limit;
|
|
bool exists;
|
|
sdc->capacitanceLimit(pin, MinMax::max(), limit, exists);
|
|
// No limit set initially
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
}
|
|
|
|
// --- Sdc: annotateGraphConstrained ---
|
|
|
|
TEST_F(SdcDesignTest, R10_SdcAnnotateGraphConstrained) {
|
|
// These are called during timing update; exercising indirectly
|
|
sta_->updateTiming(true);
|
|
}
|
|
|
|
// --- DisabledInstancePorts: construct and accessors ---
|
|
|
|
TEST_F(SdcDesignTest, R10_DisabledInstancePortsAccessors) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
InstanceChildIterator *iter = network->childIterator(top);
|
|
if (iter->hasNext()) {
|
|
Instance *inst = iter->next();
|
|
DisabledInstancePorts dip(inst);
|
|
EXPECT_EQ(dip.instance(), inst);
|
|
}
|
|
delete iter;
|
|
}
|
|
|
|
// --- PinClockPairLess: using public class ---
|
|
|
|
TEST_F(SdcDesignTest, R10_PinClockPairLessDesign) {
|
|
Network *network = sta_->cmdNetwork();
|
|
PinClockPairLess less(network);
|
|
(void)less;
|
|
}
|
|
|
|
// --- Sdc: clockLatency for edge ---
|
|
|
|
TEST_F(SdcDesignTest, R10_SdcClockLatencyEdge) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Graph *graph = sta_->graph();
|
|
Network *network = sta_->cmdNetwork();
|
|
Pin *pin = findPin("r1/CK");
|
|
if (pin && graph) {
|
|
Vertex *v = graph->pinLoadVertex(pin);
|
|
if (v) {
|
|
VertexInEdgeIterator in_iter(v, graph);
|
|
if (in_iter.hasNext()) {
|
|
Edge *edge = in_iter.next();
|
|
const ClockLatency *lat = sdc->clockLatency(edge);
|
|
(void)lat;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Sdc: disable/removeDisable for pin pair ---
|
|
|
|
TEST_F(SdcDesignTest, R10_SdcDisablePinPair) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
// Find a gate with input/output pin pair
|
|
InstanceChildIterator *inst_iter = network->childIterator(top);
|
|
while (inst_iter->hasNext()) {
|
|
Instance *inst = inst_iter->next();
|
|
LibertyCell *lib_cell = network->libertyCell(inst);
|
|
if (lib_cell) {
|
|
LibertyPort *in_port = nullptr;
|
|
LibertyPort *out_port = nullptr;
|
|
LibertyCellPortIterator port_iter(lib_cell);
|
|
while (port_iter.hasNext()) {
|
|
LibertyPort *port = port_iter.next();
|
|
if (port->direction()->isInput() && !in_port)
|
|
in_port = port;
|
|
else if (port->direction()->isOutput() && !out_port)
|
|
out_port = port;
|
|
}
|
|
if (in_port && out_port) {
|
|
Pin *in_pin = network->findPin(inst, in_port);
|
|
Pin *out_pin = network->findPin(inst, out_port);
|
|
if (in_pin && out_pin) {
|
|
sdc->disable(in_pin, out_pin);
|
|
sdc->removeDisable(in_pin, out_pin);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
delete inst_iter;
|
|
}
|
|
|
|
// --- ExceptionThru: makePinEdges, makeNetEdges, makeInstEdges, deletePinEdges ---
|
|
|
|
TEST_F(SdcDesignTest, R10_ExceptionThruEdges) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *pin = network->findPin(top, "in1");
|
|
if (pin) {
|
|
PinSet *pins = new PinSet(network);
|
|
pins->insert(pin);
|
|
ExceptionThru *thru = new ExceptionThru(pins, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(), true, network);
|
|
const char *str = thru->asString(network);
|
|
EXPECT_NE(str, nullptr);
|
|
delete thru;
|
|
}
|
|
}
|
|
|
|
TEST_F(SdcDesignTest, R10_ExceptionThruWithNet) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
// Find a net
|
|
NetIterator *net_iter = network->netIterator(top);
|
|
if (net_iter->hasNext()) {
|
|
Net *net = net_iter->next();
|
|
NetSet *nets = new NetSet(network);
|
|
nets->insert(net);
|
|
ExceptionThru *thru = new ExceptionThru(nullptr, nets, nullptr,
|
|
RiseFallBoth::riseFall(), true, network);
|
|
const char *str = thru->asString(network);
|
|
EXPECT_NE(str, nullptr);
|
|
delete thru;
|
|
}
|
|
delete net_iter;
|
|
}
|
|
|
|
TEST_F(SdcDesignTest, R10_ExceptionThruWithInstance) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
InstanceChildIterator *inst_iter = network->childIterator(top);
|
|
if (inst_iter->hasNext()) {
|
|
Instance *inst = inst_iter->next();
|
|
InstanceSet *insts = new InstanceSet(network);
|
|
insts->insert(inst);
|
|
ExceptionThru *thru = new ExceptionThru(nullptr, nullptr, insts,
|
|
RiseFallBoth::riseFall(), true, network);
|
|
const char *str = thru->asString(network);
|
|
EXPECT_NE(str, nullptr);
|
|
delete thru;
|
|
}
|
|
delete inst_iter;
|
|
}
|
|
|
|
// --- WriteSdc with leaf/map_hpins ---
|
|
|
|
TEST_F(SdcDesignTest, R10_WriteSdcLeaf) {
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_leaf.sdc";
|
|
sta_->writeSdc(filename, true, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with data check ---
|
|
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithDataCheck) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *from_pin = network->findPin(top, "r1/D");
|
|
Pin *to_pin = network->findPin(top, "r1/CK");
|
|
if (from_pin && to_pin) {
|
|
sta_->setDataCheck(from_pin, RiseFallBoth::riseFall(),
|
|
to_pin, RiseFallBoth::riseFall(),
|
|
nullptr, MinMaxAll::max(), 1.0);
|
|
}
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_datacheck.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with port loads ---
|
|
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithPortLoad) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *out = network->findPin(top, "out");
|
|
if (out) {
|
|
Port *port = network->port(out);
|
|
Corner *corner = sta_->cmdCorner();
|
|
if (port && corner)
|
|
sta_->setPortExtPinCap(port, RiseFallBoth::riseFall(), corner, MinMaxAll::all(), 0.5f);
|
|
}
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_portload.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with clock slew ---
|
|
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithClockSlew) {
|
|
Clock *clk = sta_->sdc()->findClock("clk");
|
|
if (clk) {
|
|
sta_->setClockSlew(clk, RiseFallBoth::riseFall(), MinMaxAll::all(), 0.1f);
|
|
}
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_clkslew.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with clock insertion ---
|
|
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithClockInsertion) {
|
|
Clock *clk = sta_->sdc()->findClock("clk");
|
|
if (clk) {
|
|
sta_->setClockInsertion(clk, nullptr, RiseFallBoth::rise(),
|
|
MinMaxAll::all(), EarlyLateAll::all(), 0.3f);
|
|
}
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_clkins.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with multicycle path ---
|
|
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithMulticycle) {
|
|
sta_->makeMulticyclePath(nullptr, nullptr, nullptr,
|
|
MinMaxAll::max(), true, 2, nullptr);
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_mcp.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with max area ---
|
|
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithMaxArea) {
|
|
sta_->sdc()->setMaxArea(1000.0);
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_maxarea.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with min pulse width ---
|
|
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithMpw) {
|
|
sta_->sdc()->setMinPulseWidth(RiseFallBoth::rise(), 0.5);
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_mpw.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with voltage ---
|
|
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithVoltage) {
|
|
sta_->sdc()->setVoltage(MinMax::max(), 1.1);
|
|
sta_->sdc()->setVoltage(MinMax::min(), 0.9);
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_voltage.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- Sdc: deleteLatchBorrowLimitsReferencing (via clock removal) ---
|
|
|
|
TEST_F(SdcInitTest, R10_SdcDeleteLatchBorrowLimits) {
|
|
Sdc *sdc = sta_->sdc();
|
|
PinSet *clk_pins = new PinSet(sta_->cmdNetwork());
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0f);
|
|
waveform->push_back(5.0f);
|
|
sta_->makeClock("clk_borrow", clk_pins, false, 10.0f, waveform, nullptr);
|
|
Clock *clk = sdc->findClock("clk_borrow");
|
|
ASSERT_NE(clk, nullptr);
|
|
// Set latch borrow limit on clock
|
|
sdc->setLatchBorrowLimit(clk, 0.5f);
|
|
// Remove the clock; this calls deleteLatchBorrowLimitsReferencing
|
|
sta_->removeClock(clk);
|
|
}
|
|
|
|
// ============================================================
|
|
// R10_ Additional SDC Tests - Round 2
|
|
// ============================================================
|
|
|
|
// --- WriteSdc with drive resistance ---
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithDriveResistance) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
if (in1) {
|
|
Port *port = network->port(in1);
|
|
if (port) {
|
|
sta_->setDriveResistance(port, RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), 50.0f);
|
|
}
|
|
}
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_driveres.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with logic value / set_logic_one ---
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithLogicValue) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
if (in1) {
|
|
sta_->setLogicValue(in1, LogicValue::one);
|
|
}
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_logicval.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with case analysis ---
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithCaseAnalysis) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *in2 = network->findPin(top, "in2");
|
|
if (in2) {
|
|
sta_->setCaseAnalysis(in2, LogicValue::zero);
|
|
}
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_caseanalysis.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with latch borrow limit on pin ---
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithLatchBorrowLimitPin) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *pin = network->findPin(top, "r1/D");
|
|
if (pin) {
|
|
sta_->setLatchBorrowLimit(pin, 0.3f);
|
|
}
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_latchborrow.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with latch borrow limit on instance ---
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithLatchBorrowLimitInst) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
InstanceChildIterator *iter = network->childIterator(top);
|
|
if (iter->hasNext()) {
|
|
Instance *inst = iter->next();
|
|
sta_->setLatchBorrowLimit(inst, 0.5f);
|
|
}
|
|
delete iter;
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_latchborrowinst.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with slew limits ---
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithSlewLimits) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk");
|
|
if (clk) {
|
|
sta_->setSlewLimit(clk, RiseFallBoth::riseFall(),
|
|
PathClkOrData::data, MinMax::max(), 2.0f);
|
|
}
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *out = network->findPin(top, "out");
|
|
if (out) {
|
|
Port *port = network->port(out);
|
|
if (port) {
|
|
sta_->setSlewLimit(port, MinMax::max(), 3.0f);
|
|
}
|
|
}
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_slewlimit.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with cap limits ---
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithCapLimits) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *out = network->findPin(top, "out");
|
|
if (out) {
|
|
Port *port = network->port(out);
|
|
if (port) {
|
|
sta_->setCapacitanceLimit(port, MinMax::max(), 0.5f);
|
|
}
|
|
sta_->setCapacitanceLimit(out, MinMax::max(), 0.3f);
|
|
}
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_caplimit.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with fanout limits ---
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithFanoutLimits) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *out = network->findPin(top, "out");
|
|
if (out) {
|
|
Port *port = network->port(out);
|
|
if (port) {
|
|
sta_->setFanoutLimit(port, MinMax::max(), 10.0f);
|
|
}
|
|
}
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_fanoutlimit.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with min pulse width on pin ---
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithMpwOnPin) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *clk_pin = network->findPin(top, "r1/CK");
|
|
if (clk_pin) {
|
|
sta_->setMinPulseWidth(clk_pin, RiseFallBoth::rise(), 0.2f);
|
|
}
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_mpwpin.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with min pulse width on instance ---
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithMpwOnInst) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
InstanceChildIterator *iter = network->childIterator(top);
|
|
if (iter->hasNext()) {
|
|
Instance *inst = iter->next();
|
|
sta_->setMinPulseWidth(inst, RiseFallBoth::rise(), 0.25f);
|
|
}
|
|
delete iter;
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_mpwinst.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with disable on instance ---
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithDisableInstance) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
InstanceChildIterator *iter = network->childIterator(top);
|
|
if (iter->hasNext()) {
|
|
Instance *inst = iter->next();
|
|
LibertyCell *lib_cell = network->libertyCell(inst);
|
|
if (lib_cell) {
|
|
LibertyPort *in_port = nullptr;
|
|
LibertyPort *out_port = nullptr;
|
|
LibertyCellPortIterator port_iter(lib_cell);
|
|
while (port_iter.hasNext()) {
|
|
LibertyPort *port = port_iter.next();
|
|
if (port->direction()->isInput() && !in_port)
|
|
in_port = port;
|
|
else if (port->direction()->isOutput() && !out_port)
|
|
out_port = port;
|
|
}
|
|
if (in_port && out_port)
|
|
sta_->disable(inst, in_port, out_port);
|
|
}
|
|
}
|
|
delete iter;
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_disableinst.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with disable on liberty port ---
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithDisableLibPort) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
InstanceChildIterator *iter = network->childIterator(top);
|
|
if (iter->hasNext()) {
|
|
Instance *inst = iter->next();
|
|
LibertyCell *lib_cell = network->libertyCell(inst);
|
|
if (lib_cell) {
|
|
LibertyCellPortIterator port_iter(lib_cell);
|
|
if (port_iter.hasNext()) {
|
|
LibertyPort *port = port_iter.next();
|
|
sta_->disable(port);
|
|
}
|
|
}
|
|
}
|
|
delete iter;
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_disablelibport.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with disable on cell ---
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithDisableCell) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
InstanceChildIterator *iter = network->childIterator(top);
|
|
if (iter->hasNext()) {
|
|
Instance *inst = iter->next();
|
|
LibertyCell *lib_cell = network->libertyCell(inst);
|
|
if (lib_cell) {
|
|
sta_->disable(lib_cell, nullptr, nullptr);
|
|
}
|
|
}
|
|
delete iter;
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_disablecell.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with output delay ---
|
|
TEST_F(SdcDesignTest, R10_WriteSdcWithOutputDelayDetailed) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *out = network->findPin(top, "out");
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk");
|
|
if (out && clk) {
|
|
sta_->setOutputDelay(out, RiseFallBoth::rise(),
|
|
clk, RiseFall::rise(), nullptr,
|
|
false, false, MinMaxAll::max(), true, 2.5f);
|
|
sta_->setOutputDelay(out, RiseFallBoth::fall(),
|
|
clk, RiseFall::fall(), nullptr,
|
|
false, false, MinMaxAll::min(), true, 1.0f);
|
|
}
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_outdelay_detail.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- Sdc: outputDelays iterator ---
|
|
TEST_F(SdcDesignTest, R10_SdcOutputDelays) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *out = network->findPin(top, "out");
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk");
|
|
if (out && clk) {
|
|
sta_->setOutputDelay(out, RiseFallBoth::riseFall(),
|
|
clk, RiseFall::rise(), nullptr,
|
|
false, false, MinMaxAll::all(), true, 1.0f);
|
|
}
|
|
const OutputDelaySet &out_delays = sdc->outputDelays();
|
|
for (OutputDelay *delay : out_delays) {
|
|
const Pin *pin = delay->pin();
|
|
(void)pin;
|
|
const ClockEdge *ce = delay->clkEdge();
|
|
(void)ce;
|
|
bool src_lat = delay->sourceLatencyIncluded();
|
|
(void)src_lat;
|
|
}
|
|
}
|
|
|
|
// --- Sdc: Variables class accessors ---
|
|
TEST_F(SdcDesignTest, R10_VariablesAccessors) {
|
|
// Test Variables accessors that modify search behavior
|
|
bool crpr_orig = sta_->crprEnabled();
|
|
sta_->setCrprEnabled(!crpr_orig);
|
|
EXPECT_NE(sta_->crprEnabled(), crpr_orig);
|
|
sta_->setCrprEnabled(crpr_orig);
|
|
|
|
bool prop_gate = sta_->propagateGatedClockEnable();
|
|
sta_->setPropagateGatedClockEnable(!prop_gate);
|
|
EXPECT_NE(sta_->propagateGatedClockEnable(), prop_gate);
|
|
sta_->setPropagateGatedClockEnable(prop_gate);
|
|
}
|
|
|
|
// --- Clock: name, period, waveform ---
|
|
TEST_F(SdcDesignTest, R10_ClockAccessors) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
EXPECT_STREQ(clk->name(), "clk");
|
|
EXPECT_FLOAT_EQ(clk->period(), 10.0f);
|
|
const FloatSeq *wave = clk->waveform();
|
|
ASSERT_NE(wave, nullptr);
|
|
EXPECT_GE(wave->size(), 2u);
|
|
EXPECT_FLOAT_EQ((*wave)[0], 0.0f);
|
|
EXPECT_FLOAT_EQ((*wave)[1], 5.0f);
|
|
EXPECT_FALSE(clk->isGenerated());
|
|
EXPECT_FALSE(clk->isVirtual());
|
|
int idx = clk->index();
|
|
(void)idx;
|
|
}
|
|
|
|
// --- ExceptionFrom: hasPins, hasClocks, hasInstances ---
|
|
TEST_F(SdcDesignTest, R10_ExceptionFromHasPins) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
if (in1) {
|
|
PinSet *pins = new PinSet(network);
|
|
pins->insert(in1);
|
|
ExceptionFrom *from = sta_->makeExceptionFrom(pins, nullptr, nullptr,
|
|
RiseFallBoth::riseFall());
|
|
ASSERT_NE(from, nullptr);
|
|
EXPECT_TRUE(from->hasPins());
|
|
EXPECT_FALSE(from->hasClocks());
|
|
EXPECT_FALSE(from->hasInstances());
|
|
EXPECT_TRUE(from->hasObjects());
|
|
delete from;
|
|
}
|
|
}
|
|
|
|
// --- ExceptionTo: hasPins, endRf ---
|
|
TEST_F(SdcDesignTest, R10_ExceptionToHasPins) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *out = network->findPin(top, "out");
|
|
if (out) {
|
|
PinSet *pins = new PinSet(network);
|
|
pins->insert(out);
|
|
ExceptionTo *to = sta_->makeExceptionTo(pins, nullptr, nullptr,
|
|
RiseFallBoth::rise(),
|
|
RiseFallBoth::riseFall());
|
|
ASSERT_NE(to, nullptr);
|
|
EXPECT_TRUE(to->hasPins());
|
|
const RiseFallBoth *end_rf = to->endTransition();
|
|
EXPECT_NE(end_rf, nullptr);
|
|
delete to;
|
|
}
|
|
}
|
|
|
|
// --- Sdc: removeClockLatency ---
|
|
TEST_F(SdcDesignTest, R10_SdcRemoveClockLatency) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk");
|
|
if (clk) {
|
|
sta_->setClockLatency(clk, nullptr,
|
|
RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), 0.3f);
|
|
sta_->removeClockLatency(clk, nullptr);
|
|
}
|
|
}
|
|
|
|
// --- Sdc: removeCaseAnalysis ---
|
|
TEST_F(SdcDesignTest, R10_SdcRemoveCaseAnalysis) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
if (in1) {
|
|
sta_->setCaseAnalysis(in1, LogicValue::one);
|
|
sta_->removeCaseAnalysis(in1);
|
|
}
|
|
}
|
|
|
|
// --- Sdc: removeDerating ---
|
|
TEST_F(SdcDesignTest, R10_SdcRemoveDerating) {
|
|
sta_->setTimingDerate(TimingDerateType::cell_delay,
|
|
PathClkOrData::data,
|
|
RiseFallBoth::riseFall(),
|
|
EarlyLate::early(), 0.95);
|
|
sta_->unsetTimingDerate();
|
|
}
|
|
|
|
// --- WriteSdc comprehensive: multiple constraints ---
|
|
TEST_F(SdcDesignTest, R10_WriteSdcComprehensive) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk");
|
|
|
|
// Add various constraints
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
Pin *in2 = network->findPin(top, "in2");
|
|
Pin *out = network->findPin(top, "out");
|
|
|
|
if (in1) {
|
|
Port *port = network->port(in1);
|
|
if (port)
|
|
sta_->setDriveResistance(port, RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), 100.0f);
|
|
}
|
|
if (in2) {
|
|
sta_->setCaseAnalysis(in2, LogicValue::zero);
|
|
}
|
|
if (out) {
|
|
Port *port = network->port(out);
|
|
if (port) {
|
|
sta_->setPortExtPinCap(port, RiseFallBoth::riseFall(),
|
|
sta_->cmdCorner(), MinMaxAll::all(), 0.1f);
|
|
sta_->setFanoutLimit(port, MinMax::max(), 5.0f);
|
|
}
|
|
}
|
|
if (clk) {
|
|
sta_->setClockLatency(clk, nullptr, RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), 0.5f);
|
|
sta_->setClockInsertion(clk, nullptr, RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), EarlyLateAll::all(), 0.2f);
|
|
}
|
|
sdc->setMaxArea(2000.0);
|
|
sdc->setMinPulseWidth(RiseFallBoth::rise(), 0.3);
|
|
sdc->setVoltage(MinMax::max(), 1.2);
|
|
sdc->setVoltage(MinMax::min(), 0.8);
|
|
|
|
sta_->setTimingDerate(TimingDerateType::cell_delay,
|
|
PathClkOrData::data,
|
|
RiseFallBoth::riseFall(),
|
|
EarlyLate::early(), 0.95);
|
|
|
|
// Write SDC with all constraints
|
|
const char *filename = "/tmp/test_write_sdc_sdc_r10_comprehensive.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
|
|
// Also write native format
|
|
const char *filename2 = "/tmp/test_write_sdc_sdc_r10_comprehensive_native.sdc";
|
|
sta_->writeSdc(filename2, false, true, 4, false, true);
|
|
FILE *f2 = fopen(filename2, "r");
|
|
EXPECT_NE(f2, nullptr);
|
|
if (f2) fclose(f2);
|
|
}
|
|
|
|
// --- Clock: isPropagated, edges, edgeCount ---
|
|
TEST_F(SdcDesignTest, R10_ClockEdgeDetails) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
bool prop = clk->isPropagated();
|
|
(void)prop;
|
|
// Each clock has 2 edges: rise and fall
|
|
ClockEdge *rise = clk->edge(RiseFall::rise());
|
|
ClockEdge *fall = clk->edge(RiseFall::fall());
|
|
ASSERT_NE(rise, nullptr);
|
|
ASSERT_NE(fall, nullptr);
|
|
// Opposite edges
|
|
const ClockEdge *rise_opp = rise->opposite();
|
|
EXPECT_EQ(rise_opp, fall);
|
|
const ClockEdge *fall_opp = fall->opposite();
|
|
EXPECT_EQ(fall_opp, rise);
|
|
}
|
|
|
|
// --- Sdc: clocks() - get all clocks ---
|
|
TEST_F(SdcDesignTest, R10_SdcClocksList) {
|
|
Sdc *sdc = sta_->sdc();
|
|
const ClockSeq &clks = sdc->clks();
|
|
EXPECT_GT(clks.size(), 0u);
|
|
for (Clock *c : clks) {
|
|
EXPECT_NE(c->name(), nullptr);
|
|
}
|
|
}
|
|
|
|
// --- InputDrive: accessors ---
|
|
TEST_F(SdcDesignTest, R10_InputDriveAccessors) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
if (in1) {
|
|
Port *port = network->port(in1);
|
|
if (port) {
|
|
// Set a drive resistance
|
|
sta_->setDriveResistance(port, RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), 75.0f);
|
|
// Now check the input drive on the port via Sdc
|
|
Sdc *sdc = sta_->sdc();
|
|
InputDrive *drive = sdc->findInputDrive(port);
|
|
if (drive) {
|
|
bool has_cell = drive->hasDriveCell(RiseFall::rise(), MinMax::max());
|
|
(void)has_cell;
|
|
InputDriveCell *dc = drive->driveCell(RiseFall::rise(), MinMax::max());
|
|
(void)dc;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ============================================================
|
|
// R11_ SDC Tests - WriteSdc coverage and Sdc method coverage
|
|
// ============================================================
|
|
|
|
// --- WriteSdc with net wire cap (triggers writeNetLoads, writeNetLoad,
|
|
// writeGetNet, WriteGetNet, scaleCapacitance, writeFloat, writeCapacitance,
|
|
// writeCommentSeparator, closeFile, ~WriteSdc) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcWithNetWireCap) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
NetIterator *net_iter = network->netIterator(top);
|
|
if (net_iter->hasNext()) {
|
|
Net *net = net_iter->next();
|
|
Corner *corner = sta_->cmdCorner();
|
|
sta_->setNetWireCap(net, false, corner, MinMaxAll::all(), 0.05f);
|
|
}
|
|
delete net_iter;
|
|
const char *filename = "/tmp/test_sdc_r11_netwire.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with net resistance (triggers writeNetResistances,
|
|
// writeNetResistance, writeGetNet, scaleResistance, writeResistance) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcWithNetResistance) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
NetIterator *net_iter = network->netIterator(top);
|
|
if (net_iter->hasNext()) {
|
|
Net *net = net_iter->next();
|
|
sta_->setResistance(net, MinMaxAll::all(), 100.0f);
|
|
}
|
|
delete net_iter;
|
|
const char *filename = "/tmp/test_sdc_r11_netres.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with input slew (triggers writeInputTransitions,
|
|
// writeRiseFallMinMaxTimeCmd, WriteGetPort, scaleTime) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcWithInputSlew) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
if (in1) {
|
|
Port *port = network->port(in1);
|
|
if (port) {
|
|
sta_->setInputSlew(port, RiseFallBoth::riseFall(),
|
|
MinMaxAll::all(), 0.1f);
|
|
}
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_inputslew.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with driving cell (triggers writeDrivingCells, writeDrivingCell,
|
|
// WriteGetLibCell, WriteGetPort) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcWithDrivingCell) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
if (in1) {
|
|
Port *port = network->port(in1);
|
|
if (port) {
|
|
// Find a buffer cell to use as driving cell
|
|
LibertyLibrary *lib = nullptr;
|
|
LibertyLibraryIterator *lib_iter = network->libertyLibraryIterator();
|
|
if (lib_iter->hasNext())
|
|
lib = lib_iter->next();
|
|
delete lib_iter;
|
|
if (lib) {
|
|
LibertyCell *buf_cell = nullptr;
|
|
LibertyCellIterator cell_iter(lib);
|
|
while (cell_iter.hasNext()) {
|
|
LibertyCell *cell = cell_iter.next();
|
|
if (cell->portCount() >= 2) {
|
|
buf_cell = cell;
|
|
break;
|
|
}
|
|
}
|
|
if (buf_cell) {
|
|
// Find input and output ports on the cell
|
|
LibertyPort *from_port = nullptr;
|
|
LibertyPort *to_port = nullptr;
|
|
LibertyCellPortIterator port_iter(buf_cell);
|
|
while (port_iter.hasNext()) {
|
|
LibertyPort *lp = port_iter.next();
|
|
if (lp->direction()->isInput() && !from_port)
|
|
from_port = lp;
|
|
else if (lp->direction()->isOutput() && !to_port)
|
|
to_port = lp;
|
|
}
|
|
if (from_port && to_port) {
|
|
float from_slews[2] = {0.05f, 0.05f};
|
|
sta_->setDriveCell(lib, buf_cell, port,
|
|
from_port, from_slews, to_port,
|
|
RiseFallBoth::riseFall(), MinMaxAll::all());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_drivecell.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with clock groups that have actual clock members
|
|
// (triggers writeClockGroups, WriteGetClock, writeGetClock) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcWithClockGroupsMembers) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk");
|
|
if (clk) {
|
|
// Create a second clock
|
|
Network *network = sta_->network();
|
|
Instance *top = network->topInstance();
|
|
Pin *clk2_pin = network->findPin(top, "clk2");
|
|
if (clk2_pin) {
|
|
PinSet *clk2_pins = new PinSet(network);
|
|
clk2_pins->insert(clk2_pin);
|
|
FloatSeq *waveform2 = new FloatSeq;
|
|
waveform2->push_back(0.0f);
|
|
waveform2->push_back(2.5f);
|
|
sta_->makeClock("clk2", clk2_pins, false, 5.0f, waveform2, nullptr);
|
|
Clock *clk2 = sdc->findClock("clk2");
|
|
if (clk2) {
|
|
ClockGroups *cg = sta_->makeClockGroups("grp1", true, false, false,
|
|
false, nullptr);
|
|
ClockSet *group1 = new ClockSet;
|
|
group1->insert(clk);
|
|
sta_->makeClockGroup(cg, group1);
|
|
ClockSet *group2 = new ClockSet;
|
|
group2->insert(clk2);
|
|
sta_->makeClockGroup(cg, group2);
|
|
}
|
|
}
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_clkgrp_members.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with false path having -from pins and -through pins and -to pins
|
|
// (triggers writeExceptionFrom, WriteGetPin, writeExceptionThru,
|
|
// writeExceptionTo) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcFalsePathFromThruTo) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
Pin *out = network->findPin(top, "out");
|
|
if (in1 && out) {
|
|
// -from
|
|
PinSet *from_pins = new PinSet(network);
|
|
from_pins->insert(in1);
|
|
ExceptionFrom *from = sta_->makeExceptionFrom(from_pins, nullptr, nullptr,
|
|
RiseFallBoth::riseFall());
|
|
// -through: use an instance
|
|
InstanceChildIterator *inst_iter = network->childIterator(top);
|
|
ExceptionThruSeq *thrus = new ExceptionThruSeq;
|
|
if (inst_iter->hasNext()) {
|
|
Instance *inst = inst_iter->next();
|
|
InstanceSet *insts = new InstanceSet(network);
|
|
insts->insert(inst);
|
|
ExceptionThru *thru = sta_->makeExceptionThru(nullptr, nullptr, insts,
|
|
RiseFallBoth::riseFall());
|
|
thrus->push_back(thru);
|
|
}
|
|
delete inst_iter;
|
|
// -to
|
|
PinSet *to_pins = new PinSet(network);
|
|
to_pins->insert(out);
|
|
ExceptionTo *to = sta_->makeExceptionTo(to_pins, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(),
|
|
RiseFallBoth::riseFall());
|
|
sta_->makeFalsePath(from, thrus, to, MinMaxAll::all(), nullptr);
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_fp_fromthru.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with false path -through net
|
|
// (triggers writeExceptionThru with nets, writeGetNet) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcFalsePathThruNet) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
NetIterator *net_iter = network->netIterator(top);
|
|
if (net_iter->hasNext()) {
|
|
Net *net = net_iter->next();
|
|
NetSet *nets = new NetSet(network);
|
|
nets->insert(net);
|
|
ExceptionThruSeq *thrus = new ExceptionThruSeq;
|
|
ExceptionThru *thru = sta_->makeExceptionThru(nullptr, nets, nullptr,
|
|
RiseFallBoth::riseFall());
|
|
thrus->push_back(thru);
|
|
sta_->makeFalsePath(nullptr, thrus, nullptr, MinMaxAll::all(), nullptr);
|
|
}
|
|
delete net_iter;
|
|
const char *filename = "/tmp/test_sdc_r11_fp_thrunet.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with false path -from clock (triggers writeGetClock in from) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcFalsePathFromClock) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk");
|
|
if (clk) {
|
|
ClockSet *from_clks = new ClockSet;
|
|
from_clks->insert(clk);
|
|
ExceptionFrom *from = sta_->makeExceptionFrom(nullptr, from_clks, nullptr,
|
|
RiseFallBoth::riseFall());
|
|
sta_->makeFalsePath(from, nullptr, nullptr, MinMaxAll::all(), nullptr);
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_fp_fromclk.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with false path -from instance (triggers writeGetInstance,
|
|
// WriteGetInstance) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcFalsePathFromInstance) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
InstanceChildIterator *iter = network->childIterator(top);
|
|
if (iter->hasNext()) {
|
|
Instance *inst = iter->next();
|
|
InstanceSet *from_insts = new InstanceSet(network);
|
|
from_insts->insert(inst);
|
|
ExceptionFrom *from = sta_->makeExceptionFrom(nullptr, nullptr, from_insts,
|
|
RiseFallBoth::riseFall());
|
|
sta_->makeFalsePath(from, nullptr, nullptr, MinMaxAll::all(), nullptr);
|
|
}
|
|
delete iter;
|
|
const char *filename = "/tmp/test_sdc_r11_fp_frominst.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with multicycle path with -from pin
|
|
// (triggers writeExceptionCmd for multicycle, writeExceptionFrom) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcMulticycleWithFrom) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
if (in1) {
|
|
PinSet *from_pins = new PinSet(network);
|
|
from_pins->insert(in1);
|
|
ExceptionFrom *from = sta_->makeExceptionFrom(from_pins, nullptr, nullptr,
|
|
RiseFallBoth::riseFall());
|
|
sta_->makeMulticyclePath(from, nullptr, nullptr,
|
|
MinMaxAll::max(), true, 3, nullptr);
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_mcp_from.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with path delay (max_delay/min_delay)
|
|
// (triggers writeExceptionCmd for path delay, writeExceptionValue) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcPathDelay) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
Pin *out = network->findPin(top, "out");
|
|
if (in1 && out) {
|
|
PinSet *from_pins = new PinSet(network);
|
|
from_pins->insert(in1);
|
|
ExceptionFrom *from = sta_->makeExceptionFrom(from_pins, nullptr, nullptr,
|
|
RiseFallBoth::riseFall());
|
|
PinSet *to_pins = new PinSet(network);
|
|
to_pins->insert(out);
|
|
ExceptionTo *to = sta_->makeExceptionTo(to_pins, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(),
|
|
RiseFallBoth::riseFall());
|
|
sta_->makePathDelay(from, nullptr, to, MinMax::max(), false, false,
|
|
5.0f, nullptr);
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_pathdelay.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with group path
|
|
// (triggers writeExceptionCmd for group path) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcGroupPath) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
if (in1) {
|
|
PinSet *from_pins = new PinSet(network);
|
|
from_pins->insert(in1);
|
|
ExceptionFrom *from = sta_->makeExceptionFrom(from_pins, nullptr, nullptr,
|
|
RiseFallBoth::riseFall());
|
|
sta_->makeGroupPath("mygroup", false, from, nullptr, nullptr, nullptr);
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_grouppath.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with clock sense
|
|
// (triggers writeClockSenses, PinClockPairNameLess) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcWithClockSense) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *clk1 = network->findPin(top, "clk1");
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk");
|
|
if (clk1 && clk) {
|
|
PinSet *pins = new PinSet(network);
|
|
pins->insert(clk1);
|
|
ClockSet *clks = new ClockSet;
|
|
clks->insert(clk);
|
|
sta_->setClockSense(pins, clks, ClockSense::positive);
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_clksense.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with port ext wire cap and fanout
|
|
// (triggers writePortLoads with wire cap, writeMinMaxIntValuesCmd) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcWithPortExtWireCap) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *out = network->findPin(top, "out");
|
|
if (out) {
|
|
Port *port = network->port(out);
|
|
Corner *corner = sta_->cmdCorner();
|
|
if (port && corner) {
|
|
sta_->setPortExtWireCap(port, false, RiseFallBoth::riseFall(),
|
|
corner, MinMaxAll::all(), 0.02f);
|
|
sta_->setPortExtFanout(port, 3, corner, MinMaxAll::all());
|
|
}
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_portwire.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with clock gating check
|
|
// (triggers writeClockGatingChecks) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcWithClockGatingCheck) {
|
|
sta_->setClockGatingCheck(RiseFallBoth::riseFall(),
|
|
MinMax::max(), 0.1f);
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk");
|
|
if (clk)
|
|
sta_->setClockGatingCheck(clk, RiseFallBoth::riseFall(),
|
|
MinMax::min(), 0.05f);
|
|
const char *filename = "/tmp/test_sdc_r11_clkgate.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- Sdc: connectedCap via Sta API ---
|
|
TEST_F(SdcDesignTest, R11_SdcConnectedCap) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *out = network->findPin(top, "out");
|
|
if (out) {
|
|
Corner *corner = sta_->cmdCorner();
|
|
float pin_cap, wire_cap;
|
|
sta_->connectedCap(out, RiseFall::rise(), corner, MinMax::max(),
|
|
pin_cap, wire_cap);
|
|
(void)pin_cap;
|
|
(void)wire_cap;
|
|
}
|
|
}
|
|
|
|
// --- Sdc: connectedCap on net via Sta API ---
|
|
TEST_F(SdcDesignTest, R11_SdcConnectedCapNet) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
NetIterator *net_iter = network->netIterator(top);
|
|
if (net_iter->hasNext()) {
|
|
Net *net = net_iter->next();
|
|
Corner *corner = sta_->cmdCorner();
|
|
float pin_cap, wire_cap;
|
|
sta_->connectedCap(net, corner, MinMax::max(), pin_cap, wire_cap);
|
|
(void)pin_cap;
|
|
(void)wire_cap;
|
|
}
|
|
delete net_iter;
|
|
}
|
|
|
|
// --- ExceptionPath::mergeable ---
|
|
TEST_F(SdcDesignTest, R11_ExceptionPathMergeable) {
|
|
// Create two false paths and check mergeability
|
|
sta_->makeFalsePath(nullptr, nullptr, nullptr, MinMaxAll::all(), nullptr);
|
|
Sdc *sdc = sta_->sdc();
|
|
ExceptionPathSet &exceptions = sdc->exceptions();
|
|
ExceptionPath *first = nullptr;
|
|
for (ExceptionPath *ep : exceptions) {
|
|
if (ep->isFalse()) {
|
|
if (!first) {
|
|
first = ep;
|
|
} else {
|
|
bool m = first->mergeable(ep);
|
|
(void)m;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- WriteSdc with propagated clock on pin
|
|
// (triggers writePropagatedClkPins) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcWithPropagatedClk) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *clk1 = network->findPin(top, "clk1");
|
|
if (clk1) {
|
|
sta_->setPropagatedClock(clk1);
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_propagated.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with min_delay path delay
|
|
// (triggers min_delay branch in writeExceptionCmd) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcMinDelay) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
Pin *out = network->findPin(top, "out");
|
|
if (in1 && out) {
|
|
PinSet *from_pins = new PinSet(network);
|
|
from_pins->insert(in1);
|
|
ExceptionFrom *from = sta_->makeExceptionFrom(from_pins, nullptr, nullptr,
|
|
RiseFallBoth::riseFall());
|
|
PinSet *to_pins = new PinSet(network);
|
|
to_pins->insert(out);
|
|
ExceptionTo *to = sta_->makeExceptionTo(to_pins, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(),
|
|
RiseFallBoth::riseFall());
|
|
sta_->makePathDelay(from, nullptr, to, MinMax::min(), false, false,
|
|
1.0f, nullptr);
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_mindelay.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with multicycle -hold (min) with -end
|
|
// (triggers the hold branch in writeExceptionCmd) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcMulticycleHold) {
|
|
sta_->makeMulticyclePath(nullptr, nullptr, nullptr,
|
|
MinMaxAll::min(), true, 0, nullptr);
|
|
const char *filename = "/tmp/test_sdc_r11_mcp_hold.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with multicycle -setup with -start
|
|
// (triggers the start branch in writeExceptionCmd) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcMulticycleStart) {
|
|
sta_->makeMulticyclePath(nullptr, nullptr, nullptr,
|
|
MinMaxAll::max(), false, 2, nullptr);
|
|
const char *filename = "/tmp/test_sdc_r11_mcp_start.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with group path default
|
|
// (triggers isDefault branch in writeExceptionCmd) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcGroupPathDefault) {
|
|
sta_->makeGroupPath(nullptr, true, nullptr, nullptr, nullptr, nullptr);
|
|
const char *filename = "/tmp/test_sdc_r11_grppath_default.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with false path -from with rise_from
|
|
// (triggers rf_prefix = "-rise_" branch) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcFalsePathRiseFrom) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
if (in1) {
|
|
PinSet *from_pins = new PinSet(network);
|
|
from_pins->insert(in1);
|
|
ExceptionFrom *from = sta_->makeExceptionFrom(from_pins, nullptr, nullptr,
|
|
RiseFallBoth::rise());
|
|
sta_->makeFalsePath(from, nullptr, nullptr, MinMaxAll::all(), nullptr);
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_fp_risefrom.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with false path -from with fall_from
|
|
// (triggers rf_prefix = "-fall_" branch) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcFalsePathFallFrom) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
if (in1) {
|
|
PinSet *from_pins = new PinSet(network);
|
|
from_pins->insert(in1);
|
|
ExceptionFrom *from = sta_->makeExceptionFrom(from_pins, nullptr, nullptr,
|
|
RiseFallBoth::fall());
|
|
sta_->makeFalsePath(from, nullptr, nullptr, MinMaxAll::all(), nullptr);
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_fp_fallfrom.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with path delay -ignore_clock_latency
|
|
// (triggers the ignoreClkLatency branch) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcPathDelayIgnoreClkLat) {
|
|
sta_->makePathDelay(nullptr, nullptr, nullptr, MinMax::max(), true, false,
|
|
8.0f, nullptr);
|
|
const char *filename = "/tmp/test_sdc_r11_pathdelay_ignoreclk.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with false path -to with end_rf rise
|
|
// (triggers the end_rf != riseFall branch in writeExceptionTo) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcFalsePathToRise) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *out = network->findPin(top, "out");
|
|
if (out) {
|
|
PinSet *to_pins = new PinSet(network);
|
|
to_pins->insert(out);
|
|
ExceptionTo *to = sta_->makeExceptionTo(to_pins, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(),
|
|
RiseFallBoth::rise());
|
|
sta_->makeFalsePath(nullptr, nullptr, to, MinMaxAll::all(), nullptr);
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_fp_torise.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with multiple from objects (triggers multi_objs branch with [list ]) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcFalsePathMultiFrom) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
Pin *in2 = network->findPin(top, "in2");
|
|
if (in1 && in2) {
|
|
PinSet *from_pins = new PinSet(network);
|
|
from_pins->insert(in1);
|
|
from_pins->insert(in2);
|
|
ExceptionFrom *from = sta_->makeExceptionFrom(from_pins, nullptr, nullptr,
|
|
RiseFallBoth::riseFall());
|
|
sta_->makeFalsePath(from, nullptr, nullptr, MinMaxAll::all(), nullptr);
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_fp_multifrom.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with data check that has a clock ref
|
|
// (triggers writeDataChecks, WriteGetPinAndClkKey) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcDataCheckWithClock) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *from_pin = network->findPin(top, "r1/D");
|
|
Pin *to_pin = network->findPin(top, "r1/CK");
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk");
|
|
if (from_pin && to_pin && clk) {
|
|
sta_->setDataCheck(from_pin, RiseFallBoth::riseFall(),
|
|
to_pin, RiseFallBoth::riseFall(),
|
|
clk, MinMaxAll::max(), 0.5f);
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_datacheck_clk.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- Sdc::removeDataCheck ---
|
|
TEST_F(SdcDesignTest, R11_SdcRemoveDataCheck) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *from_pin = network->findPin(top, "r1/D");
|
|
Pin *to_pin = network->findPin(top, "r1/CK");
|
|
if (from_pin && to_pin) {
|
|
sta_->setDataCheck(from_pin, RiseFallBoth::riseFall(),
|
|
to_pin, RiseFallBoth::riseFall(),
|
|
nullptr, MinMaxAll::max(), 1.0f);
|
|
sta_->removeDataCheck(from_pin, RiseFallBoth::riseFall(),
|
|
to_pin, RiseFallBoth::riseFall(),
|
|
nullptr, MinMaxAll::max());
|
|
}
|
|
}
|
|
|
|
// --- WriteSdc with clock uncertainty on pin
|
|
// (triggers writeClockUncertaintyPins, writeClockUncertaintyPin) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcClockUncertaintyPin) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *clk1 = network->findPin(top, "clk1");
|
|
if (clk1) {
|
|
sta_->setClockUncertainty(clk1, MinMaxAll::max(), 0.2f);
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_clkuncpin.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with voltage on net
|
|
// (triggers writeVoltages with net voltage) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcVoltageNet) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
NetIterator *net_iter = network->netIterator(top);
|
|
if (net_iter->hasNext()) {
|
|
Net *net = net_iter->next();
|
|
sta_->setVoltage(net, MinMax::max(), 1.0f);
|
|
sta_->setVoltage(net, MinMax::min(), 0.9f);
|
|
}
|
|
delete net_iter;
|
|
const char *filename = "/tmp/test_sdc_r11_voltnet.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with disable on timing arcs of cell
|
|
// (triggers writeGetTimingArcsOfOjbects, writeGetTimingArcs,
|
|
// getTimingArcsCmd) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcDisableTimingArcs) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
InstanceChildIterator *iter = network->childIterator(top);
|
|
if (iter->hasNext()) {
|
|
Instance *inst = iter->next();
|
|
LibertyCell *lib_cell = network->libertyCell(inst);
|
|
if (lib_cell) {
|
|
LibertyPort *in_port = nullptr;
|
|
LibertyPort *out_port = nullptr;
|
|
LibertyCellPortIterator port_iter(lib_cell);
|
|
while (port_iter.hasNext()) {
|
|
LibertyPort *port = port_iter.next();
|
|
if (port->direction()->isInput() && !in_port)
|
|
in_port = port;
|
|
else if (port->direction()->isOutput() && !out_port)
|
|
out_port = port;
|
|
}
|
|
if (in_port && out_port) {
|
|
// Disable specific from->to arc on cell
|
|
sta_->disable(lib_cell, in_port, out_port);
|
|
}
|
|
}
|
|
}
|
|
delete iter;
|
|
const char *filename = "/tmp/test_sdc_r11_disablearcs.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with min pulse width on clock
|
|
// (triggers writeMinPulseWidths clock branch) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcMpwClock) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk");
|
|
if (clk) {
|
|
sta_->setMinPulseWidth(clk, RiseFallBoth::rise(), 0.4f);
|
|
sta_->setMinPulseWidth(clk, RiseFallBoth::fall(), 0.3f);
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_mpwclk.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with slew limit on clock data
|
|
// (triggers writeClkSlewLimits, writeClkSlewLimit) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcSlewLimitClkData) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk");
|
|
if (clk) {
|
|
sta_->setSlewLimit(clk, RiseFallBoth::riseFall(),
|
|
PathClkOrData::clk, MinMax::max(), 1.5f);
|
|
sta_->setSlewLimit(clk, RiseFallBoth::riseFall(),
|
|
PathClkOrData::data, MinMax::max(), 2.5f);
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_slewclkdata.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with cell-level cap limit
|
|
// (triggers writeCapLimits cell branch) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcCapLimitCell) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
InstanceChildIterator *iter = network->childIterator(top);
|
|
if (iter->hasNext()) {
|
|
Instance *inst = iter->next();
|
|
Cell *cell = network->cell(inst);
|
|
if (cell) {
|
|
sta_->setCapacitanceLimit(cell, MinMax::max(), 2.0f);
|
|
}
|
|
}
|
|
delete iter;
|
|
const char *filename = "/tmp/test_sdc_r11_caplimitcell.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with cell-level fanout limit
|
|
// (triggers writeFanoutLimits cell branch) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcFanoutLimitCell) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
InstanceChildIterator *iter = network->childIterator(top);
|
|
if (iter->hasNext()) {
|
|
Instance *inst = iter->next();
|
|
Cell *cell = network->cell(inst);
|
|
if (cell) {
|
|
sta_->setFanoutLimit(cell, MinMax::max(), 15.0f);
|
|
}
|
|
}
|
|
delete iter;
|
|
const char *filename = "/tmp/test_sdc_r11_fanoutcell.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with cell-level slew limit
|
|
// (triggers writeSlewLimits cell branch) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcSlewLimitCell) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
InstanceChildIterator *iter = network->childIterator(top);
|
|
if (iter->hasNext()) {
|
|
Instance *inst = iter->next();
|
|
Cell *cell = network->cell(inst);
|
|
if (cell) {
|
|
sta_->setSlewLimit(cell, MinMax::max(), 5.0f);
|
|
}
|
|
}
|
|
delete iter;
|
|
const char *filename = "/tmp/test_sdc_r11_slewcell.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc comprehensive: trigger as many writer paths as possible ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcMegaComprehensive) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk");
|
|
Corner *corner = sta_->cmdCorner();
|
|
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
Pin *in2 = network->findPin(top, "in2");
|
|
Pin *out = network->findPin(top, "out");
|
|
|
|
// Net wire cap and resistance
|
|
NetIterator *net_iter = network->netIterator(top);
|
|
if (net_iter->hasNext()) {
|
|
Net *net = net_iter->next();
|
|
sta_->setNetWireCap(net, false, corner, MinMaxAll::all(), 0.03f);
|
|
sta_->setResistance(net, MinMaxAll::all(), 50.0f);
|
|
sta_->setVoltage(net, MinMax::max(), 1.1f);
|
|
}
|
|
delete net_iter;
|
|
|
|
// Input slew
|
|
if (in1) {
|
|
Port *port = network->port(in1);
|
|
if (port)
|
|
sta_->setInputSlew(port, RiseFallBoth::riseFall(), MinMaxAll::all(), 0.08f);
|
|
}
|
|
|
|
// Port ext wire cap + fanout
|
|
if (out) {
|
|
Port *port = network->port(out);
|
|
if (port && corner) {
|
|
sta_->setPortExtPinCap(port, RiseFallBoth::riseFall(), corner,
|
|
MinMaxAll::all(), 0.1f);
|
|
sta_->setPortExtWireCap(port, false, RiseFallBoth::riseFall(), corner,
|
|
MinMaxAll::all(), 0.015f);
|
|
sta_->setPortExtFanout(port, 2, corner, MinMaxAll::all());
|
|
}
|
|
}
|
|
|
|
// Clock groups
|
|
if (clk) {
|
|
ClockGroups *cg = sta_->makeClockGroups("mega_grp", false, true, false,
|
|
false, nullptr);
|
|
ClockSet *g1 = new ClockSet;
|
|
g1->insert(clk);
|
|
sta_->makeClockGroup(cg, g1);
|
|
}
|
|
|
|
// False path with -from pin, -through instance, -to pin
|
|
if (in1 && out) {
|
|
PinSet *from_pins = new PinSet(network);
|
|
from_pins->insert(in1);
|
|
ExceptionFrom *from = sta_->makeExceptionFrom(from_pins, nullptr, nullptr,
|
|
RiseFallBoth::rise());
|
|
InstanceChildIterator *inst_iter = network->childIterator(top);
|
|
ExceptionThruSeq *thrus = new ExceptionThruSeq;
|
|
if (inst_iter->hasNext()) {
|
|
Instance *inst = inst_iter->next();
|
|
InstanceSet *insts = new InstanceSet(network);
|
|
insts->insert(inst);
|
|
ExceptionThru *thru = sta_->makeExceptionThru(nullptr, nullptr, insts,
|
|
RiseFallBoth::riseFall());
|
|
thrus->push_back(thru);
|
|
}
|
|
delete inst_iter;
|
|
PinSet *to_pins = new PinSet(network);
|
|
to_pins->insert(out);
|
|
ExceptionTo *to = sta_->makeExceptionTo(to_pins, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(),
|
|
RiseFallBoth::rise());
|
|
sta_->makeFalsePath(from, thrus, to, MinMaxAll::all(), nullptr);
|
|
}
|
|
|
|
// Max/min delay
|
|
if (in2 && out) {
|
|
PinSet *from_pins = new PinSet(network);
|
|
from_pins->insert(in2);
|
|
ExceptionFrom *from = sta_->makeExceptionFrom(from_pins, nullptr, nullptr,
|
|
RiseFallBoth::riseFall());
|
|
PinSet *to_pins = new PinSet(network);
|
|
to_pins->insert(out);
|
|
ExceptionTo *to = sta_->makeExceptionTo(to_pins, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(),
|
|
RiseFallBoth::riseFall());
|
|
sta_->makePathDelay(from, nullptr, to, MinMax::max(), true, false,
|
|
6.0f, nullptr);
|
|
}
|
|
|
|
// Multicycle
|
|
sta_->makeMulticyclePath(nullptr, nullptr, nullptr,
|
|
MinMaxAll::max(), false, 4, nullptr);
|
|
|
|
// Group path
|
|
sta_->makeGroupPath("mega", false, nullptr, nullptr, nullptr, nullptr);
|
|
|
|
// Clock gating check
|
|
sta_->setClockGatingCheck(RiseFallBoth::riseFall(), MinMax::max(), 0.15f);
|
|
|
|
// Logic value
|
|
if (in2) {
|
|
sta_->setLogicValue(in2, LogicValue::zero);
|
|
}
|
|
|
|
// Voltage
|
|
sdc->setVoltage(MinMax::max(), 1.2);
|
|
sdc->setVoltage(MinMax::min(), 0.8);
|
|
|
|
// Min pulse width
|
|
sdc->setMinPulseWidth(RiseFallBoth::rise(), 0.35);
|
|
sdc->setMinPulseWidth(RiseFallBoth::fall(), 0.25);
|
|
|
|
// Max area
|
|
sdc->setMaxArea(3000.0);
|
|
|
|
// Write SDC
|
|
const char *filename = "/tmp/test_sdc_r11_mega.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
|
|
// Also write in native mode
|
|
const char *filename2 = "/tmp/test_sdc_r11_mega_native.sdc";
|
|
sta_->writeSdc(filename2, false, true, 4, false, true);
|
|
FILE *f2 = fopen(filename2, "r");
|
|
EXPECT_NE(f2, nullptr);
|
|
if (f2) fclose(f2);
|
|
|
|
// Also write in leaf mode
|
|
const char *filename3 = "/tmp/test_sdc_r11_mega_leaf.sdc";
|
|
sta_->writeSdc(filename3, true, false, 4, false, true);
|
|
FILE *f3 = fopen(filename3, "r");
|
|
EXPECT_NE(f3, nullptr);
|
|
if (f3) fclose(f3);
|
|
}
|
|
|
|
// --- Sdc: remove clock groups ---
|
|
TEST_F(SdcDesignTest, R11_SdcRemoveClockGroups) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk");
|
|
if (clk) {
|
|
ClockGroups *cg = sta_->makeClockGroups("rm_grp", true, false, false,
|
|
false, nullptr);
|
|
ClockSet *g1 = new ClockSet;
|
|
g1->insert(clk);
|
|
sta_->makeClockGroup(cg, g1);
|
|
// Remove by name
|
|
sta_->removeClockGroupsLogicallyExclusive("rm_grp");
|
|
}
|
|
}
|
|
|
|
// --- Sdc: remove physically exclusive clock groups ---
|
|
TEST_F(SdcDesignTest, R11_SdcRemovePhysExclClkGroups) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk");
|
|
if (clk) {
|
|
ClockGroups *cg = sta_->makeClockGroups("phys_grp", false, true, false,
|
|
false, nullptr);
|
|
ClockSet *g1 = new ClockSet;
|
|
g1->insert(clk);
|
|
sta_->makeClockGroup(cg, g1);
|
|
sta_->removeClockGroupsPhysicallyExclusive("phys_grp");
|
|
}
|
|
}
|
|
|
|
// --- Sdc: remove async clock groups ---
|
|
TEST_F(SdcDesignTest, R11_SdcRemoveAsyncClkGroups) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk");
|
|
if (clk) {
|
|
ClockGroups *cg = sta_->makeClockGroups("async_grp", false, false, true,
|
|
false, nullptr);
|
|
ClockSet *g1 = new ClockSet;
|
|
g1->insert(clk);
|
|
sta_->makeClockGroup(cg, g1);
|
|
sta_->removeClockGroupsAsynchronous("async_grp");
|
|
}
|
|
}
|
|
|
|
// --- Sdc: clear via removeConstraints (covers initVariables, clearCycleAcctings) ---
|
|
TEST_F(SdcDesignTest, R11_SdcRemoveConstraintsCover) {
|
|
Sdc *sdc = sta_->sdc();
|
|
// Set various constraints first
|
|
sdc->setMaxArea(500.0);
|
|
sdc->setMinPulseWidth(RiseFallBoth::rise(), 0.3);
|
|
sdc->setVoltage(MinMax::max(), 1.1);
|
|
// removeConstraints calls initVariables and clearCycleAcctings internally
|
|
sta_->removeConstraints();
|
|
}
|
|
|
|
// --- ExceptionFrom: hash via exception creation and matching ---
|
|
TEST_F(SdcDesignTest, R11_ExceptionFromMatching) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
Pin *in2 = network->findPin(top, "in2");
|
|
if (in1 && in2) {
|
|
PinSet *pins1 = new PinSet(network);
|
|
pins1->insert(in1);
|
|
ExceptionFrom *from1 = sta_->makeExceptionFrom(pins1, nullptr, nullptr,
|
|
RiseFallBoth::riseFall());
|
|
PinSet *pins2 = new PinSet(network);
|
|
pins2->insert(in2);
|
|
ExceptionFrom *from2 = sta_->makeExceptionFrom(pins2, nullptr, nullptr,
|
|
RiseFallBoth::riseFall());
|
|
// Make false paths - internally triggers findHash
|
|
sta_->makeFalsePath(from1, nullptr, nullptr, MinMaxAll::all(), nullptr);
|
|
sta_->makeFalsePath(from2, nullptr, nullptr, MinMaxAll::all(), nullptr);
|
|
}
|
|
}
|
|
|
|
// --- DisabledCellPorts accessors ---
|
|
TEST_F(SdcDesignTest, R11_DisabledCellPortsAccessors) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
InstanceChildIterator *iter = network->childIterator(top);
|
|
if (iter->hasNext()) {
|
|
Instance *inst = iter->next();
|
|
LibertyCell *lib_cell = network->libertyCell(inst);
|
|
if (lib_cell) {
|
|
DisabledCellPorts *dcp = new DisabledCellPorts(lib_cell);
|
|
EXPECT_EQ(dcp->cell(), lib_cell);
|
|
bool all_disabled = dcp->all();
|
|
(void)all_disabled;
|
|
delete dcp;
|
|
}
|
|
}
|
|
delete iter;
|
|
}
|
|
|
|
// --- DisabledInstancePorts with disable ---
|
|
TEST_F(SdcDesignTest, R11_DisabledInstancePortsDisable) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
InstanceChildIterator *iter = network->childIterator(top);
|
|
if (iter->hasNext()) {
|
|
Instance *inst = iter->next();
|
|
LibertyCell *lib_cell = network->libertyCell(inst);
|
|
if (lib_cell) {
|
|
LibertyPort *in_port = nullptr;
|
|
LibertyPort *out_port = nullptr;
|
|
LibertyCellPortIterator port_iter(lib_cell);
|
|
while (port_iter.hasNext()) {
|
|
LibertyPort *port = port_iter.next();
|
|
if (port->direction()->isInput() && !in_port)
|
|
in_port = port;
|
|
else if (port->direction()->isOutput() && !out_port)
|
|
out_port = port;
|
|
}
|
|
if (in_port && out_port) {
|
|
// Disable on instance with from/to
|
|
sta_->disable(inst, in_port, out_port);
|
|
// Write SDC to exercise the disabled instance path
|
|
const char *filename = "/tmp/test_sdc_r11_disinstports.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
// Remove the disable
|
|
sta_->removeDisable(inst, in_port, out_port);
|
|
}
|
|
}
|
|
}
|
|
delete iter;
|
|
}
|
|
|
|
// --- WriteSdc with latch borrow limit on clock
|
|
// (triggers writeLatchBorrowLimits clock branch) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcLatchBorrowClock) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Clock *clk = sdc->findClock("clk");
|
|
if (clk) {
|
|
sta_->setLatchBorrowLimit(clk, 0.6f);
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_latchborrowclk.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with derating on cell, instance, net ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcDeratingCellInstNet) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
|
|
// Cell-level derating
|
|
InstanceChildIterator *iter = network->childIterator(top);
|
|
if (iter->hasNext()) {
|
|
Instance *inst = iter->next();
|
|
LibertyCell *lib_cell = network->libertyCell(inst);
|
|
if (lib_cell) {
|
|
sta_->setTimingDerate(lib_cell,
|
|
TimingDerateCellType::cell_delay,
|
|
PathClkOrData::data,
|
|
RiseFallBoth::riseFall(),
|
|
EarlyLate::early(), 0.93);
|
|
}
|
|
// Instance-level derating
|
|
sta_->setTimingDerate(inst,
|
|
TimingDerateCellType::cell_delay,
|
|
PathClkOrData::data,
|
|
RiseFallBoth::riseFall(),
|
|
EarlyLate::late(), 1.07);
|
|
}
|
|
delete iter;
|
|
|
|
// Net-level derating
|
|
NetIterator *net_iter = network->netIterator(top);
|
|
if (net_iter->hasNext()) {
|
|
Net *net = net_iter->next();
|
|
sta_->setTimingDerate(net,
|
|
PathClkOrData::data,
|
|
RiseFallBoth::riseFall(),
|
|
EarlyLate::early(), 0.92);
|
|
}
|
|
delete net_iter;
|
|
|
|
const char *filename = "/tmp/test_sdc_r11_derate_all.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- Sdc: capacitanceLimit on pin ---
|
|
TEST_F(SdcDesignTest, R11_SdcCapLimitPin) {
|
|
Sdc *sdc = sta_->sdc();
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *out = network->findPin(top, "out");
|
|
if (out) {
|
|
sta_->setCapacitanceLimit(out, MinMax::max(), 0.5f);
|
|
float limit;
|
|
bool exists;
|
|
sdc->capacitanceLimit(out, MinMax::max(), limit, exists);
|
|
EXPECT_TRUE(exists);
|
|
EXPECT_FLOAT_EQ(limit, 0.5f);
|
|
}
|
|
}
|
|
|
|
// --- WriteSdc with set_false_path -hold only
|
|
// (triggers writeSetupHoldFlag for hold) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcFalsePathHold) {
|
|
sta_->makeFalsePath(nullptr, nullptr, nullptr, MinMaxAll::min(), nullptr);
|
|
const char *filename = "/tmp/test_sdc_r11_fp_hold.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with set_false_path -setup only
|
|
// (triggers writeSetupHoldFlag for setup) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcFalsePathSetup) {
|
|
sta_->makeFalsePath(nullptr, nullptr, nullptr, MinMaxAll::max(), nullptr);
|
|
const char *filename = "/tmp/test_sdc_r11_fp_setup.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
// --- WriteSdc with exception -through with rise_through
|
|
// (triggers rf_prefix branches in writeExceptionThru) ---
|
|
TEST_F(SdcDesignTest, R11_WriteSdcFalsePathRiseThru) {
|
|
Network *network = sta_->cmdNetwork();
|
|
Instance *top = network->topInstance();
|
|
Pin *in1 = network->findPin(top, "in1");
|
|
if (in1) {
|
|
PinSet *thru_pins = new PinSet(network);
|
|
thru_pins->insert(in1);
|
|
ExceptionThruSeq *thrus = new ExceptionThruSeq;
|
|
ExceptionThru *thru = sta_->makeExceptionThru(thru_pins, nullptr, nullptr,
|
|
RiseFallBoth::rise());
|
|
thrus->push_back(thru);
|
|
sta_->makeFalsePath(nullptr, thrus, nullptr, MinMaxAll::all(), nullptr);
|
|
}
|
|
const char *filename = "/tmp/test_sdc_r11_fp_risethru.sdc";
|
|
sta_->writeSdc(filename, false, false, 4, false, true);
|
|
FILE *f = fopen(filename, "r");
|
|
EXPECT_NE(f, nullptr);
|
|
if (f) fclose(f);
|
|
}
|
|
|
|
} // namespace sta
|