3
0
Fork 0
mirror of https://github.com/YosysHQ/yosys synced 2026-07-15 03:35:40 +00:00
yosys/tests/unit/kernel/twinePublicityTest.cc
2026-06-24 11:51:01 +02:00

132 lines
3.8 KiB
C++

#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