Enable disabled liberty tests and stabilize clock groups regression

Signed-off-by: Jaehyun Kim <jhkim@precisioninno.com>
This commit is contained in:
Jaehyun Kim 2026-03-11 18:24:39 +09:00
parent 2d2a275ab9
commit a4419fb7dd
3 changed files with 405 additions and 363 deletions

View File

@ -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)

View File

@ -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<const LibertyGroup *> root_groups;
std::vector<const LibertySimpleAttr *> simple_attrs;
std::vector<const LibertyComplexAttr *> complex_attrs;
std::vector<LibertyVariable *> 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<GateLinearModel *>(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<GateLinearModel *>(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<CheckLinearModel *>(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<GateLinearModel *>(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<GateTableModel *>(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

View File

@ -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