1700 lines
57 KiB
C++
1700 lines
57 KiB
C++
#include <gtest/gtest.h>
|
|
#include <set>
|
|
#include "MinMax.hh"
|
|
#include "Transition.hh"
|
|
#include "StringUtil.hh"
|
|
|
|
// SDF module smoke tests - verifying types used by SDF reader/writer
|
|
namespace sta {
|
|
|
|
class SdfSmokeTest : public ::testing::Test {};
|
|
|
|
// SDF uses RiseFall for transitions
|
|
TEST_F(SdfSmokeTest, SdfTripleIndices) {
|
|
// SDF triples are indexed by rise/fall
|
|
EXPECT_EQ(RiseFall::riseIndex(), 0);
|
|
EXPECT_EQ(RiseFall::fallIndex(), 1);
|
|
}
|
|
|
|
// SDF uses MinMax for min/typ/max
|
|
TEST_F(SdfSmokeTest, MinMaxForSdf) {
|
|
EXPECT_NE(MinMax::min(), nullptr);
|
|
EXPECT_NE(MinMax::max(), nullptr);
|
|
}
|
|
|
|
// SDF transitions
|
|
TEST_F(SdfSmokeTest, SdfTransitions) {
|
|
// SDF has 12 transition types + rise_fall
|
|
const Transition *t01 = Transition::rise();
|
|
const Transition *t10 = Transition::fall();
|
|
const Transition *t0z = Transition::tr0Z();
|
|
const Transition *tz1 = Transition::trZ1();
|
|
EXPECT_NE(t01, nullptr);
|
|
EXPECT_NE(t10, nullptr);
|
|
EXPECT_NE(t0z, nullptr);
|
|
EXPECT_NE(tz1, nullptr);
|
|
}
|
|
|
|
// Test string comparison used in SDF parsing
|
|
TEST_F(SdfSmokeTest, StringComparison) {
|
|
EXPECT_TRUE(stringEq("IOPATH", "IOPATH"));
|
|
EXPECT_FALSE(stringEq("IOPATH", "iopath"));
|
|
EXPECT_TRUE(stringEqual("IOPATH", "iopath")); // case insensitive
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// Additional SDF-relevant type tests
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// Test all 12 SDF transitions
|
|
TEST_F(SdfSmokeTest, AllSdfTransitions) {
|
|
// 01 (rise)
|
|
EXPECT_NE(Transition::rise(), nullptr);
|
|
EXPECT_NE(Transition::rise()->asRiseFall(), nullptr);
|
|
EXPECT_EQ(Transition::rise()->asRiseFall(), RiseFall::rise());
|
|
|
|
// 10 (fall)
|
|
EXPECT_NE(Transition::fall(), nullptr);
|
|
EXPECT_NE(Transition::fall()->asRiseFall(), nullptr);
|
|
EXPECT_EQ(Transition::fall()->asRiseFall(), RiseFall::fall());
|
|
|
|
// 0Z
|
|
EXPECT_NE(Transition::tr0Z(), nullptr);
|
|
EXPECT_NE(Transition::tr0Z()->asInitFinalString(), nullptr);
|
|
|
|
// Z1
|
|
EXPECT_NE(Transition::trZ1(), nullptr);
|
|
|
|
// 1Z
|
|
EXPECT_NE(Transition::tr1Z(), nullptr);
|
|
|
|
// Z0
|
|
EXPECT_NE(Transition::trZ0(), nullptr);
|
|
|
|
// 0X
|
|
EXPECT_NE(Transition::tr0X(), nullptr);
|
|
|
|
// X1
|
|
EXPECT_NE(Transition::trX1(), nullptr);
|
|
|
|
// 1X
|
|
EXPECT_NE(Transition::tr1X(), nullptr);
|
|
|
|
// X0
|
|
EXPECT_NE(Transition::trX0(), nullptr);
|
|
|
|
// XZ
|
|
EXPECT_NE(Transition::trXZ(), nullptr);
|
|
|
|
// ZX
|
|
EXPECT_NE(Transition::trZX(), nullptr);
|
|
}
|
|
|
|
// Test transition index values
|
|
TEST_F(SdfSmokeTest, TransitionIndices) {
|
|
EXPECT_EQ(Transition::rise()->sdfTripleIndex(), RiseFall::riseIndex());
|
|
EXPECT_EQ(Transition::fall()->sdfTripleIndex(), RiseFall::fallIndex());
|
|
EXPECT_GE(Transition::maxIndex(), 0);
|
|
}
|
|
|
|
// Test transition name strings
|
|
TEST_F(SdfSmokeTest, TransitionNames) {
|
|
EXPECT_EQ(Transition::rise()->to_string(), "^");
|
|
EXPECT_EQ(Transition::fall()->to_string(), "v");
|
|
EXPECT_FALSE(Transition::tr0Z()->to_string().empty());
|
|
EXPECT_FALSE(Transition::trZ1()->to_string().empty());
|
|
}
|
|
|
|
// Test transition find
|
|
TEST_F(SdfSmokeTest, TransitionFind) {
|
|
const Transition *rise = Transition::find("^");
|
|
EXPECT_EQ(rise, Transition::rise());
|
|
|
|
const Transition *fall = Transition::find("v");
|
|
EXPECT_EQ(fall, Transition::fall());
|
|
}
|
|
|
|
// Test transition matches
|
|
TEST_F(SdfSmokeTest, TransitionMatches) {
|
|
EXPECT_TRUE(Transition::rise()->matches(Transition::rise()));
|
|
EXPECT_FALSE(Transition::rise()->matches(Transition::fall()));
|
|
|
|
// riseFall matches both
|
|
EXPECT_TRUE(Transition::riseFall()->matches(Transition::rise()));
|
|
EXPECT_TRUE(Transition::riseFall()->matches(Transition::fall()));
|
|
}
|
|
|
|
// Test RiseFall find
|
|
TEST_F(SdfSmokeTest, RiseFallFind) {
|
|
const RiseFall *rise = RiseFall::find("rise");
|
|
EXPECT_EQ(rise, RiseFall::rise());
|
|
|
|
const RiseFall *fall = RiseFall::find("fall");
|
|
EXPECT_EQ(fall, RiseFall::fall());
|
|
}
|
|
|
|
// Test RiseFall names
|
|
TEST_F(SdfSmokeTest, RiseFallNames) {
|
|
EXPECT_STREQ(RiseFall::rise()->name(), "rise");
|
|
EXPECT_STREQ(RiseFall::fall()->name(), "fall");
|
|
EXPECT_STREQ(RiseFall::rise()->shortName(), "^");
|
|
EXPECT_STREQ(RiseFall::fall()->shortName(), "v");
|
|
}
|
|
|
|
// Test RiseFall opposite
|
|
TEST_F(SdfSmokeTest, RiseFallOpposite) {
|
|
EXPECT_EQ(RiseFall::rise()->opposite(), RiseFall::fall());
|
|
EXPECT_EQ(RiseFall::fall()->opposite(), RiseFall::rise());
|
|
}
|
|
|
|
// Test RiseFall asRiseFallBoth
|
|
TEST_F(SdfSmokeTest, RiseFallAsRiseFallBoth) {
|
|
const RiseFallBoth *rfb = RiseFall::rise()->asRiseFallBoth();
|
|
EXPECT_NE(rfb, nullptr);
|
|
EXPECT_EQ(rfb->asRiseFall(), RiseFall::rise());
|
|
}
|
|
|
|
// Test RiseFallBoth
|
|
TEST_F(SdfSmokeTest, RiseFallBothBasic) {
|
|
EXPECT_NE(RiseFallBoth::rise(), nullptr);
|
|
EXPECT_NE(RiseFallBoth::fall(), nullptr);
|
|
EXPECT_NE(RiseFallBoth::riseFall(), nullptr);
|
|
|
|
EXPECT_STREQ(RiseFallBoth::rise()->name(), "rise");
|
|
EXPECT_STREQ(RiseFallBoth::fall()->name(), "fall");
|
|
}
|
|
|
|
// Test RiseFallBoth matches
|
|
TEST_F(SdfSmokeTest, RiseFallBothMatches) {
|
|
EXPECT_TRUE(RiseFallBoth::rise()->matches(RiseFall::rise()));
|
|
EXPECT_FALSE(RiseFallBoth::rise()->matches(RiseFall::fall()));
|
|
EXPECT_TRUE(RiseFallBoth::riseFall()->matches(RiseFall::rise()));
|
|
EXPECT_TRUE(RiseFallBoth::riseFall()->matches(RiseFall::fall()));
|
|
}
|
|
|
|
// Test MinMax details
|
|
TEST_F(SdfSmokeTest, MinMaxDetails) {
|
|
EXPECT_STREQ(MinMax::min()->to_string().c_str(), "min");
|
|
EXPECT_STREQ(MinMax::max()->to_string().c_str(), "max");
|
|
EXPECT_EQ(MinMax::min()->index(), MinMax::minIndex());
|
|
EXPECT_EQ(MinMax::max()->index(), MinMax::maxIndex());
|
|
}
|
|
|
|
// Test MinMax opposite
|
|
TEST_F(SdfSmokeTest, MinMaxOpposite) {
|
|
EXPECT_EQ(MinMax::min()->opposite(), MinMax::max());
|
|
EXPECT_EQ(MinMax::max()->opposite(), MinMax::min());
|
|
}
|
|
|
|
// Test MinMax compare
|
|
TEST_F(SdfSmokeTest, MinMaxCompare) {
|
|
// min->compare returns true when value1 < value2
|
|
EXPECT_TRUE(MinMax::min()->compare(1.0f, 2.0f));
|
|
EXPECT_FALSE(MinMax::min()->compare(2.0f, 1.0f));
|
|
|
|
// max->compare returns true when value1 > value2
|
|
EXPECT_TRUE(MinMax::max()->compare(2.0f, 1.0f));
|
|
EXPECT_FALSE(MinMax::max()->compare(1.0f, 2.0f));
|
|
}
|
|
|
|
// Test MinMax minMax function
|
|
TEST_F(SdfSmokeTest, MinMaxMinMaxFunc) {
|
|
EXPECT_FLOAT_EQ(MinMax::min()->minMax(1.0f, 2.0f), 1.0f);
|
|
EXPECT_FLOAT_EQ(MinMax::max()->minMax(1.0f, 2.0f), 2.0f);
|
|
}
|
|
|
|
// Test MinMax find
|
|
TEST_F(SdfSmokeTest, MinMaxFind) {
|
|
EXPECT_EQ(MinMax::find("min"), MinMax::min());
|
|
EXPECT_EQ(MinMax::find("max"), MinMax::max());
|
|
EXPECT_EQ(MinMax::find(0), MinMax::min());
|
|
EXPECT_EQ(MinMax::find(1), MinMax::max());
|
|
}
|
|
|
|
// Test MinMaxAll
|
|
TEST_F(SdfSmokeTest, MinMaxAllBasic) {
|
|
EXPECT_NE(MinMaxAll::min(), nullptr);
|
|
EXPECT_NE(MinMaxAll::max(), nullptr);
|
|
EXPECT_NE(MinMaxAll::all(), nullptr);
|
|
}
|
|
|
|
// Test MinMaxAll matches
|
|
TEST_F(SdfSmokeTest, MinMaxAllMatches) {
|
|
EXPECT_TRUE(MinMaxAll::all()->matches(MinMax::min()));
|
|
EXPECT_TRUE(MinMaxAll::all()->matches(MinMax::max()));
|
|
EXPECT_TRUE(MinMaxAll::min()->matches(MinMax::min()));
|
|
EXPECT_FALSE(MinMaxAll::min()->matches(MinMax::max()));
|
|
}
|
|
|
|
// Test MinMaxAll range
|
|
TEST_F(SdfSmokeTest, MinMaxAllRange) {
|
|
auto range = MinMaxAll::all()->range();
|
|
EXPECT_EQ(range.size(), 2u);
|
|
|
|
auto min_range = MinMaxAll::min()->range();
|
|
EXPECT_EQ(min_range.size(), 1u);
|
|
}
|
|
|
|
// Test MinMax initValue
|
|
TEST_F(SdfSmokeTest, MinMaxInitValue) {
|
|
// min's init value is very large (positive INF)
|
|
EXPECT_GT(MinMax::min()->initValue(), 0.0f);
|
|
// max's init value is very negative (-INF)
|
|
EXPECT_LT(MinMax::max()->initValue(), 0.0f);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// Additional SDF-relevant tests for function coverage
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// Test all RiseFall methods
|
|
TEST_F(SdfSmokeTest, RiseFallIndex) {
|
|
EXPECT_EQ(RiseFall::rise()->index(), 0);
|
|
EXPECT_EQ(RiseFall::fall()->index(), 1);
|
|
}
|
|
|
|
// Test RiseFall::asTransition (Transition.cc coverage)
|
|
TEST_F(SdfSmokeTest, RiseFallAsTransition) {
|
|
const Transition *tr_rise = RiseFall::rise()->asTransition();
|
|
EXPECT_EQ(tr_rise, Transition::rise());
|
|
const Transition *tr_fall = RiseFall::fall()->asTransition();
|
|
EXPECT_EQ(tr_fall, Transition::fall());
|
|
}
|
|
|
|
// Test RiseFallBoth::find
|
|
TEST_F(SdfSmokeTest, RiseFallBothFindSdf) {
|
|
const RiseFallBoth *r = RiseFallBoth::find("rise");
|
|
EXPECT_NE(r, nullptr);
|
|
EXPECT_EQ(r, RiseFallBoth::rise());
|
|
const RiseFallBoth *f = RiseFallBoth::find("fall");
|
|
EXPECT_NE(f, nullptr);
|
|
EXPECT_EQ(f, RiseFallBoth::fall());
|
|
const RiseFallBoth *rf = RiseFallBoth::find("rise_fall");
|
|
EXPECT_NE(rf, nullptr);
|
|
EXPECT_EQ(rf, RiseFallBoth::riseFall());
|
|
}
|
|
|
|
// Test RiseFallBoth::matches(const Transition*)
|
|
TEST_F(SdfSmokeTest, RiseFallBothMatchesTransition) {
|
|
EXPECT_TRUE(RiseFallBoth::rise()->matches(Transition::rise()));
|
|
EXPECT_FALSE(RiseFallBoth::rise()->matches(Transition::fall()));
|
|
EXPECT_TRUE(RiseFallBoth::fall()->matches(Transition::fall()));
|
|
EXPECT_FALSE(RiseFallBoth::fall()->matches(Transition::rise()));
|
|
EXPECT_TRUE(RiseFallBoth::riseFall()->matches(Transition::rise()));
|
|
EXPECT_TRUE(RiseFallBoth::riseFall()->matches(Transition::fall()));
|
|
}
|
|
|
|
// Test Transition::asRiseFallBoth
|
|
TEST_F(SdfSmokeTest, TransitionAsRiseFallBothSdf) {
|
|
const RiseFallBoth *rfb = Transition::rise()->asRiseFallBoth();
|
|
EXPECT_NE(rfb, nullptr);
|
|
const RiseFallBoth *rfb2 = Transition::fall()->asRiseFallBoth();
|
|
EXPECT_NE(rfb2, nullptr);
|
|
}
|
|
|
|
// Test Transition find with init/final strings (used by SDF reader)
|
|
TEST_F(SdfSmokeTest, TransitionFindInitFinalSdf) {
|
|
EXPECT_EQ(Transition::find("01"), Transition::rise());
|
|
EXPECT_EQ(Transition::find("10"), Transition::fall());
|
|
EXPECT_EQ(Transition::find("0Z"), Transition::tr0Z());
|
|
EXPECT_EQ(Transition::find("Z1"), Transition::trZ1());
|
|
EXPECT_EQ(Transition::find("1Z"), Transition::tr1Z());
|
|
EXPECT_EQ(Transition::find("Z0"), Transition::trZ0());
|
|
EXPECT_EQ(Transition::find("0X"), Transition::tr0X());
|
|
EXPECT_EQ(Transition::find("X1"), Transition::trX1());
|
|
EXPECT_EQ(Transition::find("1X"), Transition::tr1X());
|
|
EXPECT_EQ(Transition::find("X0"), Transition::trX0());
|
|
EXPECT_EQ(Transition::find("XZ"), Transition::trXZ());
|
|
EXPECT_EQ(Transition::find("ZX"), Transition::trZX());
|
|
}
|
|
|
|
// Test all transition sdfTripleIndex values
|
|
TEST_F(SdfSmokeTest, AllTransitionSdfTripleIndex) {
|
|
EXPECT_EQ(Transition::rise()->sdfTripleIndex(), 0);
|
|
EXPECT_EQ(Transition::fall()->sdfTripleIndex(), 1);
|
|
EXPECT_EQ(Transition::tr0Z()->sdfTripleIndex(), 2);
|
|
EXPECT_EQ(Transition::trZ1()->sdfTripleIndex(), 3);
|
|
EXPECT_EQ(Transition::tr1Z()->sdfTripleIndex(), 4);
|
|
EXPECT_EQ(Transition::trZ0()->sdfTripleIndex(), 5);
|
|
EXPECT_EQ(Transition::tr0X()->sdfTripleIndex(), 6);
|
|
EXPECT_EQ(Transition::trX1()->sdfTripleIndex(), 7);
|
|
EXPECT_EQ(Transition::tr1X()->sdfTripleIndex(), 8);
|
|
EXPECT_EQ(Transition::trX0()->sdfTripleIndex(), 9);
|
|
EXPECT_EQ(Transition::trXZ()->sdfTripleIndex(), 10);
|
|
EXPECT_EQ(Transition::trZX()->sdfTripleIndex(), 11);
|
|
}
|
|
|
|
// Test all transition initFinal strings
|
|
TEST_F(SdfSmokeTest, AllTransitionInitFinalString) {
|
|
EXPECT_STREQ(Transition::rise()->asInitFinalString(), "01");
|
|
EXPECT_STREQ(Transition::fall()->asInitFinalString(), "10");
|
|
EXPECT_STREQ(Transition::tr0Z()->asInitFinalString(), "0Z");
|
|
EXPECT_STREQ(Transition::trZ1()->asInitFinalString(), "Z1");
|
|
EXPECT_STREQ(Transition::tr1Z()->asInitFinalString(), "1Z");
|
|
EXPECT_STREQ(Transition::trZ0()->asInitFinalString(), "Z0");
|
|
EXPECT_STREQ(Transition::tr0X()->asInitFinalString(), "0X");
|
|
EXPECT_STREQ(Transition::trX1()->asInitFinalString(), "X1");
|
|
EXPECT_STREQ(Transition::tr1X()->asInitFinalString(), "1X");
|
|
EXPECT_STREQ(Transition::trX0()->asInitFinalString(), "X0");
|
|
EXPECT_STREQ(Transition::trXZ()->asInitFinalString(), "XZ");
|
|
EXPECT_STREQ(Transition::trZX()->asInitFinalString(), "ZX");
|
|
}
|
|
|
|
// Test all transition asRiseFall
|
|
TEST_F(SdfSmokeTest, AllTransitionAsRiseFall) {
|
|
EXPECT_EQ(Transition::tr0Z()->asRiseFall(), RiseFall::rise());
|
|
EXPECT_EQ(Transition::trZ1()->asRiseFall(), RiseFall::rise());
|
|
EXPECT_EQ(Transition::tr0X()->asRiseFall(), RiseFall::rise());
|
|
EXPECT_EQ(Transition::trX1()->asRiseFall(), RiseFall::rise());
|
|
EXPECT_EQ(Transition::tr1Z()->asRiseFall(), RiseFall::fall());
|
|
EXPECT_EQ(Transition::trZ0()->asRiseFall(), RiseFall::fall());
|
|
EXPECT_EQ(Transition::tr1X()->asRiseFall(), RiseFall::fall());
|
|
EXPECT_EQ(Transition::trX0()->asRiseFall(), RiseFall::fall());
|
|
EXPECT_EQ(Transition::trXZ()->asRiseFall(), nullptr);
|
|
EXPECT_EQ(Transition::trZX()->asRiseFall(), nullptr);
|
|
}
|
|
|
|
// Test all transition to_string
|
|
TEST_F(SdfSmokeTest, AllTransitionToString) {
|
|
EXPECT_FALSE(Transition::tr0Z()->to_string().empty());
|
|
EXPECT_FALSE(Transition::trZ1()->to_string().empty());
|
|
EXPECT_FALSE(Transition::tr1Z()->to_string().empty());
|
|
EXPECT_FALSE(Transition::trZ0()->to_string().empty());
|
|
EXPECT_FALSE(Transition::tr0X()->to_string().empty());
|
|
EXPECT_FALSE(Transition::trX1()->to_string().empty());
|
|
EXPECT_FALSE(Transition::tr1X()->to_string().empty());
|
|
EXPECT_FALSE(Transition::trX0()->to_string().empty());
|
|
EXPECT_FALSE(Transition::trXZ()->to_string().empty());
|
|
EXPECT_FALSE(Transition::trZX()->to_string().empty());
|
|
EXPECT_FALSE(Transition::riseFall()->to_string().empty());
|
|
}
|
|
|
|
// Test RiseFallBoth range and rangeIndex
|
|
TEST_F(SdfSmokeTest, RiseFallBothRangesSdf) {
|
|
auto &rr = RiseFallBoth::rise()->range();
|
|
EXPECT_EQ(rr.size(), 1u);
|
|
auto &fr = RiseFallBoth::fall()->range();
|
|
EXPECT_EQ(fr.size(), 1u);
|
|
auto &rfr = RiseFallBoth::riseFall()->range();
|
|
EXPECT_EQ(rfr.size(), 2u);
|
|
|
|
auto &ri = RiseFallBoth::rise()->rangeIndex();
|
|
EXPECT_EQ(ri.size(), 1u);
|
|
auto &fi = RiseFallBoth::fall()->rangeIndex();
|
|
EXPECT_EQ(fi.size(), 1u);
|
|
auto &rfi = RiseFallBoth::riseFall()->rangeIndex();
|
|
EXPECT_EQ(rfi.size(), 2u);
|
|
}
|
|
|
|
// Test MinMax range and rangeIndex
|
|
TEST_F(SdfSmokeTest, MinMaxRange) {
|
|
auto &range = MinMax::range();
|
|
EXPECT_EQ(range.size(), 2u);
|
|
auto &ridx = MinMax::rangeIndex();
|
|
EXPECT_EQ(ridx.size(), 2u);
|
|
}
|
|
|
|
// Test Transition matches self
|
|
TEST_F(SdfSmokeTest, TransitionMatchesSelf) {
|
|
EXPECT_TRUE(Transition::rise()->matches(Transition::rise()));
|
|
EXPECT_FALSE(Transition::rise()->matches(Transition::fall()));
|
|
EXPECT_TRUE(Transition::fall()->matches(Transition::fall()));
|
|
EXPECT_TRUE(Transition::tr0Z()->matches(Transition::tr0Z()));
|
|
EXPECT_FALSE(Transition::tr0Z()->matches(Transition::trZ1()));
|
|
}
|
|
|
|
// Test MinMaxAll asMinMax
|
|
TEST_F(SdfSmokeTest, MinMaxAllAsMinMax) {
|
|
EXPECT_EQ(MinMaxAll::min()->asMinMax(), MinMax::min());
|
|
EXPECT_EQ(MinMaxAll::max()->asMinMax(), MinMax::max());
|
|
}
|
|
|
|
// SdfTriple tests (class defined in SdfReader.cc, not directly accessible
|
|
// but we test the concepts that SDF triple values represent)
|
|
|
|
// Test SDF edge names for transitions
|
|
// Covers: SdfWriter::sdfEdge - exercises transition to SDF edge string mapping
|
|
TEST_F(SdfSmokeTest, TransitionAsInitFinalString) {
|
|
// SDF uses init/final transition string representation
|
|
EXPECT_NE(Transition::rise()->asInitFinalString(), nullptr);
|
|
EXPECT_NE(Transition::fall()->asInitFinalString(), nullptr);
|
|
EXPECT_NE(Transition::tr0Z()->asInitFinalString(), nullptr);
|
|
EXPECT_NE(Transition::trZ1()->asInitFinalString(), nullptr);
|
|
EXPECT_NE(Transition::tr1Z()->asInitFinalString(), nullptr);
|
|
EXPECT_NE(Transition::trZ0()->asInitFinalString(), nullptr);
|
|
EXPECT_NE(Transition::tr0X()->asInitFinalString(), nullptr);
|
|
EXPECT_NE(Transition::trX1()->asInitFinalString(), nullptr);
|
|
EXPECT_NE(Transition::tr1X()->asInitFinalString(), nullptr);
|
|
EXPECT_NE(Transition::trX0()->asInitFinalString(), nullptr);
|
|
}
|
|
|
|
// Test Transition asRiseFall for SDF edge transitions
|
|
TEST_F(SdfSmokeTest, TransitionAsRiseFallAll) {
|
|
// Rise transitions map to rise
|
|
EXPECT_EQ(Transition::rise()->asRiseFall(), RiseFall::rise());
|
|
// Fall transitions map to fall
|
|
EXPECT_EQ(Transition::fall()->asRiseFall(), RiseFall::fall());
|
|
// Z1 maps to rise
|
|
EXPECT_EQ(Transition::trZ1()->asRiseFall(), RiseFall::rise());
|
|
// Z0 maps to fall
|
|
EXPECT_EQ(Transition::trZ0()->asRiseFall(), RiseFall::fall());
|
|
// 0Z maps to rise
|
|
EXPECT_EQ(Transition::tr0Z()->asRiseFall(), RiseFall::rise());
|
|
// 1Z maps to fall
|
|
EXPECT_EQ(Transition::tr1Z()->asRiseFall(), RiseFall::fall());
|
|
}
|
|
|
|
// Test MinMaxAll matches method
|
|
TEST_F(SdfSmokeTest, MinMaxAllMatches2) {
|
|
EXPECT_TRUE(MinMaxAll::min()->matches(MinMax::min()));
|
|
EXPECT_FALSE(MinMaxAll::min()->matches(MinMax::max()));
|
|
EXPECT_TRUE(MinMaxAll::max()->matches(MinMax::max()));
|
|
EXPECT_FALSE(MinMaxAll::max()->matches(MinMax::min()));
|
|
EXPECT_TRUE(MinMaxAll::all()->matches(MinMax::min()));
|
|
EXPECT_TRUE(MinMaxAll::all()->matches(MinMax::max()));
|
|
}
|
|
|
|
// Test MinMaxAll matches MinMaxAll
|
|
TEST_F(SdfSmokeTest, MinMaxAllMatchesAll) {
|
|
EXPECT_TRUE(MinMaxAll::all()->matches(MinMaxAll::min()));
|
|
EXPECT_TRUE(MinMaxAll::all()->matches(MinMaxAll::max()));
|
|
EXPECT_TRUE(MinMaxAll::all()->matches(MinMaxAll::all()));
|
|
EXPECT_TRUE(MinMaxAll::min()->matches(MinMaxAll::min()));
|
|
EXPECT_FALSE(MinMaxAll::min()->matches(MinMaxAll::max()));
|
|
}
|
|
|
|
// Test MinMax find by name
|
|
TEST_F(SdfSmokeTest, MinMaxFindByName) {
|
|
EXPECT_EQ(MinMax::find("min"), MinMax::min());
|
|
EXPECT_EQ(MinMax::find("max"), MinMax::max());
|
|
EXPECT_EQ(MinMax::find("nonexistent"), nullptr);
|
|
}
|
|
|
|
// Test MinMax find by index
|
|
TEST_F(SdfSmokeTest, MinMaxFindByIndex) {
|
|
EXPECT_EQ(MinMax::find(MinMax::minIndex()), MinMax::min());
|
|
EXPECT_EQ(MinMax::find(MinMax::maxIndex()), MinMax::max());
|
|
}
|
|
|
|
// Test MinMaxAll find by name
|
|
TEST_F(SdfSmokeTest, MinMaxAllFindByName) {
|
|
EXPECT_EQ(MinMaxAll::find("min"), MinMaxAll::min());
|
|
EXPECT_EQ(MinMaxAll::find("max"), MinMaxAll::max());
|
|
EXPECT_EQ(MinMaxAll::find("all"), MinMaxAll::all());
|
|
EXPECT_EQ(MinMaxAll::find("nonexistent"), nullptr);
|
|
}
|
|
|
|
// Test MinMax opposite
|
|
TEST_F(SdfSmokeTest, MinMaxOpposite2) {
|
|
EXPECT_EQ(MinMax::min()->opposite(), MinMax::max());
|
|
EXPECT_EQ(MinMax::max()->opposite(), MinMax::min());
|
|
}
|
|
|
|
// Test MinMax minMax function
|
|
TEST_F(SdfSmokeTest, MinMaxMinMaxFunc2) {
|
|
EXPECT_FLOAT_EQ(MinMax::min()->minMax(3.0f, 5.0f), 3.0f);
|
|
EXPECT_FLOAT_EQ(MinMax::min()->minMax(5.0f, 3.0f), 3.0f);
|
|
EXPECT_FLOAT_EQ(MinMax::max()->minMax(3.0f, 5.0f), 5.0f);
|
|
EXPECT_FLOAT_EQ(MinMax::max()->minMax(5.0f, 3.0f), 5.0f);
|
|
}
|
|
|
|
// Test MinMax to_string
|
|
TEST_F(SdfSmokeTest, MinMaxToString) {
|
|
EXPECT_EQ(MinMax::min()->to_string(), "min");
|
|
EXPECT_EQ(MinMax::max()->to_string(), "max");
|
|
}
|
|
|
|
// Test MinMaxAll to_string
|
|
TEST_F(SdfSmokeTest, MinMaxAllToString) {
|
|
EXPECT_EQ(MinMaxAll::min()->to_string(), "min");
|
|
EXPECT_EQ(MinMaxAll::max()->to_string(), "max");
|
|
EXPECT_EQ(MinMaxAll::all()->to_string(), "all");
|
|
}
|
|
|
|
// Test MinMax initValueInt
|
|
TEST_F(SdfSmokeTest, MinMaxInitValueInt) {
|
|
// min's init value is a large positive integer
|
|
EXPECT_GT(MinMax::min()->initValueInt(), 0);
|
|
// max's init value is a large negative integer
|
|
EXPECT_LT(MinMax::max()->initValueInt(), 0);
|
|
}
|
|
|
|
// Test MinMaxAll rangeIndex
|
|
TEST_F(SdfSmokeTest, MinMaxAllRangeIndex) {
|
|
auto &min_range_idx = MinMaxAll::min()->rangeIndex();
|
|
EXPECT_EQ(min_range_idx.size(), 1u);
|
|
EXPECT_EQ(min_range_idx[0], MinMax::minIndex());
|
|
|
|
auto &max_range_idx = MinMaxAll::max()->rangeIndex();
|
|
EXPECT_EQ(max_range_idx.size(), 1u);
|
|
EXPECT_EQ(max_range_idx[0], MinMax::maxIndex());
|
|
|
|
auto &all_range_idx = MinMaxAll::all()->rangeIndex();
|
|
EXPECT_EQ(all_range_idx.size(), 2u);
|
|
}
|
|
|
|
// Test MinMax constructor coverage (exercises internal MinMax ctor)
|
|
// Covers: MinMax::MinMax(const char*, int, float, int, compare_fn)
|
|
TEST_F(SdfSmokeTest, MinMaxConstructorCoverage) {
|
|
// The MinMax constructor is private; we verify it was called via singletons
|
|
const MinMax *mn = MinMax::min();
|
|
EXPECT_STREQ(mn->to_string().c_str(), "min");
|
|
EXPECT_EQ(mn->index(), MinMax::minIndex());
|
|
EXPECT_GT(mn->initValue(), 0.0f);
|
|
EXPECT_GT(mn->initValueInt(), 0);
|
|
// Compare function: min returns true when value1 < value2
|
|
EXPECT_TRUE(mn->compare(1.0f, 2.0f));
|
|
EXPECT_FALSE(mn->compare(3.0f, 2.0f));
|
|
|
|
const MinMax *mx = MinMax::max();
|
|
EXPECT_STREQ(mx->to_string().c_str(), "max");
|
|
EXPECT_EQ(mx->index(), MinMax::maxIndex());
|
|
EXPECT_LT(mx->initValue(), 0.0f);
|
|
EXPECT_LT(mx->initValueInt(), 0);
|
|
EXPECT_TRUE(mx->compare(3.0f, 2.0f));
|
|
EXPECT_FALSE(mx->compare(1.0f, 2.0f));
|
|
}
|
|
|
|
// Test MinMax minMax with equal values
|
|
// Covers: MinMax::minMax edge case
|
|
TEST_F(SdfSmokeTest, MinMaxMinMaxEqualValues) {
|
|
EXPECT_FLOAT_EQ(MinMax::min()->minMax(5.0f, 5.0f), 5.0f);
|
|
EXPECT_FLOAT_EQ(MinMax::max()->minMax(5.0f, 5.0f), 5.0f);
|
|
}
|
|
|
|
// Test MinMaxAll index values
|
|
// Covers: MinMaxAll constructor internals
|
|
TEST_F(SdfSmokeTest, MinMaxAllIndices) {
|
|
EXPECT_EQ(MinMaxAll::min()->index(), 0);
|
|
EXPECT_EQ(MinMaxAll::max()->index(), 1);
|
|
EXPECT_EQ(MinMaxAll::all()->index(), 2);
|
|
}
|
|
|
|
// Test MinMax find with nullptr
|
|
// Covers: MinMax::find edge case
|
|
TEST_F(SdfSmokeTest, MinMaxFindNull) {
|
|
const MinMax *result = MinMax::find("invalid_string");
|
|
EXPECT_EQ(result, nullptr);
|
|
}
|
|
|
|
// Test RiseFall asRiseFallBoth
|
|
// Covers: RiseFall::asRiseFallBoth
|
|
TEST_F(SdfSmokeTest, RiseFallAsRiseFallBoth2) {
|
|
const RiseFallBoth *rfb = RiseFall::rise()->asRiseFallBoth();
|
|
EXPECT_EQ(rfb, RiseFallBoth::rise());
|
|
rfb = RiseFall::fall()->asRiseFallBoth();
|
|
EXPECT_EQ(rfb, RiseFallBoth::fall());
|
|
}
|
|
|
|
// Test Transition::riseFall matches all transitions
|
|
// Covers: Transition::matches for riseFall wildcard
|
|
TEST_F(SdfSmokeTest, TransitionRiseFallMatchesAll) {
|
|
EXPECT_TRUE(Transition::riseFall()->matches(Transition::rise()));
|
|
EXPECT_TRUE(Transition::riseFall()->matches(Transition::fall()));
|
|
EXPECT_TRUE(Transition::riseFall()->matches(Transition::tr0Z()));
|
|
EXPECT_TRUE(Transition::riseFall()->matches(Transition::trZ1()));
|
|
EXPECT_TRUE(Transition::riseFall()->matches(Transition::tr1Z()));
|
|
EXPECT_TRUE(Transition::riseFall()->matches(Transition::trZ0()));
|
|
EXPECT_TRUE(Transition::riseFall()->matches(Transition::tr0X()));
|
|
EXPECT_TRUE(Transition::riseFall()->matches(Transition::trX1()));
|
|
EXPECT_TRUE(Transition::riseFall()->matches(Transition::tr1X()));
|
|
EXPECT_TRUE(Transition::riseFall()->matches(Transition::trX0()));
|
|
EXPECT_TRUE(Transition::riseFall()->matches(Transition::trXZ()));
|
|
EXPECT_TRUE(Transition::riseFall()->matches(Transition::trZX()));
|
|
}
|
|
|
|
// Test Transition::find with empty/unknown string
|
|
// Covers: Transition::find edge case
|
|
TEST_F(SdfSmokeTest, TransitionFindUnknown) {
|
|
const Transition *t = Transition::find("nonexistent");
|
|
EXPECT_EQ(t, nullptr);
|
|
}
|
|
|
|
// Test RiseFall::find with unknown string
|
|
// Covers: RiseFall::find edge case
|
|
TEST_F(SdfSmokeTest, RiseFallFindUnknown) {
|
|
const RiseFall *rf = RiseFall::find("unknown");
|
|
EXPECT_EQ(rf, nullptr);
|
|
}
|
|
|
|
// Test Transition::maxIndex value
|
|
// Covers: Transition::maxIndex
|
|
TEST_F(SdfSmokeTest, TransitionMaxIndex) {
|
|
// Transition::maxIndex() returns the max valid index
|
|
EXPECT_GE(Transition::maxIndex(), 1);
|
|
// All transitions should have index <= maxIndex
|
|
EXPECT_LE(Transition::rise()->index(), Transition::maxIndex());
|
|
EXPECT_LE(Transition::fall()->index(), Transition::maxIndex());
|
|
}
|
|
|
|
// Test RiseFall to_string
|
|
// Covers: RiseFall::to_string
|
|
TEST_F(SdfSmokeTest, RiseFallToString) {
|
|
EXPECT_EQ(RiseFall::rise()->to_string(), "rise");
|
|
EXPECT_EQ(RiseFall::fall()->to_string(), "fall");
|
|
}
|
|
|
|
// Test MinMax compare with equal values
|
|
// Covers: MinMax::compare edge case
|
|
TEST_F(SdfSmokeTest, MinMaxCompareEqual) {
|
|
EXPECT_FALSE(MinMax::min()->compare(5.0f, 5.0f));
|
|
EXPECT_FALSE(MinMax::max()->compare(5.0f, 5.0f));
|
|
}
|
|
|
|
// Test MinMax compare with negative values
|
|
// Covers: MinMax::compare with negatives
|
|
TEST_F(SdfSmokeTest, MinMaxCompareNegative) {
|
|
EXPECT_TRUE(MinMax::min()->compare(-2.0f, -1.0f));
|
|
EXPECT_FALSE(MinMax::min()->compare(-1.0f, -2.0f));
|
|
EXPECT_TRUE(MinMax::max()->compare(-1.0f, -2.0f));
|
|
EXPECT_FALSE(MinMax::max()->compare(-2.0f, -1.0f));
|
|
}
|
|
|
|
// Test MinMax compare with zero
|
|
// Covers: MinMax::compare with zero
|
|
TEST_F(SdfSmokeTest, MinMaxCompareZero) {
|
|
EXPECT_TRUE(MinMax::min()->compare(0.0f, 1.0f));
|
|
EXPECT_FALSE(MinMax::min()->compare(0.0f, 0.0f));
|
|
EXPECT_TRUE(MinMax::max()->compare(1.0f, 0.0f));
|
|
EXPECT_FALSE(MinMax::max()->compare(0.0f, 0.0f));
|
|
}
|
|
|
|
// Test MinMaxAll range sizes
|
|
// Covers: MinMaxAll::range
|
|
TEST_F(SdfSmokeTest, MinMaxAllRangeSizes) {
|
|
EXPECT_EQ(MinMaxAll::min()->range().size(), 1u);
|
|
EXPECT_EQ(MinMaxAll::max()->range().size(), 1u);
|
|
EXPECT_EQ(MinMaxAll::all()->range().size(), 2u);
|
|
}
|
|
|
|
// Test Transition sdfTripleIndex uniqueness
|
|
// Covers: Transition::sdfTripleIndex
|
|
TEST_F(SdfSmokeTest, TransitionSdfTripleIndexUnique) {
|
|
std::set<int> indices;
|
|
indices.insert(Transition::rise()->sdfTripleIndex());
|
|
indices.insert(Transition::fall()->sdfTripleIndex());
|
|
indices.insert(Transition::tr0Z()->sdfTripleIndex());
|
|
indices.insert(Transition::trZ1()->sdfTripleIndex());
|
|
indices.insert(Transition::tr1Z()->sdfTripleIndex());
|
|
indices.insert(Transition::trZ0()->sdfTripleIndex());
|
|
indices.insert(Transition::tr0X()->sdfTripleIndex());
|
|
indices.insert(Transition::trX1()->sdfTripleIndex());
|
|
indices.insert(Transition::tr1X()->sdfTripleIndex());
|
|
indices.insert(Transition::trX0()->sdfTripleIndex());
|
|
indices.insert(Transition::trXZ()->sdfTripleIndex());
|
|
indices.insert(Transition::trZX()->sdfTripleIndex());
|
|
EXPECT_EQ(indices.size(), 12u);
|
|
}
|
|
|
|
// Test RiseFall range iteration
|
|
// Covers: RiseFall::range
|
|
TEST_F(SdfSmokeTest, RiseFallRangeIteration) {
|
|
int count = 0;
|
|
for (auto rf : RiseFall::range()) {
|
|
EXPECT_NE(rf, nullptr);
|
|
count++;
|
|
}
|
|
EXPECT_EQ(count, 2);
|
|
}
|
|
|
|
// Test MinMax range
|
|
// Covers: MinMax::range
|
|
TEST_F(SdfSmokeTest, MinMaxRangeIteration) {
|
|
int count = 0;
|
|
for (auto mm : MinMax::range()) {
|
|
EXPECT_NE(mm, nullptr);
|
|
count++;
|
|
}
|
|
EXPECT_EQ(count, 2);
|
|
}
|
|
|
|
// Test RiseFallBoth find with nullptr
|
|
// Covers: RiseFallBoth::find edge case
|
|
TEST_F(SdfSmokeTest, RiseFallBothFindNull) {
|
|
const RiseFallBoth *result = RiseFallBoth::find("nonexistent");
|
|
EXPECT_EQ(result, nullptr);
|
|
}
|
|
|
|
// Test Transition asRiseFallBoth for non-rise/fall transitions
|
|
// Covers: Transition::asRiseFallBoth edge cases
|
|
TEST_F(SdfSmokeTest, TransitionAsRiseFallBothTristate) {
|
|
// Tristate transitions should still return valid RiseFallBoth
|
|
const RiseFallBoth *rfb_0z = Transition::tr0Z()->asRiseFallBoth();
|
|
EXPECT_NE(rfb_0z, nullptr);
|
|
}
|
|
|
|
// Test Transition to_string for riseFall wildcard
|
|
// Covers: Transition::to_string for riseFall
|
|
TEST_F(SdfSmokeTest, TransitionRiseFallToString) {
|
|
EXPECT_FALSE(Transition::riseFall()->to_string().empty());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R8_ tests for SDF module coverage improvement
|
|
// SdfWriter, SdfTriple, SdfPortSpec are all internal/protected.
|
|
// We exercise them through the full STA flow.
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
} // namespace sta
|
|
|
|
#include <tcl.h>
|
|
#include <cstdio>
|
|
#include "Sta.hh"
|
|
#include "Network.hh"
|
|
#include "ReportTcl.hh"
|
|
#include "Scene.hh"
|
|
#include "Error.hh"
|
|
#include "sdf/SdfReader.hh"
|
|
|
|
namespace sta {
|
|
|
|
class SdfDesignTest : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override {
|
|
interp_ = Tcl_CreateInterp();
|
|
initSta();
|
|
sta_ = new Sta;
|
|
Sta::setSta(sta_);
|
|
sta_->makeComponents();
|
|
ReportTcl *report = dynamic_cast<ReportTcl*>(sta_->report());
|
|
if (report)
|
|
report->setTclInterp(interp_);
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
const MinMaxAll *min_max = MinMaxAll::all();
|
|
bool infer_latches = false;
|
|
|
|
LibertyLibrary *lib_seq = sta_->readLiberty(
|
|
"test/asap7/asap7sc7p5t_SEQ_RVT_FF_nldm_220123.lib",
|
|
corner, min_max, infer_latches);
|
|
if (!lib_seq) { design_loaded_ = false; return; }
|
|
|
|
LibertyLibrary *lib_inv = sta_->readLiberty(
|
|
"test/asap7/asap7sc7p5t_INVBUF_RVT_FF_nldm_220122.lib.gz",
|
|
corner, min_max, infer_latches);
|
|
if (!lib_inv) { design_loaded_ = false; return; }
|
|
|
|
LibertyLibrary *lib_simple = sta_->readLiberty(
|
|
"test/asap7/asap7sc7p5t_SIMPLE_RVT_FF_nldm_211120.lib.gz",
|
|
corner, min_max, infer_latches);
|
|
if (!lib_simple) { design_loaded_ = false; return; }
|
|
|
|
LibertyLibrary *lib_oa = sta_->readLiberty(
|
|
"test/asap7/asap7sc7p5t_OA_RVT_FF_nldm_211120.lib.gz",
|
|
corner, min_max, infer_latches);
|
|
if (!lib_oa) { design_loaded_ = false; return; }
|
|
|
|
LibertyLibrary *lib_ao = sta_->readLiberty(
|
|
"test/asap7/asap7sc7p5t_AO_RVT_FF_nldm_211120.lib.gz",
|
|
corner, min_max, infer_latches);
|
|
if (!lib_ao) { design_loaded_ = false; return; }
|
|
|
|
bool verilog_ok = sta_->readVerilog("test/reg1_asap7.v");
|
|
if (!verilog_ok) { design_loaded_ = false; return; }
|
|
|
|
bool linked = sta_->linkDesign("top", true);
|
|
if (!linked) { design_loaded_ = false; return; }
|
|
|
|
design_loaded_ = true;
|
|
}
|
|
|
|
void TearDown() override {
|
|
deleteAllMemory();
|
|
sta_ = nullptr;
|
|
if (interp_)
|
|
Tcl_DeleteInterp(interp_);
|
|
interp_ = nullptr;
|
|
}
|
|
|
|
Sta *sta_;
|
|
Tcl_Interp *interp_;
|
|
bool design_loaded_ = false;
|
|
};
|
|
|
|
// Test writeSdf exercises SdfWriter constructor/destructor,
|
|
// writeTrailer, writeInstTrailer, sdfEdge, writeTimingCheckHeader/Trailer
|
|
// Covers: SdfWriter::~SdfWriter, SdfWriter::writeTrailer,
|
|
// SdfWriter::writeInstTrailer, SdfWriter::writeTimingCheckHeader,
|
|
// SdfWriter::writeTimingCheckTrailer, SdfWriter::sdfEdge
|
|
TEST_F(SdfDesignTest, WriteSdfExercisesWriter) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
// Read SPEF to have timing data
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
// Write SDF to a temp file - this exercises all SdfWriter methods
|
|
const char *tmpfile = "/tmp/test_r8_sdf_output.sdf";
|
|
sta_->writeSdf(tmpfile, corner, '/', true, 3, false, true, true);
|
|
|
|
// Verify the file was created and has content
|
|
FILE *f = fopen(tmpfile, "r");
|
|
ASSERT_NE(f, nullptr);
|
|
fseek(f, 0, SEEK_END);
|
|
long size = ftell(f);
|
|
fclose(f);
|
|
EXPECT_GT(size, 0);
|
|
|
|
// Clean up
|
|
std::remove(tmpfile);
|
|
}
|
|
|
|
// Test writeSdf with gzip
|
|
// Covers: SdfWriter methods through gzip path
|
|
TEST_F(SdfDesignTest, WriteSdfGzip) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *tmpfile = "/tmp/test_r8_sdf_output.sdf.gz";
|
|
sta_->writeSdf(tmpfile, corner, '/', false, 3, true, true, true);
|
|
|
|
// Verify the file was created
|
|
FILE *f = fopen(tmpfile, "r");
|
|
ASSERT_NE(f, nullptr);
|
|
fseek(f, 0, SEEK_END);
|
|
long size = ftell(f);
|
|
fclose(f);
|
|
EXPECT_GT(size, 0);
|
|
|
|
std::remove(tmpfile);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////
|
|
// R9_ tests for SDF module coverage improvement
|
|
////////////////////////////////////////////////////////////////
|
|
|
|
// Test writeSdf with dot divider
|
|
// Covers: SdfWriter path separator handling
|
|
TEST_F(SdfDesignTest, WriteSdfDotDivider) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *tmpfile = "/tmp/test_r9_sdf_dot.sdf";
|
|
sta_->writeSdf(tmpfile, corner, '.', true, 3, false, true, true);
|
|
|
|
FILE *f = fopen(tmpfile, "r");
|
|
ASSERT_NE(f, nullptr);
|
|
fseek(f, 0, SEEK_END);
|
|
long size = ftell(f);
|
|
fclose(f);
|
|
EXPECT_GT(size, 0);
|
|
std::remove(tmpfile);
|
|
}
|
|
|
|
// Test writeSdf without typ values
|
|
// Covers: SdfWriter min/max only path
|
|
TEST_F(SdfDesignTest, WriteSdfNoTyp) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *tmpfile = "/tmp/test_r9_sdf_notyp.sdf";
|
|
sta_->writeSdf(tmpfile, corner, '/', false, 3, false, true, true);
|
|
|
|
FILE *f = fopen(tmpfile, "r");
|
|
ASSERT_NE(f, nullptr);
|
|
fseek(f, 0, SEEK_END);
|
|
long size = ftell(f);
|
|
fclose(f);
|
|
EXPECT_GT(size, 0);
|
|
std::remove(tmpfile);
|
|
}
|
|
|
|
// Test writeSdf with high precision
|
|
// Covers: SdfWriter digit formatting
|
|
TEST_F(SdfDesignTest, WriteSdfHighPrecision) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *tmpfile = "/tmp/test_r9_sdf_highprec.sdf";
|
|
sta_->writeSdf(tmpfile, corner, '/', true, 6, false, true, true);
|
|
|
|
FILE *f = fopen(tmpfile, "r");
|
|
ASSERT_NE(f, nullptr);
|
|
fseek(f, 0, SEEK_END);
|
|
long size = ftell(f);
|
|
fclose(f);
|
|
EXPECT_GT(size, 0);
|
|
std::remove(tmpfile);
|
|
}
|
|
|
|
// Test writeSdf with no_timestamp
|
|
// Covers: SdfWriter header control
|
|
TEST_F(SdfDesignTest, WriteSdfNoTimestamp) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *tmpfile = "/tmp/test_r9_sdf_notimestamp.sdf";
|
|
sta_->writeSdf(tmpfile, corner, '/', true, 3, false, false, true);
|
|
|
|
FILE *f = fopen(tmpfile, "r");
|
|
ASSERT_NE(f, nullptr);
|
|
fseek(f, 0, SEEK_END);
|
|
long size = ftell(f);
|
|
fclose(f);
|
|
EXPECT_GT(size, 0);
|
|
std::remove(tmpfile);
|
|
}
|
|
|
|
// Test writeSdf with no_timescale
|
|
// Covers: SdfWriter timescale control
|
|
TEST_F(SdfDesignTest, WriteSdfNoTimescale) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *tmpfile = "/tmp/test_r9_sdf_notimescale.sdf";
|
|
sta_->writeSdf(tmpfile, corner, '/', true, 3, false, true, false);
|
|
|
|
FILE *f = fopen(tmpfile, "r");
|
|
ASSERT_NE(f, nullptr);
|
|
fseek(f, 0, SEEK_END);
|
|
long size = ftell(f);
|
|
fclose(f);
|
|
EXPECT_GT(size, 0);
|
|
std::remove(tmpfile);
|
|
}
|
|
|
|
// Test writeSdf and readSdf round-trip
|
|
// Covers: readSdf, SdfReader constructor, SdfScanner, SdfPortSpec, SdfTriple
|
|
TEST_F(SdfDesignTest, WriteThenReadSdf) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *tmpfile = "/tmp/test_r9_sdf_roundtrip.sdf";
|
|
sta_->writeSdf(tmpfile, corner, '/', true, 3, false, true, true);
|
|
|
|
// Now read it back
|
|
readSdf(tmpfile, nullptr, corner, false, false,
|
|
const_cast<MinMaxAll*>(MinMaxAll::all()), sta_);
|
|
|
|
std::remove(tmpfile);
|
|
}
|
|
|
|
// Test readSdf with unescaped_dividers option
|
|
// Covers: SdfReader unescaped divider path
|
|
TEST_F(SdfDesignTest, ReadSdfUnescapedDividers) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *tmpfile = "/tmp/test_r9_sdf_unesc.sdf";
|
|
sta_->writeSdf(tmpfile, corner, '/', true, 3, false, true, true);
|
|
|
|
readSdf(tmpfile, nullptr, corner, true, false,
|
|
const_cast<MinMaxAll*>(MinMaxAll::all()), sta_);
|
|
|
|
std::remove(tmpfile);
|
|
}
|
|
|
|
// Test readSdf with incremental_only option
|
|
// Covers: SdfReader incremental_only path
|
|
TEST_F(SdfDesignTest, ReadSdfIncrementalOnly) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *tmpfile = "/tmp/test_r9_sdf_incr.sdf";
|
|
sta_->writeSdf(tmpfile, corner, '/', true, 3, false, true, true);
|
|
|
|
readSdf(tmpfile, nullptr, corner, false, true,
|
|
const_cast<MinMaxAll*>(MinMaxAll::all()), sta_);
|
|
|
|
std::remove(tmpfile);
|
|
}
|
|
|
|
// Test readSdf with cond_use min
|
|
// Covers: SdfReader cond_use min path
|
|
TEST_F(SdfDesignTest, ReadSdfCondUseMin) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *tmpfile = "/tmp/test_r9_sdf_cumin.sdf";
|
|
sta_->writeSdf(tmpfile, corner, '/', true, 3, false, true, true);
|
|
|
|
readSdf(tmpfile, nullptr, corner, false, false,
|
|
const_cast<MinMaxAll*>(MinMaxAll::min()), sta_);
|
|
|
|
std::remove(tmpfile);
|
|
}
|
|
|
|
// Test readSdf with cond_use max
|
|
// Covers: SdfReader cond_use max path
|
|
TEST_F(SdfDesignTest, ReadSdfCondUseMax) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *tmpfile = "/tmp/test_r9_sdf_cumax.sdf";
|
|
sta_->writeSdf(tmpfile, corner, '/', true, 3, false, true, true);
|
|
|
|
readSdf(tmpfile, nullptr, corner, false, false,
|
|
const_cast<MinMaxAll*>(MinMaxAll::max()), sta_);
|
|
|
|
std::remove(tmpfile);
|
|
}
|
|
|
|
// Test writeSdf then read with both unescaped and incremental
|
|
// Covers: combined SdfReader option paths
|
|
TEST_F(SdfDesignTest, ReadSdfCombinedOptions) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *tmpfile = "/tmp/test_r9_sdf_combined.sdf";
|
|
sta_->writeSdf(tmpfile, corner, '/', true, 3, false, true, true);
|
|
|
|
readSdf(tmpfile, nullptr, corner, true, true,
|
|
const_cast<MinMaxAll*>(MinMaxAll::all()), sta_);
|
|
|
|
std::remove(tmpfile);
|
|
}
|
|
|
|
// Test writeSdf with low precision (1 digit)
|
|
// Covers: SdfWriter digit formatting edge case
|
|
TEST_F(SdfDesignTest, WriteSdfLowPrecision) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *tmpfile = "/tmp/test_r9_sdf_lowprec.sdf";
|
|
sta_->writeSdf(tmpfile, corner, '/', true, 1, false, true, true);
|
|
|
|
FILE *f = fopen(tmpfile, "r");
|
|
ASSERT_NE(f, nullptr);
|
|
fseek(f, 0, SEEK_END);
|
|
long size = ftell(f);
|
|
fclose(f);
|
|
EXPECT_GT(size, 0);
|
|
std::remove(tmpfile);
|
|
}
|
|
|
|
// Test writeSdf gzip then readSdf
|
|
// Covers: SdfReader gzip input path
|
|
TEST_F(SdfDesignTest, WriteSdfGzipThenRead) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *tmpfile = "/tmp/test_r9_sdf_gz.sdf.gz";
|
|
sta_->writeSdf(tmpfile, corner, '/', true, 3, true, true, true);
|
|
|
|
readSdf(tmpfile, nullptr, corner, false, false,
|
|
const_cast<MinMaxAll*>(MinMaxAll::all()), sta_);
|
|
|
|
std::remove(tmpfile);
|
|
}
|
|
|
|
// Test writeSdf with no_timestamp and no_timescale
|
|
// Covers: SdfWriter combined header options
|
|
TEST_F(SdfDesignTest, WriteSdfNoTimestampNoTimescale) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *tmpfile = "/tmp/test_r9_sdf_minimal.sdf";
|
|
sta_->writeSdf(tmpfile, corner, '/', false, 3, false, false, false);
|
|
|
|
FILE *f = fopen(tmpfile, "r");
|
|
ASSERT_NE(f, nullptr);
|
|
fseek(f, 0, SEEK_END);
|
|
long size = ftell(f);
|
|
fclose(f);
|
|
EXPECT_GT(size, 0);
|
|
std::remove(tmpfile);
|
|
}
|
|
|
|
// Test readSdf with nonexistent file throws FileNotReadable
|
|
// Covers: SdfReader error handling path
|
|
TEST_F(SdfDesignTest, ReadSdfNonexistent) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
// Attempt to read nonexistent SDF - should throw
|
|
EXPECT_THROW(
|
|
readSdf("/tmp/nonexistent_r9.sdf", nullptr, corner,
|
|
false, false, const_cast<MinMaxAll*>(MinMaxAll::all()), sta_),
|
|
FileNotReadable
|
|
);
|
|
}
|
|
|
|
// R9_ SdfSmokeTest - Transition properties for SDF
|
|
TEST_F(SdfSmokeTest, TransitionRiseProperties) {
|
|
const Transition *t = Transition::rise();
|
|
EXPECT_NE(t, nullptr);
|
|
EXPECT_EQ(t->asRiseFall(), RiseFall::rise());
|
|
EXPECT_EQ(t->sdfTripleIndex(), RiseFall::riseIndex());
|
|
EXPECT_FALSE(t->to_string().empty());
|
|
EXPECT_NE(t->asInitFinalString(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdfSmokeTest, TransitionFallProperties) {
|
|
const Transition *t = Transition::fall();
|
|
EXPECT_NE(t, nullptr);
|
|
EXPECT_EQ(t->asRiseFall(), RiseFall::fall());
|
|
EXPECT_EQ(t->sdfTripleIndex(), RiseFall::fallIndex());
|
|
EXPECT_FALSE(t->to_string().empty());
|
|
EXPECT_NE(t->asInitFinalString(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdfSmokeTest, TransitionTristateProperties) {
|
|
// 0Z
|
|
const Transition *t0z = Transition::tr0Z();
|
|
EXPECT_NE(t0z, nullptr);
|
|
EXPECT_FALSE(t0z->to_string().empty());
|
|
EXPECT_NE(t0z->asRiseFallBoth(), nullptr);
|
|
|
|
// Z1
|
|
const Transition *tz1 = Transition::trZ1();
|
|
EXPECT_NE(tz1, nullptr);
|
|
EXPECT_NE(tz1->asRiseFallBoth(), nullptr);
|
|
|
|
// 1Z
|
|
const Transition *t1z = Transition::tr1Z();
|
|
EXPECT_NE(t1z, nullptr);
|
|
EXPECT_NE(t1z->asRiseFallBoth(), nullptr);
|
|
|
|
// Z0
|
|
const Transition *tz0 = Transition::trZ0();
|
|
EXPECT_NE(tz0, nullptr);
|
|
EXPECT_NE(tz0->asRiseFallBoth(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdfSmokeTest, TransitionUnknownProperties) {
|
|
// 0X
|
|
const Transition *t0x = Transition::tr0X();
|
|
EXPECT_NE(t0x, nullptr);
|
|
EXPECT_NE(t0x->asRiseFallBoth(), nullptr);
|
|
|
|
// X1
|
|
const Transition *tx1 = Transition::trX1();
|
|
EXPECT_NE(tx1, nullptr);
|
|
EXPECT_NE(tx1->asRiseFallBoth(), nullptr);
|
|
|
|
// 1X
|
|
const Transition *t1x = Transition::tr1X();
|
|
EXPECT_NE(t1x, nullptr);
|
|
EXPECT_NE(t1x->asRiseFallBoth(), nullptr);
|
|
|
|
// X0
|
|
const Transition *tx0 = Transition::trX0();
|
|
EXPECT_NE(tx0, nullptr);
|
|
EXPECT_NE(tx0->asRiseFallBoth(), nullptr);
|
|
}
|
|
|
|
TEST_F(SdfSmokeTest, TransitionHighZUnknown) {
|
|
// XZ
|
|
const Transition *txz = Transition::trXZ();
|
|
EXPECT_NE(txz, nullptr);
|
|
EXPECT_FALSE(txz->to_string().empty());
|
|
|
|
// ZX
|
|
const Transition *tzx = Transition::trZX();
|
|
EXPECT_NE(tzx, nullptr);
|
|
EXPECT_FALSE(tzx->to_string().empty());
|
|
}
|
|
|
|
TEST_F(SdfSmokeTest, RiseFallBothRiseFallMatches) {
|
|
EXPECT_TRUE(RiseFallBoth::riseFall()->matches(RiseFall::rise()));
|
|
EXPECT_TRUE(RiseFallBoth::riseFall()->matches(RiseFall::fall()));
|
|
EXPECT_TRUE(RiseFallBoth::rise()->matches(RiseFall::rise()));
|
|
EXPECT_FALSE(RiseFallBoth::rise()->matches(RiseFall::fall()));
|
|
EXPECT_FALSE(RiseFallBoth::fall()->matches(RiseFall::rise()));
|
|
EXPECT_TRUE(RiseFallBoth::fall()->matches(RiseFall::fall()));
|
|
}
|
|
|
|
TEST_F(SdfSmokeTest, MinMaxAllRange2) {
|
|
// Verify MinMaxAll::all() range contains both min and max
|
|
int count = 0;
|
|
for (auto mm : MinMaxAll::all()->range()) {
|
|
EXPECT_NE(mm, nullptr);
|
|
count++;
|
|
}
|
|
EXPECT_EQ(count, 2);
|
|
}
|
|
|
|
TEST_F(SdfSmokeTest, MinMaxInitValue2) {
|
|
// min init value is large positive (for finding minimum)
|
|
float min_init = MinMax::min()->initValue();
|
|
EXPECT_GT(min_init, 0.0f);
|
|
|
|
// max init value is large negative (for finding maximum)
|
|
float max_init = MinMax::max()->initValue();
|
|
EXPECT_LT(max_init, 0.0f);
|
|
}
|
|
|
|
TEST_F(SdfSmokeTest, MinMaxCompareExtremes) {
|
|
// Very large values
|
|
EXPECT_TRUE(MinMax::min()->compare(1e10f, 1e20f));
|
|
EXPECT_FALSE(MinMax::min()->compare(1e20f, 1e10f));
|
|
EXPECT_TRUE(MinMax::max()->compare(1e20f, 1e10f));
|
|
EXPECT_FALSE(MinMax::max()->compare(1e10f, 1e20f));
|
|
|
|
// Very small values
|
|
EXPECT_TRUE(MinMax::min()->compare(1e-20f, 1e-10f));
|
|
EXPECT_TRUE(MinMax::max()->compare(1e-10f, 1e-20f));
|
|
}
|
|
|
|
TEST_F(SdfSmokeTest, RiseFallToStringAndFind) {
|
|
EXPECT_EQ(RiseFall::rise()->to_string(), "rise");
|
|
EXPECT_EQ(RiseFall::fall()->to_string(), "fall");
|
|
EXPECT_EQ(RiseFall::find("^"), RiseFall::rise());
|
|
EXPECT_EQ(RiseFall::find("v"), RiseFall::fall());
|
|
EXPECT_EQ(RiseFall::find("rise"), RiseFall::rise());
|
|
EXPECT_EQ(RiseFall::find("fall"), RiseFall::fall());
|
|
}
|
|
|
|
TEST_F(SdfSmokeTest, TransitionFindByName) {
|
|
EXPECT_EQ(Transition::find("^"), Transition::rise());
|
|
EXPECT_EQ(Transition::find("v"), Transition::fall());
|
|
EXPECT_EQ(Transition::find("nonexistent"), nullptr);
|
|
}
|
|
|
|
TEST_F(SdfSmokeTest, MinMaxAllAsMinMax2) {
|
|
EXPECT_EQ(MinMaxAll::min()->asMinMax(), MinMax::min());
|
|
EXPECT_EQ(MinMaxAll::max()->asMinMax(), MinMax::max());
|
|
}
|
|
|
|
TEST_F(SdfSmokeTest, RiseFallOpposite2) {
|
|
EXPECT_EQ(RiseFall::rise()->opposite(), RiseFall::fall());
|
|
EXPECT_EQ(RiseFall::fall()->opposite(), RiseFall::rise());
|
|
}
|
|
|
|
TEST_F(SdfSmokeTest, TransitionMatchesSelf2) {
|
|
EXPECT_TRUE(Transition::rise()->matches(Transition::rise()));
|
|
EXPECT_TRUE(Transition::fall()->matches(Transition::fall()));
|
|
EXPECT_FALSE(Transition::rise()->matches(Transition::fall()));
|
|
EXPECT_FALSE(Transition::fall()->matches(Transition::rise()));
|
|
}
|
|
|
|
TEST_F(SdfSmokeTest, TransitionMatchesRiseFallWildcard) {
|
|
EXPECT_TRUE(Transition::riseFall()->matches(Transition::rise()));
|
|
EXPECT_TRUE(Transition::riseFall()->matches(Transition::fall()));
|
|
EXPECT_TRUE(Transition::riseFall()->matches(Transition::tr0Z()));
|
|
EXPECT_TRUE(Transition::riseFall()->matches(Transition::trXZ()));
|
|
}
|
|
|
|
TEST_F(SdfSmokeTest, MinMaxMinMaxFunc3) {
|
|
EXPECT_FLOAT_EQ(MinMax::min()->minMax(10.0f, 20.0f), 10.0f);
|
|
EXPECT_FLOAT_EQ(MinMax::max()->minMax(10.0f, 20.0f), 20.0f);
|
|
EXPECT_FLOAT_EQ(MinMax::min()->minMax(-5.0f, 5.0f), -5.0f);
|
|
EXPECT_FLOAT_EQ(MinMax::max()->minMax(-5.0f, 5.0f), 5.0f);
|
|
}
|
|
|
|
TEST_F(SdfSmokeTest, RiseFallBothFind) {
|
|
EXPECT_EQ(RiseFallBoth::find("rise"), RiseFallBoth::rise());
|
|
EXPECT_EQ(RiseFallBoth::find("fall"), RiseFallBoth::fall());
|
|
EXPECT_EQ(RiseFallBoth::find("rise_fall"), RiseFallBoth::riseFall());
|
|
EXPECT_EQ(RiseFallBoth::find("nonexistent"), nullptr);
|
|
}
|
|
|
|
// =========================================================================
|
|
// R11_ tests: Cover additional uncovered SDF functions
|
|
// =========================================================================
|
|
|
|
// R11_1: Write SDF then read it with a path argument
|
|
// Covers: SdfReader with path set, SdfTriple construction paths
|
|
TEST_F(SdfDesignTest, ReadSdfWithPath) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *tmpfile = "/tmp/test_r11_sdf_path.sdf";
|
|
sta_->writeSdf(tmpfile, corner, '/', true, 3, false, true, true);
|
|
|
|
// Read with a path argument (top instance path)
|
|
readSdf(tmpfile, "top", corner, false, false,
|
|
const_cast<MinMaxAll*>(MinMaxAll::all()), sta_);
|
|
|
|
std::remove(tmpfile);
|
|
}
|
|
|
|
// R11_2: Read a hand-crafted SDF with specific constructs to exercise
|
|
// SdfReader::makeTriple(), makeTriple(float), SdfPortSpec, SdfTriple::hasValue
|
|
TEST_F(SdfDesignTest, ReadHandCraftedSdf) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
// Write a hand-crafted SDF with IOPATH and timing checks
|
|
const char *sdf_path = "/tmp/test_r11_handcraft.sdf";
|
|
FILE *fp = fopen(sdf_path, "w");
|
|
ASSERT_NE(fp, nullptr);
|
|
fprintf(fp, "(DELAYFILE\n");
|
|
fprintf(fp, " (SDFVERSION \"3.0\")\n");
|
|
fprintf(fp, " (DESIGN \"top\")\n");
|
|
fprintf(fp, " (TIMESCALE 1ns)\n");
|
|
fprintf(fp, " (CELL\n");
|
|
fprintf(fp, " (CELLTYPE \"DFFHQx4_ASAP7_75t_R\")\n");
|
|
fprintf(fp, " (INSTANCE r1)\n");
|
|
fprintf(fp, " (DELAY\n");
|
|
fprintf(fp, " (ABSOLUTE\n");
|
|
fprintf(fp, " (IOPATH CLK Q (0.100::0.200) (0.150::0.250))\n");
|
|
fprintf(fp, " )\n");
|
|
fprintf(fp, " )\n");
|
|
fprintf(fp, " (TIMINGCHECK\n");
|
|
fprintf(fp, " (SETUP D (posedge CLK) (0.050::0.080))\n");
|
|
fprintf(fp, " (HOLD D (posedge CLK) (0.020::0.030))\n");
|
|
fprintf(fp, " )\n");
|
|
fprintf(fp, " )\n");
|
|
fprintf(fp, ")\n");
|
|
fclose(fp);
|
|
|
|
readSdf(sdf_path, nullptr, corner, false, false,
|
|
const_cast<MinMaxAll*>(MinMaxAll::all()), sta_);
|
|
|
|
std::remove(sdf_path);
|
|
}
|
|
|
|
// R11_3: Read SDF with edge-specific IOPATH (posedge, negedge)
|
|
// Covers: SdfPortSpec with transitions, sdfEdge paths
|
|
TEST_F(SdfDesignTest, ReadSdfEdgeIopath) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *sdf_path = "/tmp/test_r11_edge_iopath.sdf";
|
|
FILE *fp = fopen(sdf_path, "w");
|
|
ASSERT_NE(fp, nullptr);
|
|
fprintf(fp, "(DELAYFILE\n");
|
|
fprintf(fp, " (SDFVERSION \"3.0\")\n");
|
|
fprintf(fp, " (DESIGN \"top\")\n");
|
|
fprintf(fp, " (TIMESCALE 1ns)\n");
|
|
fprintf(fp, " (CELL\n");
|
|
fprintf(fp, " (CELLTYPE \"DFFHQx4_ASAP7_75t_R\")\n");
|
|
fprintf(fp, " (INSTANCE r1)\n");
|
|
fprintf(fp, " (DELAY\n");
|
|
fprintf(fp, " (ABSOLUTE\n");
|
|
fprintf(fp, " (IOPATH (posedge CLK) Q (0.100::0.200) (0.150::0.250))\n");
|
|
fprintf(fp, " (IOPATH (negedge CLK) Q (0.110::0.210) (0.160::0.260))\n");
|
|
fprintf(fp, " )\n");
|
|
fprintf(fp, " )\n");
|
|
fprintf(fp, " )\n");
|
|
fprintf(fp, ")\n");
|
|
fclose(fp);
|
|
|
|
readSdf(sdf_path, nullptr, corner, false, false,
|
|
const_cast<MinMaxAll*>(MinMaxAll::all()), sta_);
|
|
|
|
std::remove(sdf_path);
|
|
}
|
|
|
|
// R11_4: Read SDF with SETUPHOLD combined check
|
|
// Covers: SdfReader::timingCheckSetupHold path
|
|
TEST_F(SdfDesignTest, ReadSdfSetupHold) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *sdf_path = "/tmp/test_r11_setuphold.sdf";
|
|
FILE *fp = fopen(sdf_path, "w");
|
|
ASSERT_NE(fp, nullptr);
|
|
fprintf(fp, "(DELAYFILE\n");
|
|
fprintf(fp, " (SDFVERSION \"3.0\")\n");
|
|
fprintf(fp, " (DESIGN \"top\")\n");
|
|
fprintf(fp, " (TIMESCALE 1ns)\n");
|
|
fprintf(fp, " (CELL\n");
|
|
fprintf(fp, " (CELLTYPE \"DFFHQx4_ASAP7_75t_R\")\n");
|
|
fprintf(fp, " (INSTANCE r1)\n");
|
|
fprintf(fp, " (TIMINGCHECK\n");
|
|
fprintf(fp, " (SETUPHOLD D (posedge CLK) (0.050) (0.020))\n");
|
|
fprintf(fp, " )\n");
|
|
fprintf(fp, " )\n");
|
|
fprintf(fp, ")\n");
|
|
fclose(fp);
|
|
|
|
readSdf(sdf_path, nullptr, corner, false, false,
|
|
const_cast<MinMaxAll*>(MinMaxAll::all()), sta_);
|
|
|
|
std::remove(sdf_path);
|
|
}
|
|
|
|
// R11_5: Read SDF with RECREM combined check
|
|
// Covers: SdfReader::timingCheckRecRem path
|
|
TEST_F(SdfDesignTest, ReadSdfRecRem) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *sdf_path = "/tmp/test_r11_recrem.sdf";
|
|
FILE *fp = fopen(sdf_path, "w");
|
|
ASSERT_NE(fp, nullptr);
|
|
fprintf(fp, "(DELAYFILE\n");
|
|
fprintf(fp, " (SDFVERSION \"3.0\")\n");
|
|
fprintf(fp, " (DESIGN \"top\")\n");
|
|
fprintf(fp, " (TIMESCALE 1ns)\n");
|
|
fprintf(fp, " (CELL\n");
|
|
fprintf(fp, " (CELLTYPE \"DFFHQx4_ASAP7_75t_R\")\n");
|
|
fprintf(fp, " (INSTANCE r1)\n");
|
|
fprintf(fp, " (TIMINGCHECK\n");
|
|
fprintf(fp, " (RECREM D (posedge CLK) (0.050) (0.020))\n");
|
|
fprintf(fp, " )\n");
|
|
fprintf(fp, " )\n");
|
|
fprintf(fp, ")\n");
|
|
fclose(fp);
|
|
|
|
readSdf(sdf_path, nullptr, corner, false, false,
|
|
const_cast<MinMaxAll*>(MinMaxAll::all()), sta_);
|
|
|
|
std::remove(sdf_path);
|
|
}
|
|
|
|
// R11_6: Read SDF with WIDTH check
|
|
// Covers: SdfReader::timingCheckWidth path
|
|
TEST_F(SdfDesignTest, ReadSdfWidth) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *sdf_path = "/tmp/test_r11_width.sdf";
|
|
FILE *fp = fopen(sdf_path, "w");
|
|
ASSERT_NE(fp, nullptr);
|
|
fprintf(fp, "(DELAYFILE\n");
|
|
fprintf(fp, " (SDFVERSION \"3.0\")\n");
|
|
fprintf(fp, " (DESIGN \"top\")\n");
|
|
fprintf(fp, " (TIMESCALE 1ns)\n");
|
|
fprintf(fp, " (CELL\n");
|
|
fprintf(fp, " (CELLTYPE \"DFFHQx4_ASAP7_75t_R\")\n");
|
|
fprintf(fp, " (INSTANCE r1)\n");
|
|
fprintf(fp, " (TIMINGCHECK\n");
|
|
fprintf(fp, " (WIDTH (posedge CLK) (0.100))\n");
|
|
fprintf(fp, " )\n");
|
|
fprintf(fp, " )\n");
|
|
fprintf(fp, ")\n");
|
|
fclose(fp);
|
|
|
|
readSdf(sdf_path, nullptr, corner, false, false,
|
|
const_cast<MinMaxAll*>(MinMaxAll::all()), sta_);
|
|
|
|
std::remove(sdf_path);
|
|
}
|
|
|
|
// R11_7: Read SDF with PERIOD check
|
|
// Covers: SdfReader::timingCheckPeriod path
|
|
TEST_F(SdfDesignTest, ReadSdfPeriod) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *sdf_path = "/tmp/test_r11_period.sdf";
|
|
FILE *fp = fopen(sdf_path, "w");
|
|
ASSERT_NE(fp, nullptr);
|
|
fprintf(fp, "(DELAYFILE\n");
|
|
fprintf(fp, " (SDFVERSION \"3.0\")\n");
|
|
fprintf(fp, " (DESIGN \"top\")\n");
|
|
fprintf(fp, " (TIMESCALE 1ns)\n");
|
|
fprintf(fp, " (CELL\n");
|
|
fprintf(fp, " (CELLTYPE \"DFFHQx4_ASAP7_75t_R\")\n");
|
|
fprintf(fp, " (INSTANCE r1)\n");
|
|
fprintf(fp, " (TIMINGCHECK\n");
|
|
fprintf(fp, " (PERIOD (posedge CLK) (1.000))\n");
|
|
fprintf(fp, " )\n");
|
|
fprintf(fp, " )\n");
|
|
fprintf(fp, ")\n");
|
|
fclose(fp);
|
|
|
|
readSdf(sdf_path, nullptr, corner, false, false,
|
|
const_cast<MinMaxAll*>(MinMaxAll::all()), sta_);
|
|
|
|
std::remove(sdf_path);
|
|
}
|
|
|
|
// R11_8: Read SDF with NOCHANGE check
|
|
// Covers: SdfReader::timingCheckNochange, notSupported
|
|
// NOCHANGE is not supported and throws, so we catch the exception
|
|
TEST_F(SdfDesignTest, ReadSdfNochange) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *sdf_path = "/tmp/test_r11_nochange.sdf";
|
|
FILE *fp = fopen(sdf_path, "w");
|
|
ASSERT_NE(fp, nullptr);
|
|
fprintf(fp, "(DELAYFILE\n");
|
|
fprintf(fp, " (SDFVERSION \"3.0\")\n");
|
|
fprintf(fp, " (DESIGN \"top\")\n");
|
|
fprintf(fp, " (TIMESCALE 1ns)\n");
|
|
fprintf(fp, " (CELL\n");
|
|
fprintf(fp, " (CELLTYPE \"DFFHQx4_ASAP7_75t_R\")\n");
|
|
fprintf(fp, " (INSTANCE r1)\n");
|
|
fprintf(fp, " (TIMINGCHECK\n");
|
|
fprintf(fp, " (NOCHANGE D (posedge CLK) (0.050) (0.020))\n");
|
|
fprintf(fp, " )\n");
|
|
fprintf(fp, " )\n");
|
|
fprintf(fp, ")\n");
|
|
fclose(fp);
|
|
|
|
// NOCHANGE is not supported and throws an exception
|
|
EXPECT_THROW(
|
|
readSdf(sdf_path, nullptr, corner, false, false,
|
|
const_cast<MinMaxAll*>(MinMaxAll::all()), sta_),
|
|
std::exception
|
|
);
|
|
|
|
std::remove(sdf_path);
|
|
}
|
|
|
|
// R11_9: Read SDF with INTERCONNECT delay
|
|
// Covers: SdfReader::interconnect path
|
|
TEST_F(SdfDesignTest, ReadSdfInterconnect) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *sdf_path = "/tmp/test_r11_interconnect.sdf";
|
|
FILE *fp = fopen(sdf_path, "w");
|
|
ASSERT_NE(fp, nullptr);
|
|
fprintf(fp, "(DELAYFILE\n");
|
|
fprintf(fp, " (SDFVERSION \"3.0\")\n");
|
|
fprintf(fp, " (DESIGN \"top\")\n");
|
|
fprintf(fp, " (TIMESCALE 1ns)\n");
|
|
fprintf(fp, " (CELL\n");
|
|
fprintf(fp, " (CELLTYPE \"top\")\n");
|
|
fprintf(fp, " (INSTANCE)\n");
|
|
fprintf(fp, " (DELAY\n");
|
|
fprintf(fp, " (ABSOLUTE\n");
|
|
fprintf(fp, " (INTERCONNECT u1/Y r3/D (0.010::0.020) (0.015::0.025))\n");
|
|
fprintf(fp, " )\n");
|
|
fprintf(fp, " )\n");
|
|
fprintf(fp, " )\n");
|
|
fprintf(fp, ")\n");
|
|
fclose(fp);
|
|
|
|
readSdf(sdf_path, nullptr, corner, false, false,
|
|
const_cast<MinMaxAll*>(MinMaxAll::all()), sta_);
|
|
|
|
std::remove(sdf_path);
|
|
}
|
|
|
|
// R11_10: WriteSdf with include_typ=true and no_version=false to cover
|
|
// the writeHeader path with version
|
|
TEST_F(SdfDesignTest, WriteSdfWithVersion) {
|
|
ASSERT_TRUE(design_loaded_);
|
|
sta_->ensureGraph();
|
|
|
|
Scene *corner = sta_->cmdScene();
|
|
sta_->readSpef("test/reg1_asap7.spef", "test/reg1_asap7.spef",
|
|
sta_->network()->topInstance(), corner,
|
|
MinMaxAll::all(), false, false, 1.0f, true);
|
|
|
|
const char *tmpfile = "/tmp/test_r11_sdf_version.sdf";
|
|
// no_timestamp=false, no_version=false -> includes version and timestamp
|
|
sta_->writeSdf(tmpfile, corner, '/', true, 4, false, false, false);
|
|
|
|
FILE *f = fopen(tmpfile, "r");
|
|
ASSERT_NE(f, nullptr);
|
|
fseek(f, 0, SEEK_END);
|
|
long size = ftell(f);
|
|
fclose(f);
|
|
EXPECT_GT(size, 0);
|
|
std::remove(tmpfile);
|
|
}
|
|
|
|
} // namespace sta
|