diff --git a/liberty/test/cpp/TestLibertyStaBasicsB.cc b/liberty/test/cpp/TestLibertyStaBasicsB.cc index ae12235f..2754c008 100644 --- a/liberty/test/cpp/TestLibertyStaBasicsB.cc +++ b/liberty/test/cpp/TestLibertyStaBasicsB.cc @@ -46,6 +46,12 @@ static void expectStaLibertyCoreState(Sta *sta, LibertyLibrary *lib) EXPECT_NE(lib, nullptr); } +static LibertyAttrValue * +makeStringAttrValue(const char *value) +{ + return new LibertyAttrValue(std::string(value)); +} + class LinearModelTest : public ::testing::Test { protected: void SetUp() override { @@ -1012,189 +1018,147 @@ TEST_F(StaLibertyTest, LibraryDriverWaveformDefault) { // R6 tests: LibertyParser classes coverage //////////////////////////////////////////////////////////////// -#if 0 -TEST(R6_LibertyStmtTest, ConstructorAndVirtuals) { - LibertyStmt *stmt = new LibertyVariable("x", 1.0f, 42); - EXPECT_EQ(stmt->line(), 42); - EXPECT_FALSE(stmt->isGroup()); - EXPECT_FALSE(stmt->isAttribute()); - EXPECT_FALSE(stmt->isDefine()); - EXPECT_TRUE(stmt->isVariable()); - delete stmt; +TEST(R6_LibertyVariableTest, ConstructorAndAccessors) { + LibertyVariable var("x", 1.0f, 42); + EXPECT_EQ(var.line(), 42); + EXPECT_EQ(var.variable(), "x"); + EXPECT_FLOAT_EQ(var.value(), 1.0f); } -#endif -#if 0 -TEST(R6_LibertyStmtTest, LibertyStmtBaseDefaultVirtuals) { - // LibertyStmt base class: isGroup, isAttribute, isDefine, isVariable all false - LibertyVariable var("v", 0.0f, 1); - LibertyStmt *base = &var; - // LibertyVariable overrides isVariable - EXPECT_TRUE(base->isVariable()); - EXPECT_FALSE(base->isGroup()); - EXPECT_FALSE(base->isAttribute()); - EXPECT_FALSE(base->isDefine()); +TEST(R6_LibertyAttrValueTest, FloatValueAndQuotedStringParsing) { + LibertyAttrValue float_value(1.25f); + EXPECT_TRUE(float_value.isFloat()); + EXPECT_FALSE(float_value.isString()); + EXPECT_FLOAT_EQ(float_value.floatValue(), 1.25f); + + LibertyAttrValue quoted_value(std::string("3.14")); + float parsed = 0.0f; + bool valid = false; + quoted_value.floatValue(parsed, valid); + EXPECT_TRUE(valid); + EXPECT_FLOAT_EQ(parsed, 3.14f); + EXPECT_TRUE(quoted_value.isString()); } -#endif -#if 0 TEST(R6_LibertyGroupTest, Construction) { - LibertyAttrValueSeq *params = new LibertyAttrValueSeq; - params->push_back(new LibertyStringAttrValue("cell1")); - LibertyGroup grp("cell", params, 10); - EXPECT_EQ(grp.type(), "cell"); - EXPECT_TRUE(grp.isGroup()); + LibertyAttrValueSeq params; + params.push_back(makeStringAttrValue("cell1")); + params.push_back(makeStringAttrValue("slow")); + LibertyGroup grp("scaled_cell", std::move(params), 10); + EXPECT_EQ(grp.type(), "scaled_cell"); EXPECT_EQ(grp.line(), 10); - EXPECT_EQ(grp.firstName(), std::string("cell1")); + ASSERT_NE(grp.firstName(), nullptr); + EXPECT_STREQ(grp.firstName(), "cell1"); + ASSERT_NE(grp.secondName(), nullptr); + EXPECT_STREQ(grp.secondName(), "slow"); } -#endif -#if 0 TEST(R6_LibertyGroupTest, AddSubgroupAndIterate) { - LibertyAttrValueSeq *params = new LibertyAttrValueSeq; - LibertyGroup *grp = new LibertyGroup("library", params, 1); - LibertyAttrValueSeq *sub_params = new LibertyAttrValueSeq; - LibertyGroup *sub = new LibertyGroup("cell", sub_params, 2); - grp->addStmt(sub); - LibertyStmtSeq *stmts = grp->stmts(); - ASSERT_NE(stmts, nullptr); - EXPECT_EQ(stmts->size(), 1u); - EXPECT_EQ((*stmts)[0], sub); - delete grp; + LibertyGroup grp("library", LibertyAttrValueSeq(), 1); + auto *sub = new LibertyGroup("cell", LibertyAttrValueSeq(), 2); + grp.addSubgroup(sub); + EXPECT_EQ(grp.subgroups().size(), 1u); + EXPECT_EQ(grp.subgroups()[0], sub); + EXPECT_EQ(grp.findSubgroup("cell"), sub); + EXPECT_EQ(grp.findSubgroups("cell").size(), 1u); } -#endif -#if 0 TEST(R6_LibertyGroupTest, AddAttributeAndIterate) { - LibertyAttrValueSeq *params = new LibertyAttrValueSeq; - LibertyGroup *grp = new LibertyGroup("cell", params, 1); - LibertyAttrValue *val = new LibertyFloatAttrValue(3.14f); - LibertySimpleAttr *attr = new LibertySimpleAttr("area", val, 5); - grp->addStmt(attr); - // Iterate over statements - LibertyStmtSeq *stmts = grp->stmts(); - ASSERT_NE(stmts, nullptr); - EXPECT_EQ(stmts->size(), 1u); - EXPECT_EQ((*stmts)[0], attr); - delete grp; -} -#endif + LibertyGroup grp("cell", LibertyAttrValueSeq(), 1); + grp.addAttr(new LibertySimpleAttr("area", LibertyAttrValue(3.14f), 5)); + const LibertySimpleAttr *attr = grp.findSimpleAttr("area"); + ASSERT_NE(attr, nullptr); + EXPECT_EQ(attr->line(), 5); + EXPECT_TRUE(attr->value().isFloat()); + EXPECT_FLOAT_EQ(attr->value().floatValue(), 3.14f); + + float area = 0.0f; + bool exists = false; + grp.findAttrFloat("area", area, exists); + EXPECT_TRUE(exists); + EXPECT_FLOAT_EQ(area, 3.14f); +} -#if 0 TEST(R6_LibertySimpleAttrTest, Construction) { - LibertyAttrValue *val = new LibertyStringAttrValue("test_value"); - LibertySimpleAttr attr("name", val, 7); + LibertySimpleAttr attr("name", LibertyAttrValue(std::string("test_value")), 7); EXPECT_EQ(attr.name(), "name"); - EXPECT_TRUE(attr.isSimpleAttr()); - EXPECT_FALSE(attr.isComplexAttr()); - // isAttribute() returns false for LibertyAttr subclasses - // (only LibertyStmt base provides it, and it returns false). - EXPECT_FALSE(attr.isAttribute()); - LibertyAttrValue *first = attr.firstValue(); - EXPECT_NE(first, nullptr); - EXPECT_TRUE(first->isString()); - EXPECT_EQ(first->stringValue(), "test_value"); + EXPECT_EQ(attr.line(), 7); + ASSERT_NE(attr.stringValue(), nullptr); + EXPECT_EQ(*attr.stringValue(), "test_value"); + EXPECT_TRUE(attr.value().isString()); } -#endif -#if 0 -TEST(R6_LibertySimpleAttrTest, ValuesReturnsNull) { - LibertyAttrValue *val = new LibertyFloatAttrValue(1.0f); - LibertySimpleAttr attr("test", val, 1); - // values() on simple attr is not standard; in implementation it triggers error - // Just test firstValue - EXPECT_EQ(attr.firstValue(), val); +TEST(R6_LibertySimpleAttrTest, FloatValueStorage) { + LibertyGroup grp("cell", LibertyAttrValueSeq(), 1); + grp.addAttr(new LibertySimpleAttr("test", LibertyAttrValue(1.0f), 1)); + float value = 0.0f; + bool exists = false; + grp.findAttrFloat("test", value, exists); + EXPECT_TRUE(exists); + EXPECT_FLOAT_EQ(value, 1.0f); } -#endif -#if 0 TEST(R6_LibertyComplexAttrTest, Construction) { - LibertyAttrValueSeq *vals = new LibertyAttrValueSeq; - vals->push_back(new LibertyFloatAttrValue(1.0f)); - vals->push_back(new LibertyFloatAttrValue(2.0f)); - LibertyComplexAttr attr("values", vals, 15); + LibertyAttrValueSeq vals; + vals.push_back(new LibertyAttrValue(1.0f)); + vals.push_back(new LibertyAttrValue(2.0f)); + LibertyComplexAttr attr("values", std::move(vals), 15); EXPECT_EQ(attr.name(), "values"); - EXPECT_FALSE(attr.isSimpleAttr()); - EXPECT_TRUE(attr.isComplexAttr()); - // isAttribute() returns false for LibertyAttr subclasses - EXPECT_FALSE(attr.isAttribute()); - LibertyAttrValue *first = attr.firstValue(); + EXPECT_EQ(attr.line(), 15); + const LibertyAttrValue *first = attr.firstValue(); EXPECT_NE(first, nullptr); EXPECT_TRUE(first->isFloat()); EXPECT_FLOAT_EQ(first->floatValue(), 1.0f); - LibertyAttrValueSeq *returned_vals = attr.values(); - EXPECT_EQ(returned_vals->size(), 2u); + EXPECT_EQ(attr.values().size(), 2u); } -#endif -#if 0 TEST(R6_LibertyComplexAttrTest, EmptyValues) { - LibertyAttrValueSeq *vals = new LibertyAttrValueSeq; - LibertyComplexAttr attr("empty", vals, 1); - LibertyAttrValue *first = attr.firstValue(); + LibertyComplexAttr attr("empty", LibertyAttrValueSeq(), 1); + const LibertyAttrValue *first = attr.firstValue(); EXPECT_EQ(first, nullptr); } -#endif -#if 0 -TEST(R6_LibertyStringAttrValueTest, Basic) { - LibertyStringAttrValue sav("hello"); +TEST(R6_LibertyAttrValueTest, StringBasic) { + LibertyAttrValue sav(std::string("hello")); EXPECT_TRUE(sav.isString()); EXPECT_FALSE(sav.isFloat()); EXPECT_EQ(sav.stringValue(), "hello"); } -#endif -#if 0 -TEST(R6_LibertyFloatAttrValueTest, Basic) { - LibertyFloatAttrValue fav(42.5f); +TEST(R6_LibertyAttrValueTest, FloatBasic) { + LibertyAttrValue fav(42.5f); EXPECT_TRUE(fav.isFloat()); EXPECT_FALSE(fav.isString()); EXPECT_FLOAT_EQ(fav.floatValue(), 42.5f); } -#endif -#if 0 TEST(R6_LibertyDefineTest, Construction) { LibertyDefine def("my_attr", LibertyGroupType::cell, LibertyAttrType::attr_string, 20); EXPECT_EQ(def.name(), "my_attr"); - EXPECT_TRUE(def.isDefine()); - EXPECT_FALSE(def.isGroup()); - EXPECT_FALSE(def.isAttribute()); - EXPECT_FALSE(def.isVariable()); EXPECT_EQ(def.groupType(), LibertyGroupType::cell); EXPECT_EQ(def.valueType(), LibertyAttrType::attr_string); EXPECT_EQ(def.line(), 20); } -#endif -#if 0 TEST(R6_LibertyVariableTest, Construction) { LibertyVariable var("k_volt_cell_rise", 1.5f, 30); EXPECT_EQ(var.variable(), "k_volt_cell_rise"); EXPECT_FLOAT_EQ(var.value(), 1.5f); - EXPECT_TRUE(var.isVariable()); - EXPECT_FALSE(var.isGroup()); - EXPECT_FALSE(var.isDefine()); EXPECT_EQ(var.line(), 30); } -#endif //////////////////////////////////////////////////////////////// // R6 tests: LibertyBuilder destructor //////////////////////////////////////////////////////////////// -#if 0 -// LibertyBuilder default constructor removed; requires Debug*, Report* -TEST(R6_LibertyBuilderTest, ConstructAndDestruct) { +TEST_F(StaLibertyTest, R6_LibertyBuilderConstructAndDestruct) { ASSERT_NO_THROW(( [&](){ - LibertyBuilder *builder = new LibertyBuilder; - delete builder; + LibertyBuilder builder(sta_->debug(), sta_->report()); + (void) builder; }() )); } -#endif //////////////////////////////////////////////////////////////// // R6 tests: WireloadForArea (via WireloadSelection) @@ -1791,69 +1755,72 @@ TEST_F(StaLibertyTest, LibraryFilename) { // Covers LibertyStmt::LibertyStmt(int), LibertyStmt::isVariable(), // LibertyGroup::isGroup(), LibertyGroup::findAttr() -#if 0 TEST(LibertyParserTest, LibertyGroupConstruction) { - LibertyAttrValueSeq *params = new LibertyAttrValueSeq; - LibertyStringAttrValue *val = new LibertyStringAttrValue("test_lib"); - params->push_back(val); - LibertyGroup group("library", params, 1); - EXPECT_TRUE(group.isGroup()); - EXPECT_FALSE(group.isVariable()); + LibertyGroup group("library", LibertyAttrValueSeq(), 1); + group.addAttr(new LibertySimpleAttr("name", + LibertyAttrValue(std::string("test_lib")), + 2)); + group.addAttr(new LibertySimpleAttr("max_cap", + LibertyAttrValue(3.0f), + 3)); + LibertyAttrValueSeq values; + values.push_back(new LibertyAttrValue(0.1f)); + values.push_back(new LibertyAttrValue(0.2f)); + group.addAttr(new LibertyComplexAttr("index_1", std::move(values), 4)); + group.addDefine(new LibertyDefine("my_define", + LibertyGroupType::cell, + LibertyAttrType::attr_string, + 5)); + group.addSubgroup(new LibertyGroup("cell", LibertyAttrValueSeq(), 6)); + EXPECT_EQ(group.type(), "library"); EXPECT_EQ(group.line(), 1); - // findAttr removed from API + ASSERT_NE(group.findAttrString("name"), nullptr); + EXPECT_EQ(*group.findAttrString("name"), "test_lib"); + float max_cap = 0.0f; + bool exists = false; + group.findAttrFloat("max_cap", max_cap, exists); + EXPECT_TRUE(exists); + EXPECT_FLOAT_EQ(max_cap, 3.0f); + int max_cap_int = 0; + group.findAttrInt("max_cap", max_cap_int, exists); + EXPECT_TRUE(exists); + EXPECT_EQ(max_cap_int, 3); + EXPECT_NE(group.findComplexAttr("index_1"), nullptr); + EXPECT_EQ(group.findComplexAttrs("index_1").size(), 1u); + EXPECT_NE(group.findSubgroup("cell"), nullptr); + EXPECT_EQ(group.defineMap().size(), 1u); } -#endif -// R7_LibertySimpleAttr removed (segfault) - -// Covers LibertyComplexAttr::isSimple() -#if 0 TEST(LibertyParserTest, LibertyComplexAttr) { - LibertyAttrValueSeq *vals = new LibertyAttrValueSeq; - vals->push_back(new LibertyFloatAttrValue(1.0f)); - vals->push_back(new LibertyFloatAttrValue(2.0f)); - LibertyComplexAttr attr("complex_attr", vals, 5); - // isAttribute() returns false for LibertyAttr subclasses - EXPECT_FALSE(attr.isAttribute()); - EXPECT_FALSE(attr.isSimpleAttr()); - EXPECT_TRUE(attr.isComplexAttr()); - LibertyAttrValue *fv = attr.firstValue(); + LibertyAttrValueSeq vals; + vals.push_back(makeStringAttrValue("0.1")); + vals.push_back(new LibertyAttrValue(2.0f)); + LibertyComplexAttr attr("complex_attr", std::move(vals), 5); + EXPECT_EQ(attr.name(), "complex_attr"); + EXPECT_EQ(attr.line(), 5); + const LibertyAttrValue *fv = attr.firstValue(); EXPECT_NE(fv, nullptr); - EXPECT_TRUE(fv->isFloat()); + EXPECT_TRUE(fv->isString()); + EXPECT_EQ(fv->stringValue(), "0.1"); + EXPECT_EQ(attr.values().size(), 2u); } -#endif -// R7_LibertyStringAttrValueFloatValue removed (segfault) - -// R7_LibertyFloatAttrValueStringValue removed (segfault) - -// Covers LibertyDefine::isDefine() -#if 0 TEST(LibertyParserTest, LibertyDefine) { LibertyDefine def("my_define", LibertyGroupType::cell, LibertyAttrType::attr_string, 20); - EXPECT_TRUE(def.isDefine()); - EXPECT_FALSE(def.isGroup()); - EXPECT_FALSE(def.isAttribute()); - EXPECT_FALSE(def.isVariable()); EXPECT_EQ(def.name(), "my_define"); EXPECT_EQ(def.groupType(), LibertyGroupType::cell); EXPECT_EQ(def.valueType(), LibertyAttrType::attr_string); + EXPECT_EQ(def.line(), 20); } -#endif -// Covers LibertyVariable::isVariable() -#if 0 TEST(LibertyParserTest, LibertyVariable) { LibertyVariable var("input_threshold_pct_rise", 50.0f, 15); - EXPECT_TRUE(var.isVariable()); - EXPECT_FALSE(var.isGroup()); - EXPECT_FALSE(var.isAttribute()); + EXPECT_EQ(var.line(), 15); EXPECT_EQ(var.variable(), "input_threshold_pct_rise"); EXPECT_FLOAT_EQ(var.value(), 50.0f); } -#endif // R7_LibertyGroupFindAttr removed (segfault) @@ -1866,14 +1833,14 @@ TEST(LibertyParserTest, LibertyVariable) { //////////////////////////////////////////////////////////////// // Covers LibertyBuilder::~LibertyBuilder() -#if 0 -// LibertyBuilder default constructor removed; requires Debug*, Report* -TEST(LibertyBuilderTest, LibertyBuilderDestructor) { - LibertyBuilder *builder = new LibertyBuilder(); +TEST_F(StaLibertyTest, LibertyBuilderDestructor) { + ASSERT_NO_THROW(( [&](){ + LibertyBuilder *builder = new LibertyBuilder(sta_->debug(), sta_->report()); EXPECT_NE(builder, nullptr); delete builder; + + }() )); } -#endif // R7_ToStringAllTypes removed (to_string(TimingType) not linked for liberty test target) diff --git a/liberty/test/cpp/TestLibertyStaCallbacks.cc b/liberty/test/cpp/TestLibertyStaCallbacks.cc index a8628f08..4ec656e4 100644 --- a/liberty/test/cpp/TestLibertyStaCallbacks.cc +++ b/liberty/test/cpp/TestLibertyStaCallbacks.cc @@ -149,6 +149,66 @@ static LibertyLibrary *writeAndReadLibReturn(Sta *sta, const char *content, cons return lib; } +static LibertyAttrValue * +makeStringAttrValue(const char *value) +{ + return new LibertyAttrValue(std::string(value)); +} + +class NoopLibertyVisitor : public LibertyGroupVisitor { +public: + void begin(const LibertyGroup *, LibertyGroup *) override {} + void end(const LibertyGroup *, LibertyGroup *) override {} + void visitAttr(const LibertySimpleAttr *) override {} + void visitAttr(const LibertyComplexAttr *) override {} + void visitVariable(LibertyVariable *) override {} +}; + +class RecordingLibertyVisitor : public LibertyGroupVisitor { +public: + ~RecordingLibertyVisitor() override + { + for (const LibertyGroup *group : root_groups) + delete group; + } + + void begin(const LibertyGroup *group, + LibertyGroup *parent_group) override + { + begin_count++; + if (parent_group == nullptr) + root_groups.push_back(group); + } + + void end(const LibertyGroup *, + LibertyGroup *) override + { + end_count++; + } + + void visitAttr(const LibertySimpleAttr *attr) override + { + simple_attrs.push_back(attr); + } + + void visitAttr(const LibertyComplexAttr *attr) override + { + complex_attrs.push_back(attr); + } + + void visitVariable(LibertyVariable *variable) override + { + variables.push_back(variable); + } + + int begin_count = 0; + int end_count = 0; + std::vector root_groups; + std::vector simple_attrs; + std::vector complex_attrs; + std::vector variables; +}; + // ---------- Library-level default attributes ---------- // R9_1: default_intrinsic_rise/fall @@ -1456,62 +1516,65 @@ TEST_F(StaLibertyTest, LeakagePowerConstruct) { } // R9_42: LibertyGroup isGroup and isVariable -#if 0 TEST_F(StaLibertyTest, LibertyStmtTypes) { - LibertyGroup grp("test", nullptr, 1); - EXPECT_TRUE(grp.isGroup()); - EXPECT_FALSE(grp.isVariable()); + LibertyAttrValueSeq params; + params.push_back(makeStringAttrValue("TEST")); + LibertyGroup grp("cell", std::move(params), 1); + EXPECT_EQ(grp.type(), "cell"); + EXPECT_EQ(grp.line(), 1); + ASSERT_NE(grp.firstName(), nullptr); + EXPECT_STREQ(grp.firstName(), "TEST"); + EXPECT_TRUE(grp.subgroups().empty()); } -#endif // R9_43: LibertySimpleAttr isComplex returns false -#if 0 TEST_F(StaLibertyTest, LibertySimpleAttrIsComplex) { - LibertyStringAttrValue *val = new LibertyStringAttrValue("test"); - LibertySimpleAttr attr("name", val, 1); - EXPECT_FALSE(attr.isComplexAttr()); - // isAttribute() returns false for LibertyAttr subclasses - EXPECT_FALSE(attr.isAttribute()); + LibertySimpleAttr attr("name", LibertyAttrValue(std::string("test")), 1); + EXPECT_EQ(attr.name(), "name"); + EXPECT_EQ(attr.line(), 1); + ASSERT_NE(attr.stringValue(), nullptr); + EXPECT_EQ(*attr.stringValue(), "test"); + EXPECT_TRUE(attr.value().isString()); } -#endif // R9_44: LibertyComplexAttr isSimple returns false -#if 0 TEST_F(StaLibertyTest, LibertyComplexAttrIsSimple) { - auto *values = new LibertyAttrValueSeq; - LibertyComplexAttr attr("name", values, 1); - EXPECT_FALSE(attr.isSimpleAttr()); - // isAttribute() returns false for LibertyAttr subclasses - EXPECT_FALSE(attr.isAttribute()); + LibertyAttrValueSeq values; + values.push_back(new LibertyAttrValue(1.0f)); + values.push_back(makeStringAttrValue("2.0")); + LibertyComplexAttr attr("name", std::move(values), 1); + ASSERT_NE(attr.firstValue(), nullptr); + EXPECT_TRUE(attr.firstValue()->isFloat()); + EXPECT_FLOAT_EQ(attr.firstValue()->floatValue(), 1.0f); + EXPECT_EQ(attr.values().size(), 2u); } -#endif // R9_45: LibertyStringAttrValue and LibertyFloatAttrValue type checks -#if 0 TEST_F(StaLibertyTest, AttrValueCrossType) { - // LibertyStringAttrValue normal usage - LibertyStringAttrValue sval("hello"); + LibertyAttrValue sval(std::string("hello")); EXPECT_TRUE(sval.isString()); EXPECT_FALSE(sval.isFloat()); EXPECT_EQ(sval.stringValue(), "hello"); + float parsed = 0.0f; + bool valid = true; + sval.floatValue(parsed, valid); + EXPECT_FALSE(valid); - // LibertyFloatAttrValue normal usage - LibertyFloatAttrValue fval(3.14f); + LibertyAttrValue fval(3.14f); EXPECT_FALSE(fval.isString()); EXPECT_TRUE(fval.isFloat()); EXPECT_FLOAT_EQ(fval.floatValue(), 3.14f); } -#endif // R9_46: LibertyDefine isDefine -#if 0 TEST_F(StaLibertyTest, LibertyDefineIsDefine) { LibertyDefine def("myattr", LibertyGroupType::cell, LibertyAttrType::attr_string, 1); - EXPECT_TRUE(def.isDefine()); - EXPECT_FALSE(def.isVariable()); + EXPECT_EQ(def.name(), "myattr"); + EXPECT_EQ(def.groupType(), LibertyGroupType::cell); + EXPECT_EQ(def.valueType(), LibertyAttrType::attr_string); + EXPECT_EQ(def.line(), 1); } -#endif // R9_47: scaled_cell group TEST_F(StaLibertyTest, ScaledCell) { @@ -1920,20 +1983,15 @@ TEST_F(StaLibertyTest, CheckTableModelCheckAxis) { } // R9_60: TimingGroup cell/transition/constraint getter coverage -#if 0 TEST_F(StaLibertyTest, TimingGroupGettersNull) { - TimingGroup tg(1); - // By default all model pointers should be null - EXPECT_EQ(tg.cell(RiseFall::rise()), nullptr); - EXPECT_EQ(tg.cell(RiseFall::fall()), nullptr); - EXPECT_EQ(tg.transition(RiseFall::rise()), nullptr); - EXPECT_EQ(tg.transition(RiseFall::fall()), nullptr); - EXPECT_EQ(tg.constraint(RiseFall::rise()), nullptr); - EXPECT_EQ(tg.constraint(RiseFall::fall()), nullptr); - EXPECT_EQ(tg.outputWaveforms(RiseFall::rise()), nullptr); - EXPECT_EQ(tg.outputWaveforms(RiseFall::fall()), nullptr); + TimingArcAttrs attrs; + EXPECT_EQ(attrs.model(RiseFall::rise()), nullptr); + EXPECT_EQ(attrs.model(RiseFall::fall()), nullptr); + EXPECT_EQ(attrs.cond(), nullptr); + EXPECT_TRUE(attrs.sdfCond().empty()); + EXPECT_TRUE(attrs.sdfCondStart().empty()); + EXPECT_TRUE(attrs.sdfCondEnd().empty()); } -#endif // R9_61: Timing with ecsm_waveform_set and ecsm_capacitance TEST_F(StaLibertyTest, EcsmWaveformSet) { @@ -2820,22 +2878,54 @@ library(test_r9_84) { } // R9_85: TimingGroup makeLinearModels coverage -#if 0 TEST_F(StaLibertyTest, TimingGroupLinearModels) { - TimingGroup tg(1); - tg.setIntrinsic(RiseFall::rise(), 0.05f); - tg.setIntrinsic(RiseFall::fall(), 0.06f); - tg.setResistance(RiseFall::rise(), 100.0f); - tg.setResistance(RiseFall::fall(), 120.0f); - // makeLinearModels needs a cell - but we can verify values are set - float val; - bool exists; - tg.intrinsic(RiseFall::rise(), val, exists); - EXPECT_TRUE(exists); - tg.resistance(RiseFall::fall(), val, exists); - EXPECT_TRUE(exists); + const char *content = R"( +library(test_r9_85) { + delay_model : generic_cmos ; + time_unit : "1ns" ; + voltage_unit : "1V" ; + current_unit : "1mA" ; + pulling_resistance_unit : "1kohm" ; + capacitive_load_unit(1, ff) ; + cell(LM2) { + area : 2.0 ; + pin(A) { direction : input ; capacitance : 0.01 ; } + pin(Z) { + direction : output ; + function : "A" ; + timing() { + related_pin : "A" ; + timing_sense : positive_unate ; + intrinsic_rise : 0.05 ; + intrinsic_fall : 0.06 ; + rise_resistance : 100.0 ; + fall_resistance : 120.0 ; + } + } + } +} +)"; + LibertyLibrary *lib = writeAndReadLibReturn(sta_, content); + ASSERT_NE(lib, nullptr); + LibertyCell *cell = lib->findLibertyCell("LM2"); + ASSERT_NE(cell, nullptr); + + bool found_linear_model = false; + for (TimingArcSet *arcset : cell->timingArcSets()) { + for (TimingArc *arc : arcset->arcs()) { + auto *model = dynamic_cast(arc->model()); + if (model) { + found_linear_model = true; + ArcDelay delay = 0.0; + Slew slew = 0.0; + model->gateDelay(nullptr, 0.0f, 0.5f, false, delay, slew); + EXPECT_GT(delay, 0.0f); + EXPECT_GE(model->driveResistance(nullptr), 100.0f); + } + } + } + EXPECT_TRUE(found_linear_model); } -#endif // R9_86: multiple wire_load and default_wire_load TEST_F(StaLibertyTest, DefaultWireLoad) { @@ -2963,37 +3053,54 @@ library(test_r9_89) { } // R9_90: TimingGroup set/get cell table models -#if 0 TEST_F(StaLibertyTest, TimingGroupCellModels) { - TimingGroup tg(1); - tg.setCell(RiseFall::rise(), nullptr); - tg.setCell(RiseFall::fall(), nullptr); - EXPECT_EQ(tg.cell(RiseFall::rise()), nullptr); - EXPECT_EQ(tg.cell(RiseFall::fall()), nullptr); + LibertyCell *cell = lib_->findLibertyCell("BUF_X1"); + ASSERT_NE(cell, nullptr); + TimingArcAttrs attrs; + auto *rise_model = new GateLinearModel(cell, 0.01f, 10.0f); + auto *fall_model = new GateLinearModel(cell, 0.02f, 12.0f); + attrs.setModel(RiseFall::rise(), rise_model); + attrs.setModel(RiseFall::fall(), fall_model); + EXPECT_EQ(attrs.model(RiseFall::rise()), rise_model); + EXPECT_EQ(attrs.model(RiseFall::fall()), fall_model); + EXPECT_FLOAT_EQ(static_cast(attrs.model(RiseFall::rise())) + ->driveResistance(nullptr), + 10.0f); } -#endif // R9_91: TimingGroup constraint setters -#if 0 TEST_F(StaLibertyTest, TimingGroupConstraintModels) { - TimingGroup tg(1); - tg.setConstraint(RiseFall::rise(), nullptr); - tg.setConstraint(RiseFall::fall(), nullptr); - EXPECT_EQ(tg.constraint(RiseFall::rise()), nullptr); - EXPECT_EQ(tg.constraint(RiseFall::fall()), nullptr); + LibertyCell *cell = lib_->findLibertyCell("DFF_X1"); + ASSERT_NE(cell, nullptr); + TimingArcAttrs attrs; + auto *rise_model = new CheckLinearModel(cell, 0.03f); + auto *fall_model = new CheckLinearModel(cell, 0.04f); + attrs.setModel(RiseFall::rise(), rise_model); + attrs.setModel(RiseFall::fall(), fall_model); + EXPECT_EQ(attrs.model(RiseFall::rise()), rise_model); + EXPECT_EQ(attrs.model(RiseFall::fall()), fall_model); + EXPECT_FLOAT_EQ(static_cast(attrs.model(RiseFall::fall())) + ->checkDelay(nullptr, 0.0f, 0.0f, 0.0f, false), + 0.04f); } -#endif // R9_92: TimingGroup transition setters -#if 0 TEST_F(StaLibertyTest, TimingGroupTransitionModels) { - TimingGroup tg(1); - tg.setTransition(RiseFall::rise(), nullptr); - tg.setTransition(RiseFall::fall(), nullptr); - EXPECT_EQ(tg.transition(RiseFall::rise()), nullptr); - EXPECT_EQ(tg.transition(RiseFall::fall()), nullptr); + LibertyCell *cell = lib_->findLibertyCell("BUF_X1"); + ASSERT_NE(cell, nullptr); + TimingArcAttrs attrs; + auto *rise_model = new GateLinearModel(cell, 0.05f, 7.0f); + attrs.setModel(RiseFall::rise(), rise_model); + ASSERT_EQ(attrs.model(RiseFall::rise()), rise_model); + EXPECT_EQ(attrs.model(RiseFall::fall()), nullptr); + + ArcDelay delay = 0.0; + Slew slew = 0.0; + static_cast(attrs.model(RiseFall::rise())) + ->gateDelay(nullptr, 0.0f, 0.2f, false, delay, slew); + EXPECT_GT(delay, 0.05f); + EXPECT_FLOAT_EQ(slew, 0.0f); } -#endif // R9_93: bus_naming_style attribute TEST_F(StaLibertyTest, BusNamingStyle) { @@ -3397,13 +3504,21 @@ library(test_r9_104) { } // R9_105: TimingGroup outputWaveforms accessors (should be null by default) -#if 0 TEST_F(StaLibertyTest, TimingGroupOutputWaveforms) { - TimingGroup tg(1); - EXPECT_EQ(tg.outputWaveforms(RiseFall::rise()), nullptr); - EXPECT_EQ(tg.outputWaveforms(RiseFall::fall()), nullptr); + LibertyCell *buf = lib_->findLibertyCell("BUF_X1"); + ASSERT_NE(buf, nullptr); + bool found_gate_table_model = false; + for (TimingArcSet *arcset : buf->timingArcSets()) { + for (TimingArc *arc : arcset->arcs()) { + auto *model = dynamic_cast(arc->model()); + if (model) { + found_gate_table_model = true; + EXPECT_EQ(model->outputWaveforms(), nullptr); + } + } + } + EXPECT_TRUE(found_gate_table_model); } -#endif // ========================================================================= // R11_ tests: Cover additional uncovered functions in liberty module @@ -3448,90 +3563,67 @@ TEST_F(StaLibertyTest, WriteLiberty) { // LibertyAttr, LibertySimpleAttr, LibertyComplexAttr, LibertyStringAttrValue, // LibertyFloatAttrValue, LibertyDefine, LibertyVariable, isGroup/isAttribute/ // isDefine/isVariable/isSimple/isComplex, and values() on simple attrs. -#if 0 TEST_F(StaLibertyTest, LibertyParserDirect) { - // Write a simple lib file for parser testing - const char *content = R"( -library(test_r11_parser) { - delay_model : table_lookup ; - time_unit : "1ns" ; - voltage_unit : "1V" ; - current_unit : "1mA" ; - capacitive_load_unit(1, ff) ; - define(my_attr, cell, string) ; - my_var = 3.14 ; - cell(P1) { - area : 1.0 ; - pin(A) { direction : input ; capacitance : 0.01 ; } - pin(Z) { direction : output ; function : "A" ; } - } -} -)"; - std::string tmp_path = makeUniqueTmpPath(); - writeLibContent(content, tmp_path); + RecordingLibertyVisitor visitor; + LibertyParser parser("test_r11_parser.lib", &visitor, sta_->report()); - // Parse with a simple visitor that just collects groups - Report *report = sta_->report(); - // Use parseLibertyFile which creates the parser internally - // This exercises LibertyParser constructor, LibertyScanner, - // group(), deleteGroups() - class TestVisitor : public LibertyGroupVisitor { - public: - int group_count = 0; - int attr_count = 0; - int var_count = 0; - void begin(LibertyGroup *group) override { group_count++; } - void end(LibertyGroup *) override {} - void visitAttr(LibertyAttr *attr) override { - attr_count++; - // Exercise isSimple, isComplex, values() - // isAttribute() returns false for LibertyAttr subclasses - EXPECT_FALSE(attr->isAttribute()); - EXPECT_FALSE(attr->isGroup()); - EXPECT_FALSE(attr->isDefine()); - EXPECT_FALSE(attr->isVariable()); - if (attr->isSimpleAttr()) { - EXPECT_FALSE(attr->isComplexAttr()); - // Simple attrs have firstValue but values() is not supported - } - if (attr->isComplexAttr()) { - EXPECT_FALSE(attr->isSimpleAttr()); - } - // Exercise firstValue - LibertyAttrValue *val = attr->firstValue(); - if (val) { - if (val->isString()) { - EXPECT_FALSE(val->stringValue().empty()); - EXPECT_FALSE(val->isFloat()); - } - if (val->isFloat()) { - EXPECT_FALSE(val->isString()); - EXPECT_FALSE(std::isinf(val->floatValue())); - } - } - } - void visitVariable(LibertyVariable *variable) override { - var_count++; - EXPECT_TRUE(variable->isVariable()); - EXPECT_FALSE(variable->isGroup()); - EXPECT_FALSE(variable->isAttribute()); - EXPECT_FALSE(variable->isDefine()); - EXPECT_FALSE(variable->variable().empty()); - EXPECT_FALSE(std::isinf(variable->value())); - } - bool save(LibertyGroup *) override { return false; } - bool save(LibertyAttr *) override { return false; } - bool save(LibertyVariable *) override { return false; } - }; + auto *lib_params = new LibertyAttrValueSeq; + lib_params->push_back(parser.makeAttrValueString("test_r11_parser")); + parser.groupBegin("library", lib_params, 1); + parser.makeSimpleAttr("delay_model", + parser.makeAttrValueString("table_lookup"), + 2); + parser.makeSimpleAttr("time_unit", + parser.makeAttrValueString("1ns"), + 3); + auto *define_values = new LibertyAttrValueSeq; + define_values->push_back(parser.makeAttrValueString("my_attr")); + define_values->push_back(parser.makeAttrValueString("cell")); + define_values->push_back(parser.makeAttrValueString("string")); + parser.makeComplexAttr("define", define_values, 4); + parser.makeVariable("my_var", 3.14f, 5); - TestVisitor visitor; - parseLibertyFile(tmp_path.c_str(), &visitor, report); - EXPECT_GT(visitor.group_count, 0); - EXPECT_GT(visitor.attr_count, 0); - EXPECT_GT(visitor.var_count, 0); - remove(tmp_path.c_str()); + auto *cell_params = new LibertyAttrValueSeq; + cell_params->push_back(parser.makeAttrValueString("P1")); + parser.groupBegin("cell", cell_params, 6); + parser.makeSimpleAttr("area", parser.makeAttrValueFloat(1.0f), 7); + auto *complex_values = new LibertyAttrValueSeq; + complex_values->push_back(parser.makeAttrValueFloat(0.01f)); + complex_values->push_back(parser.makeAttrValueFloat(0.02f)); + parser.makeComplexAttr("values", complex_values, 8); + LibertyGroup *cell = parser.groupEnd(); + LibertyGroup *library = parser.groupEnd(); + + EXPECT_EQ(visitor.begin_count, 2); + EXPECT_EQ(visitor.end_count, 2); + ASSERT_EQ(visitor.root_groups.size(), 1u); + EXPECT_EQ(visitor.root_groups.front(), library); + EXPECT_EQ(visitor.simple_attrs.size(), 3u); + EXPECT_EQ(visitor.complex_attrs.size(), 1u); + EXPECT_EQ(visitor.variables.size(), 1u); + + ASSERT_NE(library->firstName(), nullptr); + EXPECT_STREQ(library->firstName(), "test_r11_parser"); + EXPECT_EQ(library->defineMap().size(), 1u); + EXPECT_EQ(library->findSubgroup("cell"), cell); + float area = 0.0f; + bool exists = false; + cell->findAttrFloat("area", area, exists); + EXPECT_TRUE(exists); + EXPECT_FLOAT_EQ(area, 1.0f); + ASSERT_NE(cell->findComplexAttr("values"), nullptr); + EXPECT_EQ(cell->findComplexAttr("values")->values().size(), 2u); + EXPECT_EQ(visitor.variables[0]->variable(), "my_var"); + EXPECT_FLOAT_EQ(visitor.variables[0]->value(), 3.14f); + + NoopLibertyVisitor cleanup_visitor; + LibertyParser cleanup_parser("cleanup.lib", &cleanup_visitor, sta_->report()); + auto *cleanup_params = new LibertyAttrValueSeq; + cleanup_params->push_back(cleanup_parser.makeAttrValueString("cleanup")); + cleanup_parser.groupBegin("library", cleanup_params, 1); + cleanup_parser.groupBegin("cell", new LibertyAttrValueSeq, 2); + cleanup_parser.deleteGroups(); } -#endif // R11_4: Liberty file with wireload_selection to cover WireloadForArea TEST_F(StaLibertyTest, WireloadForArea) { @@ -3978,7 +4070,6 @@ library(test_r11_intport) { // R11_15: Directly test LibertyParser API through parseLibertyFile // Focus on saving attrs/variables/groups to exercise more code paths -#if 0 TEST_F(StaLibertyTest, ParserSaveAll) { const char *content = R"( library(test_r11_save) { @@ -3999,43 +4090,27 @@ library(test_r11_save) { std::string tmp_path = makeUniqueTmpPath(); writeLibContent(content, tmp_path); - // Visitor that saves everything - class SaveVisitor : public LibertyGroupVisitor { - public: - int group_begin_count = 0; - int group_end_count = 0; - int define_count = 0; - int var_count = 0; - void begin(LibertyGroup *group) override { - group_begin_count++; - EXPECT_TRUE(group->isGroup()); - EXPECT_FALSE(group->isAttribute()); - EXPECT_FALSE(group->isVariable()); - EXPECT_FALSE(group->isDefine()); - EXPECT_FALSE(group->type().empty()); - } - void end(LibertyGroup *) override { group_end_count++; } - void visitAttr(LibertyAttr *attr) override { - // Check isDefine virtual dispatch - if (attr->isDefine()) - define_count++; - } - void visitVariable(LibertyVariable *var) override { - var_count++; - } - bool save(LibertyGroup *) override { return true; } - bool save(LibertyAttr *) override { return true; } - bool save(LibertyVariable *) override { return true; } - }; + RecordingLibertyVisitor visitor; + parseLibertyFile(tmp_path.c_str(), &visitor, sta_->report()); - Report *report = sta_->report(); - SaveVisitor visitor; - parseLibertyFile(tmp_path.c_str(), &visitor, report); - EXPECT_GT(visitor.group_begin_count, 0); - EXPECT_EQ(visitor.group_begin_count, visitor.group_end_count); - remove(tmp_path.c_str()); + EXPECT_GT(visitor.begin_count, 0); + EXPECT_EQ(visitor.begin_count, visitor.end_count); + ASSERT_EQ(visitor.root_groups.size(), 1u); + const LibertyGroup *library = visitor.root_groups.front(); + ASSERT_NE(library, nullptr); + EXPECT_EQ(library->defineMap().size(), 1u); + EXPECT_EQ(visitor.variables.size(), 1u); + EXPECT_GT(visitor.simple_attrs.size(), 0u); + + const LibertyGroup *cell = library->findSubgroup("cell"); + ASSERT_NE(cell, nullptr); + float area = 0.0f; + bool exists = false; + cell->findAttrFloat("area", area, exists); + EXPECT_TRUE(exists); + EXPECT_FLOAT_EQ(area, 1.0f); + EXPECT_EQ(remove(tmp_path.c_str()), 0); } -#endif // R11_16: Exercises clearAxisValues and setEnergyScale through internal_power // with energy values diff --git a/sdc/test/sdc_clock_groups_sense.tcl b/sdc/test/sdc_clock_groups_sense.tcl index 7e164489..47930f97 100644 --- a/sdc/test/sdc_clock_groups_sense.tcl +++ b/sdc/test/sdc_clock_groups_sense.tcl @@ -177,7 +177,7 @@ set_clock_uncertainty -from [get_clocks clk2] -to [get_clocks clk1] -hold 0.12 # Write SDC with all uncertainty set sdc_file7 [make_result_file sdc_clk_uncert.sdc] write_sdc -no_timestamp $sdc_file7 -diff_files sdc_clk_uncert.sdcok $sdc_file7 +diff_files_sorted sdc_clk_uncert.sdcok $sdc_file7 # Remove inter-clock uncertainty unset_clock_uncertainty -from [get_clocks clk1] -to [get_clocks clk2] -setup