unit tests: twines

This commit is contained in:
Emil J. Tywoniak 2026-06-24 11:51:01 +02:00
parent c93f60f6af
commit 9ae4717502
10 changed files with 187 additions and 31 deletions

View File

@ -3,6 +3,7 @@
#include "kernel/yosys_common.h"
#include "kernel/celltypes.h"
#include "kernel/newcelltypes.h"
#include "tests/unit/yosysSetupEnv.h"
#include <unordered_set>

View File

@ -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());
}

View File

@ -4,6 +4,7 @@
#include <gtest/gtest.h>
#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<Wire*> createWires(int count, int width = 4) {
std::vector<Wire*> 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;

View File

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

View File

@ -1,5 +1,6 @@
#include <gtest/gtest.h>
#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<Module> mod = std::make_unique<Module>();
Wire *wire = mod->addWire(ID(test), 10);
std::unique_ptr<Design> design = std::make_unique<Design>();
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();

View File

@ -12,7 +12,7 @@ namespace RTLIL {
std::vector<Wire*> 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));

View File

@ -1,6 +1,7 @@
#include <gtest/gtest.h>
#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<Wire*> createWires(int count, int width = 4) {
std::vector<Wire*> 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

View File

@ -0,0 +1,132 @@
#include <gtest/gtest.h>
#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<TwineRef> 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

View File

@ -1,5 +1,6 @@
#include <gtest/gtest.h>
#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 {

View File

@ -0,0 +1,16 @@
#ifndef YOSYS_SETUP_ENV_H
#define YOSYS_SETUP_ENV_H
#include <gtest/gtest.h>
#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 */