3411 lines
109 KiB
C++
3411 lines
109 KiB
C++
#include <gtest/gtest.h>
|
|
#include <tcl.h>
|
|
#include <fstream>
|
|
#include <iterator>
|
|
#include <string>
|
|
#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 "Scene.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 {
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// 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_;
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R5_ Tests - New tests for coverage improvement
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// Clock::addPin with nullptr - covers Clock::addPin
|
|
TEST_F(SdcInitTest, ClockAddPinNull) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->makeClock("clk_addpin", nullptr, false, 10.0,
|
|
waveform, "");
|
|
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, ClockSetSlewRfMinMax) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->makeClock("clk_slew", nullptr, false, 10.0,
|
|
waveform, "");
|
|
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, ClockEdgeTime) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->makeClock("clk_edge", nullptr, false, 10.0,
|
|
waveform, "");
|
|
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, ClockEdgeOpposite) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->makeClock("clk_opp", nullptr, false, 10.0,
|
|
waveform, "");
|
|
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, ClockEdgePulseWidth) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(4.0);
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->makeClock("clk_pw", nullptr, false, 10.0,
|
|
waveform, "");
|
|
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, ClockEdgeNameIndex) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->makeClock("clk_ni", nullptr, false, 10.0,
|
|
waveform, "");
|
|
ASSERT_NE(clk, nullptr);
|
|
ClockEdge *rise_edge = clk->edge(RiseFall::rise());
|
|
ASSERT_NE(rise_edge, nullptr);
|
|
EXPECT_FALSE(rise_edge->name().empty());
|
|
int idx = rise_edge->index();
|
|
EXPECT_GE(idx, 0);
|
|
}
|
|
|
|
// DisabledCellPorts - covers constructor/destructor and methods
|
|
TEST_F(SdcInitTest, DisabledCellPortsBasic) {
|
|
// We need a real liberty cell
|
|
LibertyLibrary *lib = sta_->readLiberty("test/nangate45/Nangate45_typ.lib",
|
|
sta_->cmdScene(),
|
|
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, DisabledCellPortsTimingArcSet) {
|
|
LibertyLibrary *lib = sta_->readLiberty("test/nangate45/Nangate45_typ.lib",
|
|
sta_->cmdScene(),
|
|
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, DisabledCellPortsIsDisabled) {
|
|
LibertyLibrary *lib = sta_->readLiberty("test/nangate45/Nangate45_typ.lib",
|
|
sta_->cmdScene(),
|
|
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, FalsePathTypeString) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, "");
|
|
EXPECT_NE(fp.typeString(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, PathDelayTypeString) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, true, "");
|
|
EXPECT_NE(pd.typeString(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, MultiCyclePathTypeString) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, "");
|
|
EXPECT_NE(mcp.typeString(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, FilterPathTypeString) {
|
|
FilterPath fp(nullptr, nullptr, nullptr, true);
|
|
EXPECT_NE(fp.typeString(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, GroupPathTypeString) {
|
|
GroupPath gp("grp1", false, nullptr, nullptr, nullptr, true, "");
|
|
EXPECT_NE(gp.typeString(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, LoopPathTypeString) {
|
|
LoopPath lp(nullptr, true);
|
|
EXPECT_NE(lp.typeString(), nullptr);
|
|
}
|
|
|
|
// ExceptionPath::mergeable tests
|
|
TEST_F(SdcInitTest, FalsePathMergeable) {
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::all(), true, "");
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::all(), true, "");
|
|
EXPECT_TRUE(fp1.mergeable(&fp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, PathDelayMergeable) {
|
|
PathDelay pd1(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, true, "");
|
|
PathDelay pd2(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, true, "");
|
|
EXPECT_TRUE(pd1.mergeable(&pd2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, PathDelayMergeableDifferentDelay) {
|
|
PathDelay pd1(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, true, "");
|
|
PathDelay pd2(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 10.0f, true, "");
|
|
EXPECT_FALSE(pd1.mergeable(&pd2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, MultiCyclePathMergeable) {
|
|
MultiCyclePath mcp1(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, "");
|
|
MultiCyclePath mcp2(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, "");
|
|
EXPECT_TRUE(mcp1.mergeable(&mcp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, GroupPathMergeable) {
|
|
GroupPath gp1("grp1", false, nullptr, nullptr, nullptr, true, "");
|
|
GroupPath gp2("grp1", false, nullptr, nullptr, nullptr, true, "");
|
|
EXPECT_TRUE(gp1.mergeable(&gp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, GroupPathNotMergeable) {
|
|
GroupPath gp1("grp1", false, nullptr, nullptr, nullptr, true, "");
|
|
GroupPath gp2("grp2", false, nullptr, nullptr, nullptr, true, "");
|
|
EXPECT_FALSE(gp1.mergeable(&gp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, LoopPathNotMergeable) {
|
|
LoopPath lp1(nullptr, true);
|
|
LoopPath lp2(nullptr, true);
|
|
EXPECT_FALSE(lp1.mergeable(&lp2));
|
|
}
|
|
|
|
// ExceptionPath::overrides tests
|
|
TEST_F(SdcInitTest, FalsePathOverrides) {
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::all(), true, "");
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::all(), true, "");
|
|
EXPECT_TRUE(fp1.overrides(&fp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, PathDelayOverrides) {
|
|
PathDelay pd1(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, true, "");
|
|
PathDelay pd2(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, true, "");
|
|
EXPECT_TRUE(pd1.overrides(&pd2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, MultiCyclePathOverrides) {
|
|
MultiCyclePath mcp1(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, "");
|
|
MultiCyclePath mcp2(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, "");
|
|
EXPECT_TRUE(mcp1.overrides(&mcp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, FilterPathOverrides2) {
|
|
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, GroupPathOverrides) {
|
|
GroupPath gp1("grp1", false, nullptr, nullptr, nullptr, true, "");
|
|
GroupPath gp2("grp1", false, nullptr, nullptr, nullptr, true, "");
|
|
EXPECT_TRUE(gp1.overrides(&gp2));
|
|
}
|
|
|
|
// ExceptionPath::matches with min_max
|
|
TEST_F(SdcInitTest, MultiCyclePathMatches) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, "");
|
|
EXPECT_TRUE(mcp.matches(MinMax::max(), false));
|
|
EXPECT_TRUE(mcp.matches(MinMax::min(), false));
|
|
}
|
|
|
|
// ExceptionPath type priorities
|
|
TEST_F(SdcInitTest, 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, ExceptionFromThruToPriority) {
|
|
int p = ExceptionPath::fromThruToPriority(nullptr, nullptr, nullptr);
|
|
EXPECT_EQ(p, 0);
|
|
}
|
|
|
|
// PathDelay specific getters
|
|
TEST_F(SdcInitTest, PathDelayGetters) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(),
|
|
true, true, 5.0f, true, "");
|
|
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, MultiCyclePathGetters) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::max(),
|
|
true, 5, true, "");
|
|
EXPECT_EQ(mcp.pathMultiplier(), 5);
|
|
EXPECT_TRUE(mcp.useEndClk());
|
|
EXPECT_TRUE(mcp.isMultiCycle());
|
|
}
|
|
|
|
// MultiCyclePath pathMultiplier with MinMax
|
|
TEST_F(SdcInitTest, MultiCyclePathMultiplierMinMax) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::max(),
|
|
true, 5, true, "");
|
|
int mult_max = mcp.pathMultiplier(MinMax::max());
|
|
EXPECT_EQ(mult_max, 5);
|
|
}
|
|
|
|
// MultiCyclePath priority with MinMax
|
|
TEST_F(SdcInitTest, MultiCyclePathPriorityMinMax) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::max(),
|
|
true, 5, true, "");
|
|
int p = mcp.priority(MinMax::max());
|
|
EXPECT_GT(p, 0);
|
|
}
|
|
|
|
// GroupPath name and isDefault
|
|
TEST_F(SdcInitTest, GroupPathName) {
|
|
GroupPath gp("test_group", true, nullptr, nullptr, nullptr, true, "");
|
|
EXPECT_EQ(gp.name(), "test_group");
|
|
EXPECT_TRUE(gp.isDefault());
|
|
}
|
|
|
|
// FilterPath basic
|
|
TEST_F(SdcInitTest, 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, FalsePathWithPriority) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true,
|
|
4500, "");
|
|
EXPECT_EQ(fp.priority(), 4500);
|
|
}
|
|
|
|
// LoopPath basic
|
|
TEST_F(SdcInitTest, 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, ExceptionPathHash) {
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::all(), true, "");
|
|
size_t h1 = fp1.hash();
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::all(), true, "");
|
|
size_t h2 = fp2.hash();
|
|
EXPECT_EQ(h1, h2);
|
|
}
|
|
|
|
// ExceptionPath clone tests
|
|
TEST_F(SdcInitTest, FalsePathCloneAndCheck) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, "");
|
|
ExceptionPath *clone = fp.clone(nullptr, nullptr, nullptr, true);
|
|
ASSERT_NE(clone, nullptr);
|
|
EXPECT_TRUE(clone->isFalse());
|
|
delete clone;
|
|
}
|
|
|
|
TEST_F(SdcInitTest, PathDelayCloneAndCheck) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, true, "");
|
|
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, MultiCyclePathCloneAndCheck) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 4, true, "");
|
|
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, GroupPathCloneAndCheck) {
|
|
GroupPath gp("grp", false, nullptr, nullptr, nullptr, true, "");
|
|
ExceptionPath *clone = gp.clone(nullptr, nullptr, nullptr, true);
|
|
ASSERT_NE(clone, nullptr);
|
|
EXPECT_TRUE(clone->isGroupPath());
|
|
EXPECT_EQ(clone->name(), "grp");
|
|
delete clone;
|
|
}
|
|
|
|
TEST_F(SdcInitTest, 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, ExceptionState) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, "");
|
|
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, ExceptionStateSetNextState) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, "");
|
|
ExceptionState state1(&fp, nullptr, 0);
|
|
ExceptionState state2(&fp, nullptr, 1);
|
|
state1.setNextState(&state2);
|
|
EXPECT_EQ(state1.nextState(), &state2);
|
|
}
|
|
|
|
// ExceptionState hash
|
|
TEST_F(SdcInitTest, ExceptionStateHash) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, "");
|
|
ExceptionState state(&fp, nullptr, 0);
|
|
size_t h = state.hash();
|
|
EXPECT_GE(h, 0);
|
|
|
|
}() ));
|
|
}
|
|
|
|
// exceptionStateLess
|
|
TEST_F(SdcInitTest, ExceptionStateLess) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::all(), true, "");
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::all(), true, "");
|
|
ExceptionState state1(&fp1, nullptr, 0);
|
|
ExceptionState state2(&fp2, nullptr, 0);
|
|
// Just exercise the comparator
|
|
ExceptionStateLess less;
|
|
less(&state1, &state2);
|
|
|
|
}() ));
|
|
}
|
|
|
|
// Sdc::setOperatingConditions(op_cond, MinMaxAll*)
|
|
TEST_F(SdcInitTest, SdcSetOperatingConditionsMinMaxAll) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
sdc->setOperatingConditions(nullptr, MinMaxAll::all());
|
|
|
|
}() ));
|
|
}
|
|
|
|
// Sdc::disable/removeDisable for LibertyPort
|
|
TEST_F(SdcInitTest, SdcDisableLibertyPort) {
|
|
LibertyLibrary *lib = sta_->readLiberty("test/nangate45/Nangate45_typ.lib",
|
|
sta_->cmdScene(),
|
|
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_->cmdSdc();
|
|
sdc->disable(port_a);
|
|
sdc->removeDisable(port_a);
|
|
}
|
|
|
|
// Sdc::disable/removeDisable for TimingArcSet
|
|
TEST_F(SdcInitTest, SdcDisableTimingArcSet) {
|
|
LibertyLibrary *lib = sta_->readLiberty("test/nangate45/Nangate45_typ.lib",
|
|
sta_->cmdScene(),
|
|
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_->cmdSdc();
|
|
sdc->disable(arc_sets[0]);
|
|
sdc->removeDisable(arc_sets[0]);
|
|
}
|
|
|
|
// Sdc clock querying via findClock
|
|
TEST_F(SdcInitTest, SdcFindClockNull) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->findClock("nonexistent_clk");
|
|
EXPECT_EQ(clk, nullptr);
|
|
}
|
|
|
|
// Sdc latch borrow limit on clock
|
|
TEST_F(SdcInitTest, SdcLatchBorrowLimitOnClock) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, "");
|
|
ASSERT_NE(clk, nullptr);
|
|
sdc->setLatchBorrowLimit(clk, 2.0f);
|
|
// Just exercise - borrow limit is set
|
|
}
|
|
|
|
// InterClockUncertainty more thorough
|
|
TEST_F(SdcInitTest, 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_->cmdSdc();
|
|
Clock *clk1 = sdc->makeClock("clk_icu1", nullptr, false, 10.0,
|
|
waveform1, "");
|
|
Clock *clk2 = sdc->makeClock("clk_icu2", nullptr, false, 6.0,
|
|
waveform2, "");
|
|
InterClockUncertainty icu(clk1, clk2);
|
|
EXPECT_TRUE(icu.empty());
|
|
EXPECT_EQ(icu.src(), clk1);
|
|
EXPECT_EQ(icu.target(), clk2);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, 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_->cmdSdc();
|
|
Clock *clk1 = sdc->makeClock("clk_icu3", nullptr, false, 10.0,
|
|
waveform1, "");
|
|
Clock *clk2 = sdc->makeClock("clk_icu4", nullptr, false, 6.0,
|
|
waveform2, "");
|
|
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, 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_->cmdSdc();
|
|
Clock *clk1 = sdc->makeClock("clk_icu5", nullptr, false, 10.0,
|
|
waveform1, "");
|
|
Clock *clk2 = sdc->makeClock("clk_icu6", nullptr, false, 6.0,
|
|
waveform2, "");
|
|
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, 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_->cmdSdc();
|
|
Clock *clk1 = sdc->makeClock("clk_icu7", nullptr, false, 10.0,
|
|
waveform1, "");
|
|
Clock *clk2 = sdc->makeClock("clk_icu8", nullptr, false, 6.0,
|
|
waveform2, "");
|
|
InterClockUncertainty icu(clk1, clk2);
|
|
const RiseFallMinMax *rfmm = icu.uncertainties(RiseFall::rise());
|
|
EXPECT_NE(rfmm, nullptr);
|
|
}
|
|
|
|
// CycleAccting exercises
|
|
TEST_F(SdcInitTest, CycleAcctingConstruct2) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->makeClock("clk_ca", nullptr, false, 10.0,
|
|
waveform, "");
|
|
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, CycleAcctingFindDefaultArrivalSrcDelays) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->makeClock("clk_ca2", nullptr, false, 10.0,
|
|
waveform, "");
|
|
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, DisabledPortsFromToOps) {
|
|
LibertyLibrary *lib = sta_->readLiberty("test/nangate45/Nangate45_typ.lib",
|
|
sta_->cmdScene(),
|
|
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, ClockSetCompare) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
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_->cmdSdc();
|
|
Clock *clk1 = sdc->makeClock("clk_csc1", nullptr, false, 10.0,
|
|
waveform1, "");
|
|
Clock *clk2 = sdc->makeClock("clk_csc2", nullptr, false, 6.0,
|
|
waveform2, "");
|
|
ClockSet set1;
|
|
set1.insert(clk1);
|
|
ClockSet set2;
|
|
set2.insert(clk2);
|
|
compare(&set1, &set2);
|
|
|
|
}() ));
|
|
}
|
|
|
|
// Sdc::clockUncertainty on null pin
|
|
TEST_F(SdcInitTest, SdcClockUncertaintyNullPin) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "");
|
|
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, 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, 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, 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, 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, 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, ExceptionPtHash) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
const Network *network = sta_->cmdNetwork();
|
|
ExceptionFrom *from = new ExceptionFrom(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::riseFall(),
|
|
true, network);
|
|
size_t h = from->hash();
|
|
EXPECT_GE(h, 0);
|
|
delete from;
|
|
|
|
}() ));
|
|
}
|
|
|
|
// ExceptionFrom::findHash (called during construction)
|
|
TEST_F(SdcInitTest, 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, CheckFromThrusToAllNull) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
// All nullptr should not throw EmptyExceptionPt
|
|
checkFromThrusTo(nullptr, nullptr, nullptr);
|
|
|
|
}() ));
|
|
}
|
|
|
|
// EmptyExceptionPt what
|
|
TEST_F(SdcInitTest, EmptyExceptionPtWhat2) {
|
|
EmptyExpceptionPt e;
|
|
const char *msg = e.what();
|
|
EXPECT_NE(msg, nullptr);
|
|
}
|
|
|
|
// ExceptionPathLess comparator
|
|
TEST_F(SdcInitTest, ExceptionPathLessComparator2) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
const Network *network = sta_->cmdNetwork();
|
|
ExceptionPathLess less(network);
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::all(), true, "");
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::all(), true, "");
|
|
// Should not crash
|
|
less(&fp1, &fp2);
|
|
|
|
}() ));
|
|
}
|
|
|
|
// Clock removeSlew
|
|
TEST_F(SdcInitTest, ClockRemoveSlew) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->makeClock("clk_rs", nullptr, false, 10.0,
|
|
waveform, "");
|
|
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, ClockSlewsAccessor) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->makeClock("clk_sa", nullptr, false, 10.0,
|
|
waveform, "");
|
|
ASSERT_NE(clk, nullptr);
|
|
clk->slews();
|
|
}
|
|
|
|
// Clock uncertainties
|
|
TEST_F(SdcInitTest, ClockUncertaintiesAccessor) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->makeClock("clk_ua", nullptr, false, 10.0,
|
|
waveform, "");
|
|
ASSERT_NE(clk, nullptr);
|
|
// A freshly created clock has no uncertainties set yet
|
|
ClockUncertainties *unc = clk->uncertainties();
|
|
EXPECT_EQ(unc, nullptr);
|
|
}
|
|
|
|
// Clock setUncertainty and removeUncertainty
|
|
TEST_F(SdcInitTest, ClockSetRemoveUncertainty) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->makeClock("clk_sru", nullptr, false, 10.0,
|
|
waveform, "");
|
|
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, ClockGeneratedProperties) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->makeClock("clk_gp", nullptr, false, 10.0,
|
|
waveform, "");
|
|
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, 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_->cmdSdc();
|
|
Clock *clkA = sdc->makeClock("alpha", nullptr, false, 10.0,
|
|
waveform1, "");
|
|
Clock *clkB = sdc->makeClock("beta", nullptr, false, 6.0,
|
|
waveform2, "");
|
|
ClockNameLess less;
|
|
EXPECT_TRUE(less(clkA, clkB));
|
|
EXPECT_FALSE(less(clkB, clkA));
|
|
}
|
|
|
|
// CycleAcctings
|
|
TEST_F(SdcInitTest, CycleAcctings) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
CycleAcctings acctings(sdc);
|
|
// Clear should not crash
|
|
acctings.clear();
|
|
|
|
}() ));
|
|
}
|
|
|
|
// Clock setPropagated / removePropagated
|
|
TEST_F(SdcInitTest, ClockPropagation2) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->makeClock("clk_prop", nullptr, false, 10.0,
|
|
waveform, "");
|
|
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, 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, 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, SdcAnalysisType) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, SdcMaxArea2) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
sdc->setMaxArea(500.0);
|
|
EXPECT_FLOAT_EQ(sdc->maxArea(), 500.0f);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Sdc setOperatingConditions
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, SdcSetOperatingConditions) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, SdcWireloadMode2) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, FalsePathMergeableSame) {
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::all(), true, "");
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::all(), true, "");
|
|
EXPECT_TRUE(fp1.mergeable(&fp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, FalsePathNotMergeableDiffMinMax) {
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::min(), true, "");
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::max(), true, "");
|
|
EXPECT_FALSE(fp1.mergeable(&fp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, FalsePathNotMergeableDiffType) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, "");
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
1.0e-9f, true, "");
|
|
EXPECT_FALSE(fp.mergeable(&pd));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: PathDelay min direction
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, PathDelayMinDirection) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::min(), false, false,
|
|
5.0e-9f, true, "");
|
|
EXPECT_TRUE(pd.matches(MinMax::min(), false));
|
|
EXPECT_FALSE(pd.matches(MinMax::max(), false));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, PathDelayTighterMin) {
|
|
PathDelay pd1(nullptr, nullptr, nullptr, MinMax::min(), false, false,
|
|
5.0e-9f, true, "");
|
|
PathDelay pd2(nullptr, nullptr, nullptr, MinMax::min(), false, false,
|
|
2.0e-9f, true, "");
|
|
// For min, larger delay is tighter
|
|
EXPECT_TRUE(pd1.tighterThan(&pd2));
|
|
EXPECT_FALSE(pd2.tighterThan(&pd1));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: ExceptionPath hash
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, PathDelayHash) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
5.0e-9f, true, "");
|
|
size_t h = pd.hash();
|
|
EXPECT_GE(h, 0u);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, MultiCyclePathHash) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, true, "");
|
|
size_t h = mcp.hash();
|
|
EXPECT_GE(h, 0u);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, GroupPathHash) {
|
|
GroupPath gp("grp", false, nullptr, nullptr, nullptr, true, "");
|
|
size_t h = gp.hash();
|
|
EXPECT_GE(h, 0u);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, FilterPathHash) {
|
|
FilterPath flp(nullptr, nullptr, nullptr, true);
|
|
size_t h = flp.hash();
|
|
EXPECT_GE(h, 0u);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, LoopPathHash) {
|
|
LoopPath lp(nullptr, true);
|
|
size_t h = lp.hash();
|
|
EXPECT_GE(h, 0u);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: ExceptionPath typeString
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, FalsePathTypeString2) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), true, "");
|
|
const char *ts = fp.typeString();
|
|
EXPECT_NE(ts, nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, PathDelayTypeString2) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(), false, false,
|
|
1.0e-9f, true, "");
|
|
const char *ts = pd.typeString();
|
|
EXPECT_NE(ts, nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, MultiCyclePathTypeString2) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 2, true, "");
|
|
const char *ts = mcp.typeString();
|
|
EXPECT_NE(ts, nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, GroupPathTypeString2) {
|
|
GroupPath gp("g", false, nullptr, nullptr, nullptr, true, "");
|
|
const char *ts = gp.typeString();
|
|
EXPECT_NE(ts, nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, FilterPathTypeString2) {
|
|
FilterPath flp(nullptr, nullptr, nullptr, true);
|
|
const char *ts = flp.typeString();
|
|
EXPECT_NE(ts, nullptr);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Clock operations
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, ClockEdgeTimeAccess) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("et_clk", nullptr, false, 10.0, waveform, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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_FALSE(rise_edge->name().empty());
|
|
EXPECT_FALSE(fall_edge->name().empty());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, ClockMakeClock) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, "");
|
|
EXPECT_NE(clk, nullptr);
|
|
EXPECT_EQ(clk->name(), "direct_clk");
|
|
}
|
|
|
|
TEST_F(SdcInitTest, ClockLeafPins) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("lp_clk", nullptr, false, 10.0, waveform, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->findClock("lp_clk");
|
|
const PinSet &pins = clk->leafPins();
|
|
EXPECT_TRUE(pins.empty());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Sdc exception operations
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, SdcMakeAndDeleteException) {
|
|
sta_->makeFalsePath(nullptr, nullptr, nullptr, MinMaxAll::all(), "", sta_->cmdSdc());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
EXPECT_FALSE(sdc->exceptions().empty());
|
|
sdc->deleteExceptions();
|
|
EXPECT_TRUE(sdc->exceptions().empty());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, SdcMultiCyclePathWithEndClk) {
|
|
sta_->makeMulticyclePath(nullptr, nullptr, nullptr,
|
|
MinMaxAll::max(),
|
|
true, 3, "", sta_->cmdSdc());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
EXPECT_FALSE(sdc->exceptions().empty());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, SdcMultiCyclePathWithStartClk) {
|
|
sta_->makeMulticyclePath(nullptr, nullptr, nullptr,
|
|
MinMaxAll::min(),
|
|
false, 2, "", sta_->cmdSdc());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
EXPECT_FALSE(sdc->exceptions().empty());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Sdc constraint accessors
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, SdcClockGatingCheckGlobal2) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
sdc->setClockGatingCheck(RiseFallBoth::rise(), SetupHold::min(), 0.3);
|
|
sdc->setClockGatingCheck(RiseFallBoth::fall(), SetupHold::max(), 0.7);
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, SdcClockGatingCheckGlobalRiseFall) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, SdcVoltageAccess) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, ExceptionFromRiseFall) {
|
|
ExceptionFrom from(nullptr, nullptr, nullptr,
|
|
RiseFallBoth::rise(), true,
|
|
sta_->cmdNetwork());
|
|
EXPECT_NE(from.transition(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdcInitTest, 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, ClockGroupsPhysicallyExclusive) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
FloatSeq *wave = new FloatSeq;
|
|
wave->push_back(0.0);
|
|
wave->push_back(5.0);
|
|
sta_->makeClock("pe_clk", nullptr, false, 10.0, wave, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->findClock("pe_clk");
|
|
|
|
ClockGroups *groups = sta_->makeClockGroups("pe_grp", false, true, false, false, "", sta_->cmdSdc());
|
|
ClockSet *clk_set = new ClockSet;
|
|
clk_set->insert(clk);
|
|
sta_->makeClockGroup(groups, clk_set, sta_->cmdSdc());
|
|
sta_->removeClockGroupsPhysicallyExclusive("pe_grp", sta_->cmdSdc());
|
|
|
|
}() ));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, ClockGroupsAsynchronous) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
FloatSeq *wave = new FloatSeq;
|
|
wave->push_back(0.0);
|
|
wave->push_back(5.0);
|
|
sta_->makeClock("async_clk", nullptr, false, 10.0, wave, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->findClock("async_clk");
|
|
|
|
ClockGroups *groups = sta_->makeClockGroups("async_grp", false, false, true, false, "", sta_->cmdSdc());
|
|
ClockSet *clk_set = new ClockSet;
|
|
clk_set->insert(clk);
|
|
sta_->makeClockGroup(groups, clk_set, sta_->cmdSdc());
|
|
sta_->removeClockGroupsAsynchronous("async_grp", sta_->cmdSdc());
|
|
|
|
}() ));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Sdc Latch borrow limits
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, SdcMinPulseWidth) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, LoopPathOverrides) {
|
|
LoopPath lp1(nullptr, true);
|
|
LoopPath lp2(nullptr, true);
|
|
EXPECT_TRUE(lp1.overrides(&lp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, LoopPathTighterThan) {
|
|
LoopPath lp1(nullptr, true);
|
|
LoopPath lp2(nullptr, true);
|
|
EXPECT_FALSE(lp1.tighterThan(&lp2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, GroupPathAsString) {
|
|
GroupPath gp("grp", false, nullptr, nullptr, nullptr, true, "");
|
|
std::string str = gp.to_string(sta_->cmdNetwork());
|
|
EXPECT_FALSE(str.empty());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, FilterPathAsString) {
|
|
FilterPath flp(nullptr, nullptr, nullptr, true);
|
|
std::string str = flp.to_string(sta_->cmdNetwork());
|
|
EXPECT_FALSE(str.empty());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, LoopPathAsString) {
|
|
LoopPath lp(nullptr, true);
|
|
std::string str = lp.to_string(sta_->cmdNetwork());
|
|
EXPECT_FALSE(str.empty());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: PatternMatch for clocks
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, 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, "", sta_->cmdMode());
|
|
|
|
FloatSeq *wave2 = new FloatSeq;
|
|
wave2->push_back(0.0);
|
|
wave2->push_back(2.5);
|
|
sta_->makeClock("sys_clk_b", nullptr, false, 5.0, wave2, "", sta_->cmdMode());
|
|
|
|
FloatSeq *wave3 = new FloatSeq;
|
|
wave3->push_back(0.0);
|
|
wave3->push_back(1.0);
|
|
sta_->makeClock("io_clk", nullptr, false, 2.0, wave3, "", sta_->cmdMode());
|
|
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, SdcPathDelaysWithoutToAfterAdd) {
|
|
// Add a path delay without a "to" endpoint
|
|
sta_->makePathDelay(nullptr, nullptr, nullptr,
|
|
MinMax::max(), false, false, 5.0e-9, "", sta_->cmdSdc());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
EXPECT_TRUE(sdc->pathDelaysWithoutTo());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Sdc multiple operations in sequence
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, SdcComplexSequence) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
|
|
// 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, "", sta_->cmdMode());
|
|
|
|
FloatSeq *w2 = new FloatSeq;
|
|
w2->push_back(0.0);
|
|
w2->push_back(2.5);
|
|
sta_->makeClock("seq_clk2", nullptr, false, 5.0, w2, "", sta_->cmdMode());
|
|
|
|
// 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(), "", sta_->cmdSdc());
|
|
sta_->makeMulticyclePath(nullptr, nullptr, nullptr,
|
|
MinMaxAll::all(), true, 4, "", sta_->cmdSdc());
|
|
sta_->makeGroupPath("test_grp", false, nullptr, nullptr, nullptr, "", sta_->cmdSdc());
|
|
|
|
EXPECT_FALSE(sdc->exceptions().empty());
|
|
EXPECT_TRUE(sta_->isPathGroupName("test_grp", sta_->cmdSdc()));
|
|
|
|
// Clear
|
|
sdc->clear();
|
|
EXPECT_TRUE(sdc->exceptions().empty());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: Clock properties after propagation
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->findClock("prop_cycle_clk");
|
|
|
|
EXPECT_TRUE(clk->isIdeal());
|
|
sta_->setPropagatedClock(clk, sta_->cmdMode());
|
|
EXPECT_TRUE(clk->isPropagated());
|
|
EXPECT_FALSE(clk->isIdeal());
|
|
sta_->removePropagatedClock(clk, sta_->cmdMode());
|
|
EXPECT_FALSE(clk->isPropagated());
|
|
EXPECT_TRUE(clk->isIdeal());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: InterClockUncertainty hash
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, InterClockUncertaintySetGet) {
|
|
FloatSeq *w1 = new FloatSeq;
|
|
w1->push_back(0.0);
|
|
w1->push_back(5.0);
|
|
sta_->makeClock("icu_clk1", nullptr, false, 10.0, w1, "", sta_->cmdMode());
|
|
FloatSeq *w2 = new FloatSeq;
|
|
w2->push_back(0.0);
|
|
w2->push_back(2.5);
|
|
sta_->makeClock("icu_clk2", nullptr, false, 5.0, w2, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, RiseFallMinMaxEqual) {
|
|
RiseFallMinMax rfmm1(5.0f);
|
|
RiseFallMinMax rfmm2(5.0f);
|
|
EXPECT_TRUE(rfmm1.equal(&rfmm2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, RiseFallMinMaxNotEqual) {
|
|
RiseFallMinMax rfmm1(5.0f);
|
|
RiseFallMinMax rfmm2(3.0f);
|
|
EXPECT_FALSE(rfmm1.equal(&rfmm2));
|
|
}
|
|
|
|
TEST_F(SdcInitTest, 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, 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, VariablesAllToggles) {
|
|
Variables vars;
|
|
vars.setCrprEnabled(false);
|
|
EXPECT_FALSE(vars.crprEnabled());
|
|
vars.setCrprEnabled(true);
|
|
EXPECT_TRUE(vars.crprEnabled());
|
|
|
|
vars.setPocvMode(PocvMode::normal);
|
|
EXPECT_TRUE(vars.pocvEnabled());
|
|
vars.setPocvMode(PocvMode::scalar);
|
|
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, 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, VariablesPropagateGatedClockEnable) {
|
|
Variables vars;
|
|
vars.setPropagateGatedClockEnable(true);
|
|
EXPECT_TRUE(vars.propagateGatedClockEnable());
|
|
vars.setPropagateGatedClockEnable(false);
|
|
EXPECT_FALSE(vars.propagateGatedClockEnable());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, VariablesPresetClrArcsEnabled) {
|
|
Variables vars;
|
|
vars.setPresetClrArcsEnabled(true);
|
|
EXPECT_TRUE(vars.presetClrArcsEnabled());
|
|
vars.setPresetClrArcsEnabled(false);
|
|
EXPECT_FALSE(vars.presetClrArcsEnabled());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, VariablesCondDefaultArcsEnabled) {
|
|
Variables vars;
|
|
vars.setCondDefaultArcsEnabled(false);
|
|
EXPECT_FALSE(vars.condDefaultArcsEnabled());
|
|
vars.setCondDefaultArcsEnabled(true);
|
|
EXPECT_TRUE(vars.condDefaultArcsEnabled());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, VariablesBidirectInstPathsEnabled) {
|
|
Variables vars;
|
|
vars.setBidirectInstPathsEnabled(true);
|
|
EXPECT_TRUE(vars.bidirectInstPathsEnabled());
|
|
vars.setBidirectInstPathsEnabled(false);
|
|
EXPECT_FALSE(vars.bidirectInstPathsEnabled());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, VariablesBidirectNetPathsEnabled) {
|
|
Variables vars;
|
|
vars.setBidirectInstPathsEnabled(true);
|
|
EXPECT_TRUE(vars.bidirectInstPathsEnabled());
|
|
vars.setBidirectInstPathsEnabled(false);
|
|
EXPECT_FALSE(vars.bidirectInstPathsEnabled());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, VariablesRecoveryRemovalChecksEnabled) {
|
|
Variables vars;
|
|
vars.setRecoveryRemovalChecksEnabled(false);
|
|
EXPECT_FALSE(vars.recoveryRemovalChecksEnabled());
|
|
vars.setRecoveryRemovalChecksEnabled(true);
|
|
EXPECT_TRUE(vars.recoveryRemovalChecksEnabled());
|
|
}
|
|
|
|
TEST_F(SdcInitTest, VariablesGatedClkChecksEnabled) {
|
|
Variables vars;
|
|
vars.setGatedClkChecksEnabled(false);
|
|
EXPECT_FALSE(vars.gatedClkChecksEnabled());
|
|
vars.setGatedClkChecksEnabled(true);
|
|
EXPECT_TRUE(vars.gatedClkChecksEnabled());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: ClockLatency
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, ClockLatencyConstruction) {
|
|
FloatSeq *waveform = new FloatSeq;
|
|
waveform->push_back(0.0);
|
|
waveform->push_back(5.0);
|
|
sta_->makeClock("lat_clk", nullptr, false, 10.0, waveform, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, InputDriveResistanceMinMaxEqual2) {
|
|
InputDrive drive;
|
|
drive.setDriveResistance(RiseFallBoth::rise(), MinMaxAll::all(), 100.0f);
|
|
EXPECT_TRUE(drive.driveResistanceMinMaxEqual(RiseFall::rise()));
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R6 tests: RiseFallMinMax more coverage
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
TEST_F(SdcInitTest, 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, 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, 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, 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, DeratingFactorsDefault) {
|
|
DeratingFactors df;
|
|
EXPECT_FALSE(df.hasValue());
|
|
}
|
|
|
|
// DeratingFactors set and get
|
|
TEST_F(SdcInitTest, DeratingFactorsSetGet2) {
|
|
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, DeratingFactorsClear2) {
|
|
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, DeratingFactorsIsOneValue2) {
|
|
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, DeratingFactorsIsOneValueClkData2) {
|
|
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, 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, 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, DeratingFactorsGlobalClear2) {
|
|
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, DeratingFactorsGlobalFactorsAccessor) {
|
|
DeratingFactorsGlobal dfg;
|
|
DeratingFactors *df = dfg.factors(TimingDerateType::cell_check);
|
|
EXPECT_NE(df, nullptr);
|
|
}
|
|
|
|
// DeratingFactorsGlobal with TimingDerateCellType
|
|
TEST_F(SdcInitTest, 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, 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, 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, DeratingFactorsCellClear2) {
|
|
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, DeratingFactorsCellFactorsAccessor) {
|
|
DeratingFactorsCell dfc;
|
|
DeratingFactors *df = dfc.factors(TimingDerateCellType::cell_delay);
|
|
EXPECT_NE(df, nullptr);
|
|
}
|
|
|
|
// DeratingFactorsCell isOneValue
|
|
TEST_F(SdcInitTest, DeratingFactorsCellIsOneValue2) {
|
|
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, DeratingFactorsNetDefault) {
|
|
DeratingFactorsNet dfn;
|
|
EXPECT_FALSE(dfn.hasValue());
|
|
}
|
|
|
|
// DeratingFactorsNet set and get
|
|
TEST_F(SdcInitTest, 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, ClockLatencyConstruct2) {
|
|
ClockLatency lat(nullptr, nullptr);
|
|
EXPECT_EQ(lat.clock(), nullptr);
|
|
EXPECT_EQ(lat.pin(), nullptr);
|
|
}
|
|
|
|
// ClockLatency set and get
|
|
TEST_F(SdcInitTest, 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, 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, ClockInsertionConstruct2) {
|
|
ClockInsertion ins(nullptr, nullptr);
|
|
EXPECT_EQ(ins.clock(), nullptr);
|
|
EXPECT_EQ(ins.pin(), nullptr);
|
|
}
|
|
|
|
// ClockInsertion set and get
|
|
TEST_F(SdcInitTest, 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, 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, ClockGatingCheckConstruct) {
|
|
ClockGatingCheck cgc;
|
|
RiseFallMinMax *margins = cgc.margins();
|
|
EXPECT_NE(margins, nullptr);
|
|
}
|
|
|
|
// ClockGatingCheck active value
|
|
TEST_F(SdcInitTest, 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, InputDriveConstruct) {
|
|
InputDrive drive;
|
|
float res;
|
|
bool exists;
|
|
drive.driveResistance(RiseFall::rise(), MinMax::max(), res, exists);
|
|
EXPECT_FALSE(exists);
|
|
}
|
|
|
|
// InputDrive set slew
|
|
TEST_F(SdcInitTest, InputDriveSetSlew2) {
|
|
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, InputDriveSetResistance2) {
|
|
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, 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, 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, InputDriveNoDriveCell) {
|
|
InputDrive drive;
|
|
EXPECT_FALSE(drive.hasDriveCell(RiseFall::rise(), MinMax::max()));
|
|
}
|
|
|
|
// InputDrive slews accessor
|
|
TEST_F(SdcInitTest, 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, 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, FalsePathType) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, "");
|
|
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, FalsePathPriority) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, "");
|
|
EXPECT_EQ(fp.typePriority(), ExceptionPath::falsePathPriority());
|
|
}
|
|
|
|
// PathDelay creation and type
|
|
TEST_F(SdcInitTest, PathDelayType) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, false, "");
|
|
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, PathDelayIgnoreClkLatency) {
|
|
PathDelay pd1(nullptr, nullptr, nullptr, MinMax::max(),
|
|
true, false, 3.0f, false, "");
|
|
EXPECT_TRUE(pd1.ignoreClkLatency());
|
|
PathDelay pd2(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 3.0f, false, "");
|
|
EXPECT_FALSE(pd2.ignoreClkLatency());
|
|
}
|
|
|
|
// PathDelay breakPath
|
|
TEST_F(SdcInitTest, PathDelayBreakPath) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, true, 3.0f, false, "");
|
|
EXPECT_TRUE(pd.breakPath());
|
|
}
|
|
|
|
// PathDelay tighterThan
|
|
TEST_F(SdcInitTest, PathDelayTighterThanMin) {
|
|
PathDelay pd1(nullptr, nullptr, nullptr, MinMax::min(),
|
|
false, false, 3.0f, false, "");
|
|
PathDelay pd2(nullptr, nullptr, nullptr, MinMax::min(),
|
|
false, false, 5.0f, false, "");
|
|
// For min, larger delay is tighter
|
|
EXPECT_TRUE(pd2.tighterThan(&pd1));
|
|
}
|
|
|
|
// PathDelay tighterThan max
|
|
TEST_F(SdcInitTest, PathDelayTighterThanMax) {
|
|
PathDelay pd1(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 3.0f, false, "");
|
|
PathDelay pd2(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, false, "");
|
|
// For max, smaller delay is tighter
|
|
EXPECT_TRUE(pd1.tighterThan(&pd2));
|
|
}
|
|
|
|
// MultiCyclePath creation and type
|
|
TEST_F(SdcInitTest, MultiCyclePathType) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, false, "");
|
|
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, MultiCyclePathStartClk) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
false, 2, false, "");
|
|
EXPECT_FALSE(mcp.useEndClk());
|
|
EXPECT_EQ(mcp.pathMultiplier(), 2);
|
|
}
|
|
|
|
// MultiCyclePath tighterThan
|
|
TEST_F(SdcInitTest, MultiCyclePathTighterThan2) {
|
|
MultiCyclePath mcp1(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 2, false, "");
|
|
MultiCyclePath mcp2(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 4, false, "");
|
|
// 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, FilterPathType) {
|
|
FilterPath fp(nullptr, nullptr, nullptr, false);
|
|
EXPECT_TRUE(fp.isFilter());
|
|
EXPECT_EQ(fp.type(), ExceptionPathType::filter);
|
|
}
|
|
|
|
// GroupPath creation and type
|
|
TEST_F(SdcInitTest, GroupPathType) {
|
|
GroupPath gp("test_group", false, nullptr, nullptr, nullptr, false, "");
|
|
EXPECT_TRUE(gp.isGroupPath());
|
|
EXPECT_EQ(gp.type(), ExceptionPathType::group_path);
|
|
EXPECT_EQ(gp.name(), "test_group");
|
|
EXPECT_FALSE(gp.isDefault());
|
|
}
|
|
|
|
// GroupPath default
|
|
TEST_F(SdcInitTest, GroupPathDefault) {
|
|
GroupPath gp("default_group", true, nullptr, nullptr, nullptr, false, "");
|
|
EXPECT_TRUE(gp.isDefault());
|
|
}
|
|
|
|
// LoopPath creation
|
|
TEST_F(SdcInitTest, LoopPathType) {
|
|
LoopPath lp(nullptr, false);
|
|
EXPECT_TRUE(lp.isFalse());
|
|
EXPECT_TRUE(lp.isLoop());
|
|
EXPECT_EQ(lp.type(), ExceptionPathType::loop);
|
|
}
|
|
|
|
// ExceptionPath minMax
|
|
TEST_F(SdcInitTest, ExceptionPathMinMax) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::min(), false, "");
|
|
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, ExceptionPathMatchesAll) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, "");
|
|
EXPECT_TRUE(fp.matches(MinMax::min(), true));
|
|
EXPECT_TRUE(fp.matches(MinMax::max(), true));
|
|
}
|
|
|
|
// FalsePath hash
|
|
TEST_F(SdcInitTest, FalsePathHash) {
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::all(), false, "");
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::all(), false, "");
|
|
// Same structure should have same hash
|
|
EXPECT_EQ(fp1.hash(), fp2.hash());
|
|
}
|
|
|
|
// FalsePath overrides
|
|
TEST_F(SdcInitTest, FalsePathOverrides2) {
|
|
FalsePath fp1(nullptr, nullptr, nullptr, MinMaxAll::all(), false, "");
|
|
FalsePath fp2(nullptr, nullptr, nullptr, MinMaxAll::all(), false, "");
|
|
EXPECT_TRUE(fp1.overrides(&fp2));
|
|
}
|
|
|
|
// PathDelay hash
|
|
TEST_F(SdcInitTest, PathDelayHashR8) {
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, false, "");
|
|
size_t h = pd.hash();
|
|
EXPECT_GT(h, 0u);
|
|
}
|
|
|
|
// FalsePath not mergeable with PathDelay
|
|
TEST_F(SdcInitTest, FalsePathNotMergeablePathDelay) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, "");
|
|
PathDelay pd(nullptr, nullptr, nullptr, MinMax::max(),
|
|
false, false, 5.0f, false, "");
|
|
EXPECT_FALSE(fp.mergeable(&pd));
|
|
}
|
|
|
|
// GroupPath tighterThan
|
|
TEST_F(SdcInitTest, GroupPathTighterThan2) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
GroupPath gp1("g1", false, nullptr, nullptr, nullptr, false, "");
|
|
GroupPath gp2("g2", false, nullptr, nullptr, nullptr, false, "");
|
|
// Group paths have no value to compare
|
|
gp1.tighterThan(&gp2);
|
|
}() ));
|
|
}
|
|
|
|
// FilterPath tighterThan
|
|
TEST_F(SdcInitTest, FilterPathTighterThan2) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
FilterPath fp1(nullptr, nullptr, nullptr, false);
|
|
FilterPath fp2(nullptr, nullptr, nullptr, false);
|
|
fp1.tighterThan(&fp2);
|
|
}() ));
|
|
}
|
|
|
|
// ExceptionPath id
|
|
TEST_F(SdcInitTest, ExceptionPathId) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, "");
|
|
fp.setId(42);
|
|
EXPECT_EQ(fp.id(), 42u);
|
|
}
|
|
|
|
// ExceptionPath setPriority
|
|
TEST_F(SdcInitTest, ExceptionPathSetPriority) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, "");
|
|
fp.setPriority(999);
|
|
EXPECT_EQ(fp.priority(), 999);
|
|
}
|
|
|
|
// ExceptionPath useEndClk default
|
|
TEST_F(SdcInitTest, ExceptionPathUseEndClkDefault) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, "");
|
|
EXPECT_FALSE(fp.useEndClk());
|
|
}
|
|
|
|
// ExceptionPath pathMultiplier default
|
|
TEST_F(SdcInitTest, ExceptionPathPathMultiplierDefault) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, "");
|
|
EXPECT_EQ(fp.pathMultiplier(), 0);
|
|
}
|
|
|
|
// ExceptionPath delay default
|
|
TEST_F(SdcInitTest, ExceptionPathDelayDefault) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, "");
|
|
EXPECT_FLOAT_EQ(fp.delay(), 0.0f);
|
|
}
|
|
|
|
// ExceptionPath name default
|
|
TEST_F(SdcInitTest, ExceptionPathNameDefault) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, "");
|
|
EXPECT_EQ(fp.name(), "");
|
|
}
|
|
|
|
// ExceptionPath isDefault
|
|
TEST_F(SdcInitTest, ExceptionPathIsDefault) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, "");
|
|
EXPECT_FALSE(fp.isDefault());
|
|
}
|
|
|
|
// ExceptionPath ignoreClkLatency default
|
|
TEST_F(SdcInitTest, ExceptionPathIgnoreClkLatencyDefault) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, "");
|
|
EXPECT_FALSE(fp.ignoreClkLatency());
|
|
}
|
|
|
|
// ExceptionPath breakPath default
|
|
TEST_F(SdcInitTest, ExceptionPathBreakPathDefault) {
|
|
FalsePath fp(nullptr, nullptr, nullptr, MinMaxAll::all(), false, "");
|
|
EXPECT_FALSE(fp.breakPath());
|
|
}
|
|
|
|
// Clock slew set and get
|
|
TEST_F(SdcInitTest, ClockSlewSetGet2) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_slew_clk", nullptr, false, 10.0, wf, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, ClockRemoveSlew2) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_rslew_clk", nullptr, false, 10.0, wf, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, ClockSlewsAccessor2) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_slews_clk", nullptr, false, 10.0, wf, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->findClock("r8_pera_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
EXPECT_FLOAT_EQ(clk->period(), 25.0f);
|
|
}
|
|
|
|
// Clock isVirtual
|
|
TEST_F(SdcInitTest, ClockIsVirtual2) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_virt_clk", nullptr, false, 10.0, wf, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->findClock("r8_ideal_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
EXPECT_TRUE(clk->isIdeal());
|
|
}
|
|
|
|
// Clock edge
|
|
TEST_F(SdcInitTest, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, ClockEdgeProperties2) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_edgep_clk", nullptr, false, 10.0, wf, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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_FALSE(rise->name().empty());
|
|
}
|
|
|
|
// ClockEdge opposite
|
|
TEST_F(SdcInitTest, ClockEdgeOpposite2) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_opp_clk", nullptr, false, 10.0, wf, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, ClockEdgePulseWidth2) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_pw_clk", nullptr, false, 10.0, wf, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, ClockUncertainty2) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_unc_clk", nullptr, false, 10.0, wf, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->findClock("r8_gen_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
EXPECT_FALSE(clk->isGenerated());
|
|
}
|
|
|
|
// Clock addToPins
|
|
TEST_F(SdcInitTest, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, ClockIndex2) {
|
|
FloatSeq *wf1 = new FloatSeq;
|
|
wf1->push_back(0.0);
|
|
wf1->push_back(5.0);
|
|
sta_->makeClock("r8_idx1_clk", nullptr, false, 10.0, wf1, "", sta_->cmdMode());
|
|
FloatSeq *wf2 = new FloatSeq;
|
|
wf2->push_back(0.0);
|
|
wf2->push_back(10.0);
|
|
sta_->makeClock("r8_idx2_clk", nullptr, false, 20.0, wf2, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
FloatSeq *wf2 = new FloatSeq;
|
|
wf2->push_back(0.0);
|
|
wf2->push_back(5.0);
|
|
sta_->makeClock("r8_icut_clk", nullptr, false, 10.0, wf2, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, InterClockUncertaintySetGet2) {
|
|
FloatSeq *wf1 = new FloatSeq;
|
|
wf1->push_back(0.0);
|
|
wf1->push_back(5.0);
|
|
sta_->makeClock("r8_icu2s_clk", nullptr, false, 10.0, wf1, "", sta_->cmdMode());
|
|
FloatSeq *wf2 = new FloatSeq;
|
|
wf2->push_back(0.0);
|
|
wf2->push_back(5.0);
|
|
sta_->makeClock("r8_icu2t_clk", nullptr, false, 10.0, wf2, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, InterClockUncertaintyRemove2) {
|
|
FloatSeq *wf1 = new FloatSeq;
|
|
wf1->push_back(0.0);
|
|
wf1->push_back(5.0);
|
|
sta_->makeClock("r8_icu3s_clk", nullptr, false, 10.0, wf1, "", sta_->cmdMode());
|
|
FloatSeq *wf2 = new FloatSeq;
|
|
wf2->push_back(0.0);
|
|
wf2->push_back(5.0);
|
|
sta_->makeClock("r8_icu3t_clk", nullptr, false, 10.0, wf2, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
FloatSeq *wf2 = new FloatSeq;
|
|
wf2->push_back(0.0);
|
|
wf2->push_back(5.0);
|
|
sta_->makeClock("r8_icu4t_clk", nullptr, false, 10.0, wf2, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, SdcSetTimingDerateGlobal2) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, SdcSetMaxAreaR8) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
sdc->setMaxArea(500.0f);
|
|
EXPECT_FLOAT_EQ(sdc->maxArea(), 500.0f);
|
|
}
|
|
|
|
// Sdc::setAnalysisType
|
|
TEST_F(SdcInitTest, SdcSetAnalysisTypeR8) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, SdcSetWireloadModeR8) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
sdc->setWireloadMode(WireloadMode::enclosed);
|
|
// Just verify no crash
|
|
sdc->setWireloadMode(WireloadMode::segmented);
|
|
sdc->setWireloadMode(WireloadMode::top);
|
|
|
|
}() ));
|
|
}
|
|
|
|
// Sdc::setPropagatedClock / removePropagatedClock
|
|
TEST_F(SdcInitTest, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, SdcSetClockSlew2) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_sslew_clk", nullptr, false, 10.0, wf, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, SdcSetClockLatency2) {
|
|
FloatSeq *wf = new FloatSeq;
|
|
wf->push_back(0.0);
|
|
wf->push_back(5.0);
|
|
sta_->makeClock("r8_slat_clk", nullptr, false, 10.0, wf, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, SdcClockLatencies) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
const ClockLatencies *lats = sdc->clockLatencies();
|
|
EXPECT_NE(lats, nullptr);
|
|
}
|
|
|
|
// Sdc::clockLatency (float overload)
|
|
TEST_F(SdcInitTest, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, SdcSetMinPulseWidthR8) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
sdc->setMinPulseWidth(RiseFallBoth::riseFall(), 0.5f);
|
|
// Just verify no crash
|
|
|
|
}() ));
|
|
}
|
|
|
|
// Sdc::setLatchBorrowLimit
|
|
TEST_F(SdcInitTest, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *clk = sdc->findClock("r8_rem_clk");
|
|
ASSERT_NE(clk, nullptr);
|
|
sdc->removeClock(clk);
|
|
// Clock should be removed
|
|
}
|
|
|
|
// Sdc::defaultArrivalClock
|
|
TEST_F(SdcInitTest, SdcDefaultArrivalClock2) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
Clock *def_clk = sdc->defaultArrivalClock();
|
|
EXPECT_NE(def_clk, nullptr);
|
|
}
|
|
|
|
// Sdc::defaultArrivalClockEdge
|
|
TEST_F(SdcInitTest, SdcDefaultArrivalClockEdge2) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
ClockEdge *edge = sdc->defaultArrivalClockEdge();
|
|
EXPECT_NE(edge, nullptr);
|
|
}
|
|
|
|
// Sdc::haveClkSlewLimits
|
|
TEST_F(SdcInitTest, SdcHaveClkSlewLimits2) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
bool have = sdc->haveClkSlewLimits();
|
|
// Initially no limits
|
|
EXPECT_FALSE(have);
|
|
}
|
|
|
|
// Sdc::invalidateGeneratedClks
|
|
TEST_F(SdcInitTest, SdcInvalidateGeneratedClks2) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
sdc->invalidateGeneratedClks();
|
|
// Just verify no crash
|
|
|
|
}() ));
|
|
}
|
|
|
|
// Variables toggles - more variables
|
|
TEST_F(SdcInitTest, VariablesDynamicLoopBreaking) {
|
|
sta_->setDynamicLoopBreaking(true);
|
|
EXPECT_TRUE(sta_->dynamicLoopBreaking());
|
|
sta_->setDynamicLoopBreaking(false);
|
|
EXPECT_FALSE(sta_->dynamicLoopBreaking());
|
|
}
|
|
|
|
// Variables propagateAllClocks
|
|
TEST_F(SdcInitTest, VariablesPropagateAllClocks) {
|
|
sta_->setPropagateAllClocks(true);
|
|
EXPECT_TRUE(sta_->propagateAllClocks());
|
|
sta_->setPropagateAllClocks(false);
|
|
EXPECT_FALSE(sta_->propagateAllClocks());
|
|
}
|
|
|
|
// Variables clkThruTristateEnabled
|
|
TEST_F(SdcInitTest, VariablesClkThruTristateEnabled) {
|
|
sta_->setClkThruTristateEnabled(true);
|
|
EXPECT_TRUE(sta_->clkThruTristateEnabled());
|
|
sta_->setClkThruTristateEnabled(false);
|
|
EXPECT_FALSE(sta_->clkThruTristateEnabled());
|
|
}
|
|
|
|
// Variables useDefaultArrivalClock
|
|
TEST_F(SdcInitTest, VariablesUseDefaultArrivalClock) {
|
|
sta_->setUseDefaultArrivalClock(true);
|
|
EXPECT_TRUE(sta_->useDefaultArrivalClock());
|
|
sta_->setUseDefaultArrivalClock(false);
|
|
EXPECT_FALSE(sta_->useDefaultArrivalClock());
|
|
}
|
|
|
|
// Variables pocvMode
|
|
TEST_F(SdcInitTest, VariablesPocvEnabled) {
|
|
sta_->setPocvMode(PocvMode::normal);
|
|
EXPECT_EQ(sta_->pocvMode(), PocvMode::normal);
|
|
sta_->setPocvMode(PocvMode::scalar);
|
|
EXPECT_EQ(sta_->pocvMode(), PocvMode::scalar);
|
|
}
|
|
|
|
// Variables crprEnabled
|
|
TEST_F(SdcInitTest, VariablesCrprEnabled) {
|
|
sta_->setCrprEnabled(true);
|
|
EXPECT_TRUE(sta_->crprEnabled());
|
|
sta_->setCrprEnabled(false);
|
|
EXPECT_FALSE(sta_->crprEnabled());
|
|
}
|
|
|
|
// RiseFallMinMax clear
|
|
TEST_F(SdcInitTest, RiseFallMinMaxClear) {
|
|
RiseFallMinMax rfmm(1.0f);
|
|
EXPECT_TRUE(rfmm.hasValue());
|
|
rfmm.clear();
|
|
EXPECT_FALSE(rfmm.hasValue());
|
|
}
|
|
|
|
// RiseFallMinMax setValue individual
|
|
TEST_F(SdcInitTest, 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, 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, PortExtCapConstruct) {
|
|
PortExtCap pec;
|
|
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, PortExtCapSetPinCap) {
|
|
PortExtCap pec;
|
|
pec.setPinCap(nullptr, 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, PortExtCapSetWireCap) {
|
|
PortExtCap pec;
|
|
pec.setWireCap(nullptr, 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, PortExtCapSetFanout) {
|
|
PortExtCap pec;
|
|
pec.setFanout(nullptr, 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, PortExtCapAccessors) {
|
|
PortExtCap pec;
|
|
pec.setPinCap(nullptr, 1.0f, RiseFall::rise(), MinMax::max());
|
|
const RiseFallMinMax *pin_cap = pec.pinCap();
|
|
EXPECT_NE(pin_cap, nullptr);
|
|
const RiseFallMinMax *wire_cap = pec.wireCap();
|
|
EXPECT_NE(wire_cap, nullptr);
|
|
const FanoutValues *fanout = pec.fanout();
|
|
EXPECT_NE(fanout, nullptr);
|
|
}
|
|
|
|
// clkCmp
|
|
TEST_F(SdcInitTest, 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, "", sta_->cmdMode());
|
|
FloatSeq *wf2 = new FloatSeq;
|
|
wf2->push_back(0.0);
|
|
wf2->push_back(5.0);
|
|
sta_->makeClock("r8_cmpb_clk", nullptr, false, 10.0, wf2, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
FloatSeq *wf2 = new FloatSeq;
|
|
wf2->push_back(0.0);
|
|
wf2->push_back(5.0);
|
|
sta_->makeClock("r8_zzz_clk", nullptr, false, 10.0, wf2, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, SdcClockGatingCheckGlobalR8) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
sdc->setClockGatingCheck(RiseFallBoth::riseFall(),
|
|
SetupHold::max(), 0.5f);
|
|
// Just verify no crash
|
|
|
|
}() ));
|
|
}
|
|
|
|
// Sdc::setClockGatingCheck on clock
|
|
TEST_F(SdcInitTest, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, "", sta_->cmdMode());
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
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, 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, 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, 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, MultiCyclePathMatchesMinMax) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, false, "");
|
|
EXPECT_TRUE(mcp.matches(MinMax::min(), false));
|
|
EXPECT_TRUE(mcp.matches(MinMax::max(), false));
|
|
}
|
|
|
|
// MultiCyclePath pathMultiplier with min_max
|
|
TEST_F(SdcInitTest, MultiCyclePathMultiplierWithMinMax2) {
|
|
MultiCyclePath mcp(nullptr, nullptr, nullptr, MinMaxAll::all(),
|
|
true, 3, false, "");
|
|
int mult_max = mcp.pathMultiplier(MinMax::max());
|
|
EXPECT_EQ(mult_max, 3);
|
|
}
|
|
|
|
// ExceptionPath fromThruToPriority
|
|
TEST_F(SdcInitTest, ExceptionPathFromThruToPriority) {
|
|
int prio = ExceptionPath::fromThruToPriority(nullptr, nullptr, nullptr);
|
|
EXPECT_EQ(prio, 0);
|
|
}
|
|
|
|
// Sdc::disabledCellPorts
|
|
TEST_F(SdcInitTest, SdcDisabledCellPorts2) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
const DisabledCellPortsMap *dcm = sdc->disabledCellPorts();
|
|
EXPECT_NE(dcm, nullptr);
|
|
}
|
|
|
|
// Sdc::disabledInstancePorts
|
|
TEST_F(SdcInitTest, SdcDisabledInstancePorts) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
const DisabledInstancePortsMap *dim = sdc->disabledInstancePorts();
|
|
EXPECT_NE(dim, nullptr);
|
|
}
|
|
|
|
// Sdc::disabledPins
|
|
TEST_F(SdcInitTest, SdcDisabledPins) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
const PinSet *pins = sdc->disabledPins();
|
|
EXPECT_NE(pins, nullptr);
|
|
}
|
|
|
|
// Sdc::disabledPorts
|
|
TEST_F(SdcInitTest, SdcDisabledPorts) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
const PortSet *ports = sdc->disabledPorts();
|
|
EXPECT_NE(ports, nullptr);
|
|
}
|
|
|
|
// Sdc::disabledLibPorts
|
|
TEST_F(SdcInitTest, SdcDisabledLibPorts) {
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
const LibertyPortSet *lib_ports = sdc->disabledLibPorts();
|
|
EXPECT_NE(lib_ports, nullptr);
|
|
}
|
|
|
|
// Sdc::netResistances
|
|
TEST_F(SdcInitTest, SdcNetResistances) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
const NetResistanceMap &nr = sdc->netResistances();
|
|
EXPECT_GE(nr.size(), 0u);
|
|
|
|
}() ));
|
|
}
|
|
|
|
// Sdc::clockInsertions
|
|
TEST_F(SdcInitTest, SdcClockInsertions) {
|
|
ASSERT_NO_THROW(( [&](){
|
|
Sdc *sdc = sta_->cmdSdc();
|
|
const ClockInsertions &insertions = sdc->clockInsertions();
|
|
EXPECT_GE(insertions.size(), 0u);
|
|
|
|
}() ));
|
|
}
|
|
|
|
} // namespace sta
|