blob: 2f79ba7657497e505890af1cb3e3a491e4ffebff [file] [log] [blame]
Zane Shelley6eb61902020-05-15 22:25:58 -05001#include <hei_chip.hpp>
2#include <register/hei_operator_register.hpp>
3#include <util/hei_flyweight.hpp>
4
5#include "gtest/gtest.h"
6
7using namespace libhei;
8
9constexpr uint16_t CONST1 = 0x1458;
10constexpr uint16_t CONST2 = 0x5368;
11
12#define MATH(x) static_cast<uint16_t>(x)
13
14uint64_t __getVal(Register::ConstPtr i_reg)
15{
16 Chip CHIP{nullptr, 0};
17 auto bs = i_reg->getBitString(CHIP);
18 return bs->getFieldRight(0, bs->getBitLen());
19}
20
21size_t __getBW(Register::ConstPtr i_reg)
22{
23 Chip CHIP{nullptr, 0};
24 return i_reg->getBitString(CHIP)->getBitLen();
25}
26
27TEST(OperatorRegisterTest, BasicOperations)
28{
29 auto const1 = std::make_shared<const ConstantRegister>(CONST1);
30 ASSERT_EQ(MATH(CONST1), __getVal(const1));
31
32 auto const2 = std::make_shared<const ConstantRegister>(CONST2);
33 ASSERT_EQ(MATH(CONST2), __getVal(const2));
34
35 auto and1 = std::make_shared<const AndRegister>(const1, const2);
36 ASSERT_EQ(MATH(CONST1 & CONST2), __getVal(and1));
37
38 auto or1 = std::make_shared<const OrRegister>(const1, const2);
39 ASSERT_EQ(MATH(CONST1 | CONST2), __getVal(or1));
40
41 auto not1 = std::make_shared<const NotRegister>(const1);
42 ASSERT_EQ(MATH(~CONST1), __getVal(not1));
43
44 auto not2 = std::make_shared<const NotRegister>(const2);
45 ASSERT_EQ(MATH(~CONST2), __getVal(not2));
46}
47
48TEST(OperatorRegisterTest, BasicOperationsWithFlyweights)
49{
50 auto& const_factory = Flyweight<const ConstantRegister>::getSingleton();
Patrick Williams2f7537d2023-05-10 07:51:39 -050051 auto& and_factory = Flyweight<const AndRegister>::getSingleton();
52 auto& or_factory = Flyweight<const OrRegister>::getSingleton();
53 auto& not_factory = Flyweight<const NotRegister>::getSingleton();
Zane Shelley6eb61902020-05-15 22:25:58 -050054
55 auto const1 = const_factory.get(CONST1);
56 auto const2 = const_factory.get(CONST2);
57
58 ASSERT_EQ(MATH(CONST1), __getVal(const1));
59 ASSERT_EQ(MATH(CONST2), __getVal(const2));
60 ASSERT_EQ(MATH(CONST1 & CONST2), __getVal(and_factory.get(const1, const2)));
61 ASSERT_EQ(MATH(CONST1 | CONST2), __getVal(or_factory.get(const1, const2)));
62 ASSERT_EQ(MATH(~CONST1), __getVal(not_factory.get(const1)));
63 ASSERT_EQ(MATH(~CONST2), __getVal(not_factory.get(const2)));
64
65 const_factory.clear();
66 and_factory.clear();
67 or_factory.clear();
68 not_factory.clear();
69}
70
71TEST(OperatorRegisterTest, ShiftOperations)
72{
Patrick Williams2f7537d2023-05-10 07:51:39 -050073 auto& const_factory = Flyweight<const ConstantRegister>::getSingleton();
Zane Shelley6eb61902020-05-15 22:25:58 -050074 auto& lshift_factory = Flyweight<const LeftShiftRegister>::getSingleton();
75 auto& rshift_factory = Flyweight<const RightShiftRegister>::getSingleton();
76
77 auto const1 = const_factory.get(CONST1);
78
79 for (size_t i = 0; i < __getBW(const1); i++)
80 {
81 ASSERT_EQ(MATH(CONST1 << i), __getVal(lshift_factory.get(const1, i)));
82 }
83
84 for (size_t i = 0; i < __getBW(const1); i++)
85 {
86 ASSERT_EQ(MATH(CONST1 >> i), __getVal(rshift_factory.get(const1, i)));
87 }
88
89 const_factory.clear();
90 lshift_factory.clear();
91 rshift_factory.clear();
92}
93
94TEST(OperatorRegisterTest, ComplexOperation)
95{
96 // Something seemingly complex:
97 // ~(((CONST1 & CONST2) << 12) | ((CONST1 | CONST2) >> 4)))
98
Patrick Williams2f7537d2023-05-10 07:51:39 -050099 auto& const_factory = Flyweight<const ConstantRegister>::getSingleton();
100 auto& and_factory = Flyweight<const AndRegister>::getSingleton();
101 auto& or_factory = Flyweight<const OrRegister>::getSingleton();
102 auto& not_factory = Flyweight<const NotRegister>::getSingleton();
Zane Shelley6eb61902020-05-15 22:25:58 -0500103 auto& lshift_factory = Flyweight<const LeftShiftRegister>::getSingleton();
104 auto& rshift_factory = Flyweight<const RightShiftRegister>::getSingleton();
105
106 auto const1 = const_factory.get(CONST1);
107 auto const2 = const_factory.get(CONST2);
108
109 auto lshift = lshift_factory.get(and_factory.get(const1, const2), 12);
110 auto rshift = rshift_factory.get(or_factory.get(const1, const2), 4);
111
112 auto expr = not_factory.get(or_factory.get(lshift, rshift));
113
114 ASSERT_EQ(MATH(~(((CONST1 & CONST2) << 12) | ((CONST1 | CONST2) >> 4))),
115 __getVal(expr));
116
117 const_factory.clear();
118 and_factory.clear();
119 or_factory.clear();
120 not_factory.clear();
121 lshift_factory.clear();
122 rshift_factory.clear();
123}
124
125TEST(OperatorRegisterTest, ConstRegConstructor)
126{
127 auto& const_factory = Flyweight<const ConstantRegister>::getSingleton();
Patrick Williams2f7537d2023-05-10 07:51:39 -0500128 auto& and_factory = Flyweight<const AndRegister>::getSingleton();
Zane Shelley6eb61902020-05-15 22:25:58 -0500129
130 // The ConstRegister constructor is a template that requires some integer
131 // type.
132
133 auto const1 = const_factory.get(CONST1); // CONST1 is uint16_t, GOOD
134
135 auto const2 = const_factory.get(uint16_t{0x1458}); // This also works
136
137 ASSERT_EQ(const1, const2); // Should point to the same thing.
138
139 // If you pass in a constant with no type the compiler assumes it is the
140 // implicit int type. This value is the same as const2, but the size will be
141 // different.
142 auto const3 = const_factory.get(0x1458);
143
144 // The values are the same, but the bit strings are are different sizes.
145 ASSERT_NE(const2, const3);
146
147 // AND and OR operators will not like different sizes either.
148 ASSERT_DEATH(and_factory.get(const2, const3), "");
149
150 const_factory.clear();
151 and_factory.clear();
152}