mirror of
https://github.com/YosysHQ/yosys
synced 2025-09-11 20:21:26 +00:00
439 lines
10 KiB
C++
439 lines
10 KiB
C++
#include <gtest/gtest.h>
|
|
#include "kernel/rtlil.h"
|
|
|
|
YOSYS_NAMESPACE_BEGIN
|
|
|
|
namespace RTLIL {
|
|
|
|
struct SafePrintToStringParamName {
|
|
template <class ParamType>
|
|
std::string operator()(const testing::TestParamInfo<ParamType>& info) const {
|
|
std::string name = testing::PrintToString(info.param);
|
|
for (auto &c : name)
|
|
if (!('0' <= c && c <= '9') && !('a' <= c && c <= 'z') && !('A' <= c && c <= 'Z') ) c = '_';
|
|
return name;
|
|
}
|
|
};
|
|
|
|
class KernelRtlilTest : public testing::Test {
|
|
protected:
|
|
KernelRtlilTest() {
|
|
if (log_files.empty()) log_files.emplace_back(stdout);
|
|
}
|
|
};
|
|
|
|
TEST_F(KernelRtlilTest, ConstAssignCompare)
|
|
{
|
|
Const c1;
|
|
Const c2;
|
|
c2 = c1;
|
|
Const c3(c2);
|
|
EXPECT_TRUE(c2 == c3);
|
|
EXPECT_FALSE(c2 < c3);
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstStr) {
|
|
// We have multiple distinct sections since it's annoying
|
|
// to list multiple testcases as friends of Const in kernel/rtlil.h
|
|
{
|
|
std::string foo = "foo";
|
|
Const c1 = foo;
|
|
Const c2;
|
|
c2 = c1;
|
|
Const c3(c2);
|
|
EXPECT_TRUE(c1.is_str());
|
|
EXPECT_TRUE(c2.is_str());
|
|
EXPECT_TRUE(c3.is_str());
|
|
}
|
|
|
|
{
|
|
// A binary constant is bitvec backed
|
|
Const cb1(0, 10);
|
|
Const cb2(1, 10);
|
|
Const cb3(cb2);
|
|
std::vector<bool> v1 {false, true};
|
|
std::vector<State> v2 {State::S0, State::S1};
|
|
Const cb4(v1);
|
|
Const cb5(v2);
|
|
EXPECT_TRUE(cb4 == cb5);
|
|
EXPECT_TRUE(cb1.is_bits());
|
|
EXPECT_TRUE(cb2.is_bits());
|
|
EXPECT_TRUE(cb3.is_bits());
|
|
EXPECT_TRUE(cb4.is_bits());
|
|
EXPECT_TRUE(cb5.is_bits());
|
|
EXPECT_EQ(cb1.size(), 10);
|
|
EXPECT_EQ(cb2.size(), 10);
|
|
EXPECT_EQ(cb3.size(), 10);
|
|
}
|
|
|
|
{
|
|
// A string constructed Const starts off packed
|
|
std::string foo = "foo";
|
|
Const cs1 = foo;
|
|
EXPECT_TRUE(cs1.is_str());
|
|
|
|
// It can be iterated without mutating
|
|
int i = 0;
|
|
for (auto bit : cs1) {
|
|
i += bit;
|
|
}
|
|
EXPECT_EQ(i, 16);
|
|
EXPECT_TRUE(cs1.is_str());
|
|
|
|
// It can be mutated via bit iteration and decays into unpacked
|
|
// when an non-defined bit is set.
|
|
for (auto b : cs1) {
|
|
b = State::Sx;
|
|
}
|
|
EXPECT_TRUE(cs1.is_bits());
|
|
}
|
|
|
|
{
|
|
Const c(0x12345678);
|
|
EXPECT_TRUE(c.is_str());
|
|
EXPECT_EQ(c.as_int(), 0x12345678);
|
|
EXPECT_TRUE(c.is_str());
|
|
}
|
|
|
|
{
|
|
Const c(0xab, 8);
|
|
EXPECT_TRUE(c.is_str());
|
|
EXPECT_EQ(c.as_int(), 0xab);
|
|
EXPECT_TRUE(c.is_str());
|
|
}
|
|
|
|
{
|
|
Const c(0x12345678, 80);
|
|
EXPECT_TRUE(c.is_str());
|
|
EXPECT_EQ(c.as_int(), 0x12345678);
|
|
EXPECT_EQ(c[79], S0);
|
|
EXPECT_TRUE(c.is_str());
|
|
}
|
|
|
|
{
|
|
Const c(-1, 80);
|
|
EXPECT_TRUE(c.is_str());
|
|
EXPECT_EQ(c.as_int(), -1);
|
|
EXPECT_EQ(c[79], S1);
|
|
EXPECT_TRUE(c.is_str());
|
|
}
|
|
|
|
{
|
|
Const c(1 << 24);
|
|
EXPECT_TRUE(c.is_str());
|
|
EXPECT_TRUE(c.as_bool());
|
|
EXPECT_TRUE(c.is_str());
|
|
}
|
|
|
|
{
|
|
Const c(0x2, 8);
|
|
EXPECT_TRUE(c.is_str());
|
|
EXPECT_EQ(c.as_string(), "00000010");
|
|
EXPECT_TRUE(c.is_str());
|
|
}
|
|
|
|
{
|
|
Const c(" ");
|
|
EXPECT_TRUE(c.is_str());
|
|
EXPECT_EQ(c.decode_string(), " ");
|
|
EXPECT_TRUE(c.is_str());
|
|
}
|
|
|
|
{
|
|
Const c(" ");
|
|
EXPECT_TRUE(c.is_str());
|
|
EXPECT_EQ(c.decode_string(), " ");
|
|
EXPECT_TRUE(c.is_str());
|
|
}
|
|
|
|
{
|
|
std::vector<State> v = {S0, S0, S0, S0, S0, S1, S0, S0};
|
|
Const c(v);
|
|
EXPECT_EQ(c.decode_string(), " ");
|
|
}
|
|
|
|
{
|
|
std::vector<State> v = {S0, S0, S0, S0, S0, S1, S0, Sx};
|
|
Const c(v);
|
|
EXPECT_EQ(c.decode_string(), " ");
|
|
}
|
|
|
|
{
|
|
Const c(" ");
|
|
EXPECT_TRUE(c.is_str());
|
|
EXPECT_FALSE(c.is_fully_zero());
|
|
EXPECT_TRUE(c.is_str());
|
|
}
|
|
|
|
{
|
|
Const c(" ");
|
|
EXPECT_TRUE(c.is_str());
|
|
EXPECT_FALSE(c.is_fully_ones());
|
|
EXPECT_TRUE(c.is_str());
|
|
}
|
|
|
|
{
|
|
Const c(" ");
|
|
EXPECT_TRUE(c.is_str());
|
|
EXPECT_TRUE(c.is_fully_def());
|
|
EXPECT_TRUE(c.is_str());
|
|
}
|
|
|
|
{
|
|
Const c(" ");
|
|
EXPECT_TRUE(c.is_str());
|
|
EXPECT_FALSE(c.is_fully_undef());
|
|
EXPECT_TRUE(c.is_str());
|
|
}
|
|
|
|
{
|
|
Const c(" ");
|
|
EXPECT_TRUE(c.is_str());
|
|
EXPECT_FALSE(c.is_fully_undef_x_only());
|
|
EXPECT_TRUE(c.is_str());
|
|
}
|
|
|
|
{
|
|
Const c(" ");
|
|
EXPECT_TRUE(c.is_str());
|
|
int pos;
|
|
EXPECT_TRUE(c.is_onehot(&pos));
|
|
EXPECT_EQ(pos, 5);
|
|
EXPECT_TRUE(c.is_str());
|
|
}
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstConstIteratorWorks) {
|
|
const Const c(0x2, 2);
|
|
Const::const_iterator it = c.begin();
|
|
ASSERT_NE(it, c.end());
|
|
EXPECT_EQ(*it, State::S0);
|
|
++it;
|
|
ASSERT_NE(it, c.end());
|
|
EXPECT_EQ(*it, State::S1);
|
|
++it;
|
|
EXPECT_EQ(it, c.end());
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstConstIteratorPreincrement) {
|
|
const Const c(0x2, 2);
|
|
Const::const_iterator it = c.begin();
|
|
EXPECT_EQ(*++it, State::S1);
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstConstIteratorPostincrement) {
|
|
const Const c(0x2, 2);
|
|
Const::const_iterator it = c.begin();
|
|
EXPECT_EQ(*it++, State::S0);
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstIteratorWorks) {
|
|
Const c(0x2, 2);
|
|
Const::iterator it = c.begin();
|
|
ASSERT_NE(it, c.end());
|
|
EXPECT_EQ(*it, State::S0);
|
|
++it;
|
|
ASSERT_NE(it, c.end());
|
|
EXPECT_EQ(*it, State::S1);
|
|
++it;
|
|
ASSERT_EQ(it, c.end());
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstIteratorPreincrement) {
|
|
Const c(0x2, 2);
|
|
Const::iterator it = c.begin();
|
|
EXPECT_EQ(*++it, State::S1);
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstIteratorPostincrement) {
|
|
Const c(0x2, 2);
|
|
Const::iterator it = c.begin();
|
|
EXPECT_EQ(*it++, State::S0);
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstIteratorWriteWorks) {
|
|
Const c(0x2, 2);
|
|
Const::iterator it = c.begin();
|
|
EXPECT_EQ(*it, State::S0);
|
|
*it = State::S1;
|
|
EXPECT_EQ(*it, State::S1);
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstBuilder) {
|
|
Const::Builder b;
|
|
EXPECT_EQ(GetSize(b), 0);
|
|
b.push_back(S0);
|
|
EXPECT_EQ(GetSize(b), 1);
|
|
b.push_back(S1);
|
|
EXPECT_EQ(GetSize(b), 2);
|
|
EXPECT_EQ(b.build(), Const(0x2, 2));
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstSet) {
|
|
Const c(0x2, 2);
|
|
c.set(0, S1);
|
|
EXPECT_EQ(c, Const(0x3, 2));
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstResize) {
|
|
Const c(0x2, 2);
|
|
c.resize(4, S1);
|
|
EXPECT_EQ(c, Const(0xe, 4));
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstEqualStr) {
|
|
EXPECT_EQ(Const("abc"), Const("abc"));
|
|
EXPECT_NE(Const("abc"), Const("def"));
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstEqualBits) {
|
|
std::vector<State> v1 = {S0, S1};
|
|
std::vector<State> v2 = {S1, S0};
|
|
EXPECT_EQ(Const(v1), Const(v1));
|
|
EXPECT_NE(Const(v1), Const(v2));
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstEqualStrBits) {
|
|
std::vector<State> v1 = {S0, S0, S0, S0, S0, S1, S0, S0};
|
|
EXPECT_EQ(Const(v1), Const(" "));
|
|
EXPECT_NE(Const(v1), Const("a"));
|
|
}
|
|
|
|
static Hasher::hash_t hash(const Const &c) {
|
|
Hasher h;
|
|
h = c.hash_into(h);
|
|
return h.yield();
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstEqualHashStrBits) {
|
|
std::vector<State> v1 = {S0, S0, S0, S0, S0, S1, S0, S0};
|
|
EXPECT_EQ(hash(Const(v1)), hash(Const(" ")));
|
|
EXPECT_NE(hash(Const(v1)), hash(Const("a")));
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstIsFullyZero) {
|
|
EXPECT_TRUE(Const(0, 8).is_fully_zero());
|
|
EXPECT_FALSE(Const(8, 8).is_fully_zero());
|
|
EXPECT_TRUE(Const().is_fully_zero());
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstIsFullyOnes) {
|
|
EXPECT_TRUE(Const(0xf, 4).is_fully_ones());
|
|
EXPECT_FALSE(Const(3, 4).is_fully_ones());
|
|
EXPECT_TRUE(Const().is_fully_ones());
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstIsFullyDef) {
|
|
EXPECT_TRUE(Const(0xf, 4).is_fully_def());
|
|
std::vector<State> v1 = {S0, Sx};
|
|
EXPECT_FALSE(Const(v1).is_fully_def());
|
|
EXPECT_TRUE(Const().is_fully_def());
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstIsFullyUndef) {
|
|
std::vector<State> v1 = {S0, Sx};
|
|
EXPECT_FALSE(Const(v1).is_fully_undef());
|
|
EXPECT_TRUE(Const(Sz, 2).is_fully_undef());
|
|
EXPECT_TRUE(Const().is_fully_undef());
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstIsFullyUndefXOnly) {
|
|
std::vector<State> v1 = {Sx, Sz};
|
|
EXPECT_FALSE(Const(v1).is_fully_undef_x_only());
|
|
EXPECT_TRUE(Const(Sx, 2).is_fully_undef_x_only());
|
|
EXPECT_TRUE(Const().is_fully_undef_x_only());
|
|
}
|
|
|
|
TEST_F(KernelRtlilTest, ConstIsOnehot) {
|
|
int pos;
|
|
EXPECT_TRUE(Const(0x80, 8).is_onehot(&pos));
|
|
EXPECT_EQ(pos, 7);
|
|
EXPECT_FALSE(Const(0x82, 8).is_onehot(&pos));
|
|
EXPECT_FALSE(Const(0, 8).is_onehot(&pos));
|
|
EXPECT_TRUE(Const(1, 1).is_onehot(&pos));
|
|
EXPECT_EQ(pos, 0);
|
|
EXPECT_FALSE(Const(Sx, 1).is_onehot(&pos));
|
|
std::vector<State> v1 = {Sx, S1};
|
|
EXPECT_FALSE(Const(v1).is_onehot(&pos));
|
|
EXPECT_FALSE(Const().is_onehot(&pos));
|
|
}
|
|
|
|
class WireRtlVsHdlIndexConversionTest :
|
|
public KernelRtlilTest,
|
|
public testing::WithParamInterface<std::tuple<bool, int, int>>
|
|
{};
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
WireRtlVsHdlIndexConversionInstance,
|
|
WireRtlVsHdlIndexConversionTest,
|
|
testing::Values(
|
|
std::make_tuple(false, 0, 10),
|
|
std::make_tuple(true, 0, 10),
|
|
std::make_tuple(false, 4, 10),
|
|
std::make_tuple(true, 4, 10),
|
|
std::make_tuple(false, -4, 10),
|
|
std::make_tuple(true, -4, 10),
|
|
std::make_tuple(false, 0, 1),
|
|
std::make_tuple(true, 0, 1),
|
|
std::make_tuple(false, 4, 1),
|
|
std::make_tuple(true, 4, 1),
|
|
std::make_tuple(false, -4, 1),
|
|
std::make_tuple(true, -4, 1)
|
|
),
|
|
SafePrintToStringParamName()
|
|
);
|
|
|
|
TEST_P(WireRtlVsHdlIndexConversionTest, WireRtlVsHdlIndexConversion) {
|
|
std::unique_ptr<Module> mod = std::make_unique<Module>();
|
|
Wire *wire = mod->addWire(ID(test), 10);
|
|
|
|
auto [upto, start_offset, width] = GetParam();
|
|
|
|
wire->upto = upto;
|
|
wire->start_offset = start_offset;
|
|
wire->width = width;
|
|
|
|
int smallest = INT_MAX;
|
|
int largest = INT_MIN;
|
|
|
|
for (int i = 0; i < wire->width; i++) {
|
|
int j = wire->to_hdl_index(i);
|
|
smallest = std::min(smallest, j);
|
|
largest = std::max(largest, j);
|
|
EXPECT_EQ(
|
|
std::make_pair(wire->from_hdl_index(j), j),
|
|
std::make_pair(i, wire->to_hdl_index(i))
|
|
);
|
|
}
|
|
|
|
EXPECT_EQ(smallest, start_offset);
|
|
EXPECT_EQ(largest, start_offset + wire->width - 1);
|
|
|
|
for (int i = 1; i < wire->width; i++) {
|
|
EXPECT_EQ(
|
|
wire->to_hdl_index(i) - wire->to_hdl_index(i - 1),
|
|
upto ? -1 : 1
|
|
);
|
|
}
|
|
|
|
for (int j = smallest; j < largest; j++) {
|
|
int i = wire->from_hdl_index(j);
|
|
EXPECT_EQ(
|
|
std::make_pair(wire->from_hdl_index(j), j),
|
|
std::make_pair(i, wire->to_hdl_index(i))
|
|
);
|
|
}
|
|
|
|
for (int i = -10; i < 0; i++)
|
|
EXPECT_EQ(wire->to_hdl_index(i), INT_MIN);
|
|
for (int i = wire->width; i < wire->width + 10; i++)
|
|
EXPECT_EQ(wire->to_hdl_index(i), INT_MIN);
|
|
for (int j = smallest - 10; j < smallest; j++)
|
|
EXPECT_EQ(wire->from_hdl_index(j), INT_MIN);
|
|
for (int j = largest + 1; j < largest + 11; j++)
|
|
EXPECT_EQ(wire->from_hdl_index(j), INT_MIN);
|
|
}
|
|
|
|
}
|
|
|
|
YOSYS_NAMESPACE_END
|