From 9ae4717502238703d6a612ace9a93c78ffb16de1 Mon Sep 17 00:00:00 2001 From: "Emil J. Tywoniak" Date: Wed, 24 Jun 2026 11:51:01 +0200 Subject: [PATCH] unit tests: twines --- tests/unit/kernel/cellTypesTest.cc | 1 + tests/unit/kernel/modindexTest.cc | 19 +-- tests/unit/kernel/rtlilHelpers.h | 5 +- tests/unit/kernel/rtlilStringTest.cc | 17 +-- tests/unit/kernel/rtlilTest.cc | 6 +- tests/unit/kernel/sigspecExtractTest.cc | 4 +- tests/unit/kernel/sigspecRemove2Test.cc | 7 +- tests/unit/kernel/twinePublicityTest.cc | 132 ++++++++++++++++++ .../opt/optDffFindComplementaryPatternTest.cc | 11 +- tests/unit/yosysSetupEnv.h | 16 +++ 10 files changed, 187 insertions(+), 31 deletions(-) create mode 100644 tests/unit/kernel/twinePublicityTest.cc create mode 100644 tests/unit/yosysSetupEnv.h diff --git a/tests/unit/kernel/cellTypesTest.cc b/tests/unit/kernel/cellTypesTest.cc index 9cde0ffd3..bb4ce4baf 100644 --- a/tests/unit/kernel/cellTypesTest.cc +++ b/tests/unit/kernel/cellTypesTest.cc @@ -3,6 +3,7 @@ #include "kernel/yosys_common.h" #include "kernel/celltypes.h" #include "kernel/newcelltypes.h" +#include "tests/unit/yosysSetupEnv.h" #include diff --git a/tests/unit/kernel/modindexTest.cc b/tests/unit/kernel/modindexTest.cc index 6c9529511..bbd6963e6 100644 --- a/tests/unit/kernel/modindexTest.cc +++ b/tests/unit/kernel/modindexTest.cc @@ -2,19 +2,20 @@ #include "kernel/modtools.h" #include "kernel/rtlil.h" +#include "tests/unit/yosysSetupEnv.h" YOSYS_NAMESPACE_BEGIN TEST(ModIndexSwapTest, has) { Design* d = new Design; - Module* m = d->addModule("$m"); - Wire* o = m->addWire("$o", 2); + Module* m = d->addModule(d->twines.add(std::string{"$m"})); + Wire* o = m->addWire(d->twines.add(std::string{"$o"}), 2); o->port_input = true; - Wire* i = m->addWire("$i", 2); + Wire* i = m->addWire(d->twines.add(std::string{"$i"}), 2); i->port_input = true; m->fixup_ports(); - m->addNot("$not", i, o); + m->addNot(Twine{std::string{"$not"}}, i, o); auto mi = ModIndex(m); mi.reload_module(); for (auto [sb, info] : mi.database) { @@ -30,16 +31,16 @@ TEST(ModIndexDeleteTest, has) { if (log_files.empty()) log_files.emplace_back(stdout); Design* d = new Design; - Module* m = d->addModule("$m"); - Wire* w = m->addWire("$w"); - Wire* o = m->addWire("$o"); + Module* m = d->addModule(d->twines.add(std::string{"$m"})); + Wire* w = m->addWire(d->twines.add(std::string{"$w"})); + Wire* o = m->addWire(d->twines.add(std::string{"$o"})); o->port_output = true; m->fixup_ports(); - Cell* not_ = m->addNotGate("$not", w, o); + Cell* not_ = m->addNotGate(Twine{std::string{"$not"}}, w, o); auto mi = ModIndex(m); mi.reload_module(); mi.dump_db(); - Wire* a = m->addWire("\\a"); + Wire* a = m->addWire(d->twines.add(std::string{"\\a"})); not_->setPort(TW::A, a); EXPECT_TRUE(mi.ok()); } diff --git a/tests/unit/kernel/rtlilHelpers.h b/tests/unit/kernel/rtlilHelpers.h index 99585f23b..8cb3f8f27 100644 --- a/tests/unit/kernel/rtlilHelpers.h +++ b/tests/unit/kernel/rtlilHelpers.h @@ -4,6 +4,7 @@ #include #include "kernel/rtlil.h" +#include "tests/unit/yosysSetupEnv.h" YOSYS_NAMESPACE_BEGIN @@ -14,7 +15,7 @@ protected: void SetUp() override { d = new Design; - m = d->addModule("$test"); + m = d->addModule(d->twines.add(std::string{"$test"})); } void TearDown() override { @@ -25,7 +26,7 @@ protected: std::vector createWires(int count, int width = 4) { std::vector wires; for (int i = 0; i < count; i++) { - Wire* w = m->addWire(stringf("$w%d", i), width); + Wire* w = m->addWire(d->twines.add(std::string{stringf("$w%d", i)}), width); wires.push_back(w); } return wires; diff --git a/tests/unit/kernel/rtlilStringTest.cc b/tests/unit/kernel/rtlilStringTest.cc index 26b296dd4..9c8763a61 100644 --- a/tests/unit/kernel/rtlilStringTest.cc +++ b/tests/unit/kernel/rtlilStringTest.cc @@ -2,6 +2,7 @@ #include "kernel/rtlil.h" #include "kernel/yosys.h" +#include "tests/unit/yosysSetupEnv.h" YOSYS_NAMESPACE_BEGIN @@ -9,8 +10,8 @@ namespace RTLIL { TEST(RtlilStrTest, DesignToString) { Design design; - Module *mod = design.addModule(ID(my_module)); - mod->addWire(ID(my_wire), 1); + Module *mod = design.addModule(design.twines.add(std::string{"\\my_module"})); + mod->addWire(design.twines.add(std::string{"\\my_wire"}), 1); std::string design_str = design.to_rtlil_str(); @@ -20,8 +21,8 @@ namespace RTLIL { TEST(RtlilStrTest, ModuleToString) { Design design; - Module *mod = design.addModule(ID(test_mod)); - Wire *wire = mod->addWire(ID(clk), 1); + Module *mod = design.addModule(design.twines.add(std::string{"\\test_mod"})); + Wire *wire = mod->addWire(design.twines.add(std::string{"\\clk"}), 1); wire->port_input = true; std::string mod_str = mod->to_rtlil_str(); @@ -34,8 +35,8 @@ namespace RTLIL { TEST(RtlilStrTest, WireToString) { Design design; - Module *mod = design.addModule(ID(m)); - Wire *wire = mod->addWire(ID(data), 8); + Module *mod = design.addModule(design.twines.add(std::string{"\\m"})); + Wire *wire = mod->addWire(design.twines.add(std::string{"\\data"}), 8); std::string wire_str = wire->to_rtlil_str(); @@ -46,8 +47,8 @@ namespace RTLIL { TEST(RtlilStrTest, CellToString) { Design design; - Module *mod = design.addModule(ID(m)); - Cell *cell = mod->addCell(ID(u1), ID(my_cell_type)); + Module *mod = design.addModule(design.twines.add(std::string{"\\m"})); + Cell *cell = mod->addCell(design.twines.add(std::string{"\\u1"}), design.twines.add(std::string{"\\my_cell_type"})); std::string cell_str = cell->to_rtlil_str(); diff --git a/tests/unit/kernel/rtlilTest.cc b/tests/unit/kernel/rtlilTest.cc index 32c40616e..dd86bb504 100644 --- a/tests/unit/kernel/rtlilTest.cc +++ b/tests/unit/kernel/rtlilTest.cc @@ -1,5 +1,6 @@ #include #include "kernel/rtlil.h" +#include "tests/unit/yosysSetupEnv.h" YOSYS_NAMESPACE_BEGIN @@ -417,8 +418,9 @@ namespace RTLIL { ); TEST_P(WireRtlVsHdlIndexConversionTest, WireRtlVsHdlIndexConversion) { - std::unique_ptr mod = std::make_unique(); - Wire *wire = mod->addWire(ID(test), 10); + std::unique_ptr design = std::make_unique(); + Module *mod = design->addModule(design->twines.add(std::string{"$test_mod"})); + Wire *wire = mod->addWire(design->twines.add(std::string{"\\test"}), 10); auto [upto, start_offset, width] = GetParam(); diff --git a/tests/unit/kernel/sigspecExtractTest.cc b/tests/unit/kernel/sigspecExtractTest.cc index 87bd4f6da..de67ae14a 100644 --- a/tests/unit/kernel/sigspecExtractTest.cc +++ b/tests/unit/kernel/sigspecExtractTest.cc @@ -12,7 +12,7 @@ namespace RTLIL { std::vector wires; SigSpec sig; for (int i = 0; i < 4; i++) - wires.push_back(m->addWire(stringf("$w%d", i), 4)); + wires.push_back(m->addWire(d->twines.add(std::string{stringf("$w%d", i)}), 4)); for (auto w : wires) sig.append(w); @@ -49,7 +49,7 @@ namespace RTLIL { { SigSpec sig; sig.append(Const(0, 4)); - Wire* w = m->addWire("$foo", 4); + Wire* w = m->addWire(d->twines.add(std::string{"$foo"}), 4); sig.append(w); sig.append(Const(15, 4)); diff --git a/tests/unit/kernel/sigspecRemove2Test.cc b/tests/unit/kernel/sigspecRemove2Test.cc index 9d7bf4863..bf7a5857a 100644 --- a/tests/unit/kernel/sigspecRemove2Test.cc +++ b/tests/unit/kernel/sigspecRemove2Test.cc @@ -1,6 +1,7 @@ #include #include "kernel/rtlil.h" +#include "tests/unit/yosysSetupEnv.h" YOSYS_NAMESPACE_BEGIN @@ -12,7 +13,7 @@ protected: void SetUp() override { d = new Design; - m = d->addModule("$test"); + m = d->addModule(d->twines.add(std::string{"$test"})); } void TearDown() override { @@ -23,7 +24,7 @@ protected: std::vector createWires(int count, int width = 4) { std::vector wires; for (int i = 0; i < count; i++) { - Wire* w = m->addWire(stringf("$w%d", i), width); + Wire* w = m->addWire(d->twines.add(std::string{stringf("$w%d", i)}), width); wires.push_back(w); } return wires; @@ -311,7 +312,7 @@ TEST_F(SigSpecRepTest, NullWireBitsStay) TEST_F(SigSpecRepTest, PartialBitRemoval) { - Wire* w = m->addWire("$w1", 8); + Wire* w = m->addWire(d->twines.add(std::string{"$w1"}), 8); SigSpec sig(w); // Remove bits 2-5 diff --git a/tests/unit/kernel/twinePublicityTest.cc b/tests/unit/kernel/twinePublicityTest.cc new file mode 100644 index 000000000..8cae12329 --- /dev/null +++ b/tests/unit/kernel/twinePublicityTest.cc @@ -0,0 +1,132 @@ +#include + +#include "kernel/rtlil.h" +#include "kernel/yosys.h" +#include "tests/unit/yosysSetupEnv.h" + +YOSYS_NAMESPACE_BEGIN + +TEST(TwinePublicityTest, LeafEscapeParsing) +{ + TwinePool pool; + TwineRef pub = pool.add(std::string("\\foo")); + TwineRef priv = pool.add(std::string("$foo")); + + EXPECT_TRUE(twine_is_public(pub)); + EXPECT_FALSE(twine_is_public(priv)); + EXPECT_EQ(pool.str(pub), "\\foo"); + EXPECT_EQ(pool.unescaped_str(pub), "foo"); + EXPECT_EQ(pool.str(priv), "$foo"); + EXPECT_EQ(pool.unescaped_str(priv), "$foo"); +} + +TEST(TwinePublicityTest, EscapedDollarStaysDistinct) +{ + // Verilog escaped identifier `\$foo` (public, content "$foo") must not + // collide with the private name `$foo` as a dict key. + TwinePool pool; + TwineRef pub = pool.add(std::string("\\$foo")); + TwineRef priv = pool.add(std::string("$foo")); + + EXPECT_EQ(twine_untag(pub), twine_untag(priv)); // shared content node + EXPECT_NE(pub, priv); // distinct handles + EXPECT_EQ(pool.str(pub), "\\$foo"); + EXPECT_EQ(pool.str(priv), "$foo"); +} + +TEST(TwinePublicityTest, InterningIsStableAcrossTags) +{ + TwinePool pool; + TwineRef a = pool.add(std::string("\\foo")); + TwineRef b = pool.add(std::string("\\foo")); + EXPECT_EQ(a, b); +} + +TEST(TwinePublicityTest, SuffixInheritsPublicity) +{ + TwinePool pool; + TwineRef pub = pool.add(std::string("\\base")); + TwineRef priv = pool.add(std::string("$base")); + + TwineRef pub_sfx = pool.add(Twine{Twine::Suffix{pub, "_1"}}); + TwineRef priv_sfx = pool.add(Twine{Twine::Suffix{priv, "_1"}}); + + EXPECT_TRUE(twine_is_public(pub_sfx)); + EXPECT_FALSE(twine_is_public(priv_sfx)); + EXPECT_EQ(pool.str(pub_sfx), "\\base_1"); + EXPECT_EQ(pool.str(priv_sfx), "$base_1"); +} + +TEST(TwinePublicityTest, StaticHandlesAreTagged) +{ + TwinePool pool; + EXPECT_TRUE(twine_is_public(TW::A)); + EXPECT_EQ(pool.str(TW::A), "\\A"); + EXPECT_EQ(pool.unescaped_str(TW::A), "A"); + EXPECT_FALSE(twine_is_public(TW::$and)); + EXPECT_EQ(pool.str(TW::$and), "$and"); +} + +TEST(TwinePublicityTest, LookupReturnsTaggedHandle) +{ + TwinePool pool; + TwineRef pub = pool.add(std::string("\\net")); + TwineRef priv = pool.add(std::string("$net")); + + TwineSearch search(&pool); + EXPECT_EQ(search.find("\\net"), pub); + EXPECT_EQ(search.find("$net"), priv); + EXPECT_EQ(search.find("\\A"), TW::A); + EXPECT_EQ(search.find("\\nonexistent"), Twine::Null); +} + +TEST(TwinePublicityTest, CopyFromPreservesTag) +{ + TwinePool src, dst; + TwineRef pub = src.add(std::string("\\xfer")); + TwineRef copied = dst.copy_from(src, pub); + EXPECT_TRUE(twine_is_public(copied)); + EXPECT_EQ(dst.str(copied), "\\xfer"); + // Static handles pass through tag and all. + EXPECT_EQ(dst.copy_from(src, TW::A), TW::A); +} + +TEST(TwinePublicityTest, GcKeepsTaggedRoots) +{ + TwinePool pool; + TwineRef pub = pool.add(std::string("\\keep")); + pool.add(std::string("\\drop")); + std::vector roots{pub}; + EXPECT_EQ(pool.gc(roots), 1u); + EXPECT_EQ(pool.str(pub), "\\keep"); +} + +TEST(TwinePublicityTest, WireNameMasquerade) +{ + RTLIL::Design design; + RTLIL::Module *mod = design.addModule(design.twines.add(std::string("\\top"))); + + RTLIL::Wire *pub = mod->addWire(design.twines.add(std::string("\\sig"))); + RTLIL::Wire *priv = mod->addWire(design.twines.add(std::string("$sig"))); + + EXPECT_TRUE(pub->name.isPublic()); + EXPECT_FALSE(priv->name.isPublic()); + EXPECT_EQ(pub->name.escaped(), "\\sig"); + EXPECT_EQ(pub->name.unescaped(), "sig"); + EXPECT_EQ(pub->name.str(), "\\sig"); + EXPECT_EQ(priv->name.escaped(), "$sig"); + EXPECT_EQ(priv->name.unescaped(), "$sig"); + + // Distinct dict keys despite shared content. + EXPECT_NE(pub, priv); + TwineSearch search(&design.twines); + EXPECT_EQ(mod->wire(search.find("\\sig")), pub); + EXPECT_EQ(mod->wire(search.find("$sig")), priv); + + // uniquify keeps publicity. + TwineRef uniq = mod->uniquify(pub->meta_->name); + EXPECT_TRUE(twine_is_public(uniq)); + EXPECT_EQ(design.twines.str(uniq), "\\sig_1"); +} + +YOSYS_NAMESPACE_END diff --git a/tests/unit/opt/optDffFindComplementaryPatternTest.cc b/tests/unit/opt/optDffFindComplementaryPatternTest.cc index 7a89da6cd..c6e3451a1 100644 --- a/tests/unit/opt/optDffFindComplementaryPatternTest.cc +++ b/tests/unit/opt/optDffFindComplementaryPatternTest.cc @@ -1,5 +1,6 @@ #include #include "kernel/pattern.h" +#include "tests/unit/yosysSetupEnv.h" YOSYS_NAMESPACE_BEGIN @@ -14,11 +15,11 @@ protected: void SetUp() override { design = new RTLIL::Design; - module = design->addModule(ID(test_module)); - wire_a = module->addWire(ID(a)); - wire_b = module->addWire(ID(b)); - wire_c = module->addWire(ID(c)); - bus = module->addWire(ID(bus), 4); + module = design->addModule(design->twines.add(std::string{"\\test_module"})); + wire_a = module->addWire(design->twines.add(std::string{"\\a"})); + wire_b = module->addWire(design->twines.add(std::string{"\\b"})); + wire_c = module->addWire(design->twines.add(std::string{"\\c"})); + bus = module->addWire(design->twines.add(std::string{"\\bus"}), 4); } void TearDown() override { diff --git a/tests/unit/yosysSetupEnv.h b/tests/unit/yosysSetupEnv.h new file mode 100644 index 000000000..5cb58b7c2 --- /dev/null +++ b/tests/unit/yosysSetupEnv.h @@ -0,0 +1,16 @@ +#ifndef YOSYS_SETUP_ENV_H +#define YOSYS_SETUP_ENV_H + +#include + +#include "kernel/yosys.h" + +namespace { + struct YosysSetupEnvironment : ::testing::Environment { + void SetUp() override { Yosys::yosys_setup(); } + }; + const ::testing::Environment *yosys_setup_env = + ::testing::AddGlobalTestEnvironment(new YosysSetupEnvironment); +} + +#endif /* YOSYS_SETUP_ENV_H */