1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <assert.h>
6 #include <climits>
7 #include <limits>
8 #include <stdio.h>
9 #include <unittest/unittest.h>
10
11 #include <hwreg/bitfields.h>
12 #include <hwreg/mmio.h>
13
14 // This function exists so that the resulting code can be inspected easily in the
15 // object file.
compilation_test()16 void compilation_test() {
17 class TestReg32 : public hwreg::RegisterBase<TestReg32, uint32_t> {
18 public:
19 DEF_FIELD(30, 12, field1);
20 DEF_BIT(11, field2);
21 DEF_RSVDZ_FIELD(10, 5);
22 DEF_FIELD(4, 3, field3);
23 DEF_RSVDZ_BIT(2);
24 DEF_RSVDZ_BIT(1);
25 DEF_FIELD(0, 0, field4);
26
27 static auto Get() { return hwreg::RegisterAddr<TestReg32>(0); }
28 };
29
30 volatile uint32_t fake_reg = 1ul << 31;
31 hwreg::RegisterIo mmio(&fake_reg);
32
33 auto reg = TestReg32::Get().ReadFrom(&mmio);
34 reg.set_field1(0x31234);
35 reg.set_field2(1);
36 reg.set_field3(2);
37 reg.set_field4(0);
38 reg.WriteTo(&mmio);
39 }
40
41 template <typename IntType>
42 struct LastBit {
43 static constexpr const unsigned int value = sizeof(IntType) * CHAR_BIT - 1;
44 };
45
46 template <typename IntType>
struct_sub_bit_test()47 static bool struct_sub_bit_test() {
48 BEGIN_TEST;
49
50 struct StructSubBitTest {
51 IntType field;
52
53 DEF_SUBBIT(field, 0, first_bit);
54 DEF_SUBBIT(field, 1, mid_bit);
55 DEF_SUBBIT(field, LastBit<IntType>::value, last_bit);
56 };
57
58 StructSubBitTest val = {};
59 EXPECT_EQ(0u, val.first_bit());
60 EXPECT_EQ(0u, val.mid_bit());
61 EXPECT_EQ(0u, val.last_bit());
62
63 val.set_first_bit(1);
64 EXPECT_EQ(1u, val.field);
65 EXPECT_EQ(1u, val.first_bit());
66 EXPECT_EQ(0u, val.mid_bit());
67 EXPECT_EQ(0u, val.last_bit());
68 val.set_first_bit(0);
69
70 val.set_mid_bit(1);
71 EXPECT_EQ(2u, val.field);
72 EXPECT_EQ(0u, val.first_bit());
73 EXPECT_EQ(1u, val.mid_bit());
74 EXPECT_EQ(0u, val.last_bit());
75 val.set_mid_bit(0);
76
77 val.set_last_bit(1);
78 EXPECT_EQ(1ull << LastBit<IntType>::value, val.field);
79 EXPECT_EQ(0u, val.first_bit());
80 EXPECT_EQ(0u, val.mid_bit());
81 EXPECT_EQ(1u, val.last_bit());
82 val.set_last_bit(0);
83
84 END_TEST;
85 }
86
87 template <typename IntType>
struct_sub_field_test()88 static bool struct_sub_field_test() {
89 BEGIN_TEST;
90
91 struct StructSubFieldTest {
92 IntType field1;
93 DEF_SUBFIELD(field1, LastBit<IntType>::value, 0, whole_length);
94
95 IntType field2;
96 DEF_SUBFIELD(field2, 2, 2, single_bit);
97
98 IntType field3;
99 DEF_SUBFIELD(field3, 2, 1, range1);
100 DEF_SUBFIELD(field3, 5, 3, range2);
101 };
102
103 StructSubFieldTest val = {};
104
105 // Ensure writing to a whole length field affects all bits
106 constexpr IntType kMax = std::numeric_limits<IntType>::max();
107 EXPECT_EQ(0u, val.whole_length());
108 val.set_whole_length(kMax);
109 EXPECT_EQ(kMax, val.whole_length());
110 EXPECT_EQ(kMax, val.field1);
111 val.set_whole_length(0);
112 EXPECT_EQ(0, val.whole_length());
113 EXPECT_EQ(0, val.field1);
114
115 // Ensure writing to a single bit only affects that bit
116 EXPECT_EQ(0u, val.single_bit());
117 val.set_single_bit(1);
118 EXPECT_EQ(1u, val.single_bit());
119 EXPECT_EQ(4u, val.field2);
120 val.set_single_bit(0);
121 EXPECT_EQ(0u, val.single_bit());
122 EXPECT_EQ(0u, val.field2);
123
124 // Ensure writing to adjacent fields does not bleed across
125 EXPECT_EQ(0u, val.range1());
126 EXPECT_EQ(0u, val.range2());
127 val.set_range1(3);
128 EXPECT_EQ(3u, val.range1());
129 EXPECT_EQ(0u, val.range2());
130 EXPECT_EQ(3u << 1, val.field3);
131 val.set_range2(1);
132 EXPECT_EQ(3u, val.range1());
133 EXPECT_EQ(1u, val.range2());
134 EXPECT_EQ((3u << 1) | (1u << 3), val.field3);
135 val.set_range2(2);
136 EXPECT_EQ(3u, val.range1());
137 EXPECT_EQ(2u, val.range2());
138 EXPECT_EQ((3u << 1) | (2u << 3), val.field3);
139 val.set_range1(0);
140 EXPECT_EQ(0u, val.range1());
141 EXPECT_EQ(2u, val.range2());
142 EXPECT_EQ((2u << 3), val.field3);
143
144 END_TEST;
145 }
146
reg_rsvdz_test()147 static bool reg_rsvdz_test() {
148 BEGIN_TEST;
149
150 class TestReg8 : public hwreg::RegisterBase<TestReg8, uint8_t> {
151 public:
152 DEF_RSVDZ_FIELD(7, 3);
153
154 static auto Get() { return hwreg::RegisterAddr<TestReg8>(0); }
155 };
156 class TestReg16 : public hwreg::RegisterBase<TestReg16, uint16_t> {
157 public:
158 DEF_RSVDZ_FIELD(14, 1);
159
160 static auto Get() { return hwreg::RegisterAddr<TestReg16>(0); }
161 };
162 class TestReg32 : public hwreg::RegisterBase<TestReg32, uint32_t> {
163 public:
164 DEF_RSVDZ_FIELD(31, 12);
165 DEF_RSVDZ_FIELD(10, 5);
166 DEF_RSVDZ_BIT(3);
167
168 static auto Get() { return hwreg::RegisterAddr<TestReg32>(0); }
169 };
170 class TestReg64 : public hwreg::RegisterBase<TestReg64, uint64_t> {
171 public:
172 DEF_RSVDZ_FIELD(63, 18);
173 DEF_RSVDZ_FIELD(10, 0);
174
175 static auto Get() { return hwreg::RegisterAddr<TestReg64>(0); }
176 };
177
178 volatile uint64_t fake_reg;
179 hwreg::RegisterIo mmio(&fake_reg);
180
181 // Ensure we mask off the RsvdZ bits when we write them back, regardless of
182 // what we read them as.
183 {
184 fake_reg = std::numeric_limits<uint8_t>::max();
185 auto reg = TestReg8::Get().ReadFrom(&mmio);
186 EXPECT_EQ(std::numeric_limits<uint8_t>::max(), reg.reg_value());
187 reg.WriteTo(&mmio);
188 EXPECT_EQ(0x7u, fake_reg);
189 }
190 {
191 fake_reg = std::numeric_limits<uint16_t>::max();
192 auto reg = TestReg16::Get().ReadFrom(&mmio);
193 EXPECT_EQ(std::numeric_limits<uint16_t>::max(), reg.reg_value());
194 reg.WriteTo(&mmio);
195 EXPECT_EQ(0x8001u, fake_reg);
196 }
197 {
198 fake_reg = std::numeric_limits<uint32_t>::max();
199 auto reg = TestReg32::Get().ReadFrom(&mmio);
200 EXPECT_EQ(std::numeric_limits<uint32_t>::max(), reg.reg_value());
201 reg.WriteTo(&mmio);
202 EXPECT_EQ((1ull << 11) | 0x17ull, fake_reg);
203 }
204 {
205 fake_reg = std::numeric_limits<uint64_t>::max();
206 auto reg = TestReg64::Get().ReadFrom(&mmio);
207 EXPECT_EQ(std::numeric_limits<uint64_t>::max(), reg.reg_value());
208 reg.WriteTo(&mmio);
209 EXPECT_EQ(0x7full << 11, fake_reg);
210 }
211
212 END_TEST;
213 }
214
reg_rsvdz_full_test()215 static bool reg_rsvdz_full_test() {
216 BEGIN_TEST;
217
218 class TestReg8 : public hwreg::RegisterBase<TestReg8, uint8_t> {
219 public:
220 DEF_RSVDZ_FIELD(7, 0);
221
222 static auto Get() { return hwreg::RegisterAddr<TestReg8>(0); }
223 };
224 class TestReg16 : public hwreg::RegisterBase<TestReg16, uint16_t> {
225 public:
226 DEF_RSVDZ_FIELD(15, 0);
227
228 static auto Get() { return hwreg::RegisterAddr<TestReg16>(0); }
229 };
230 class TestReg32 : public hwreg::RegisterBase<TestReg32, uint32_t> {
231 public:
232 DEF_RSVDZ_FIELD(31, 0);
233
234 static auto Get() { return hwreg::RegisterAddr<TestReg32>(0); }
235 };
236 class TestReg64 : public hwreg::RegisterBase<TestReg64, uint64_t> {
237 public:
238 DEF_RSVDZ_FIELD(63, 0);
239
240 static auto Get() { return hwreg::RegisterAddr<TestReg64>(0); }
241 };
242
243 volatile uint64_t fake_reg;
244 hwreg::RegisterIo mmio(&fake_reg);
245
246 // Ensure we mask off the RsvdZ bits when we write them back, regardless of
247 // what we read them as.
248 {
249 fake_reg = std::numeric_limits<uint8_t>::max();
250 auto reg = TestReg8::Get().ReadFrom(&mmio);
251 EXPECT_EQ(std::numeric_limits<uint8_t>::max(), reg.reg_value());
252 reg.WriteTo(&mmio);
253 EXPECT_EQ(0u, fake_reg);
254 }
255 {
256 fake_reg = std::numeric_limits<uint16_t>::max();
257 auto reg = TestReg16::Get().ReadFrom(&mmio);
258 EXPECT_EQ(std::numeric_limits<uint16_t>::max(), reg.reg_value());
259 reg.WriteTo(&mmio);
260 EXPECT_EQ(0u, fake_reg);
261 }
262 {
263 fake_reg = std::numeric_limits<uint32_t>::max();
264 auto reg = TestReg32::Get().ReadFrom(&mmio);
265 EXPECT_EQ(std::numeric_limits<uint32_t>::max(), reg.reg_value());
266 reg.WriteTo(&mmio);
267 EXPECT_EQ(0u, fake_reg);
268 }
269 {
270 fake_reg = std::numeric_limits<uint64_t>::max();
271 auto reg = TestReg64::Get().ReadFrom(&mmio);
272 EXPECT_EQ(std::numeric_limits<uint64_t>::max(), reg.reg_value());
273 reg.WriteTo(&mmio);
274 EXPECT_EQ(0u, fake_reg);
275 }
276
277 END_TEST;
278 }
279
reg_field_test()280 static bool reg_field_test() {
281 BEGIN_TEST;
282
283 class TestReg8 : public hwreg::RegisterBase<TestReg8, uint8_t> {
284 public:
285 DEF_FIELD(7, 3, field1);
286 DEF_FIELD(2, 0, field2);
287
288 static auto Get() { return hwreg::RegisterAddr<TestReg8>(0); }
289 };
290 class TestReg16 : public hwreg::RegisterBase<TestReg16, uint16_t> {
291 public:
292 DEF_FIELD(13, 3, field1);
293 DEF_FIELD(2, 1, field2);
294 DEF_BIT(0, field3);
295
296 static auto Get() { return hwreg::RegisterAddr<TestReg16>(0); }
297 };
298 class TestReg32 : public hwreg::RegisterBase<TestReg32, uint32_t> {
299 public:
300 DEF_FIELD(30, 21, field1);
301 DEF_FIELD(20, 12, field2);
302 DEF_RSVDZ_FIELD(11, 0);
303
304 static auto Get() { return hwreg::RegisterAddr<TestReg32>(0); }
305 };
306 class TestReg64 : public hwreg::RegisterBase<TestReg64, uint64_t> {
307 public:
308 DEF_FIELD(60, 20, field1);
309 DEF_FIELD(10, 0, field2);
310
311 static auto Get() { return hwreg::RegisterAddr<TestReg64>(0); }
312 };
313
314 volatile uint64_t fake_reg;
315 hwreg::RegisterIo mmio(&fake_reg);
316
317 // Ensure modified fields go to the right place, and unspecified bits are
318 // preserved.
319 {
320 constexpr uint8_t kInitVal = 0x42u;
321 fake_reg = kInitVal;
322 auto reg = TestReg8::Get().ReadFrom(&mmio);
323 EXPECT_EQ(kInitVal, reg.reg_value());
324 EXPECT_EQ(kInitVal >> 3, reg.field1());
325 EXPECT_EQ(0x2u, reg.field2());
326 reg.set_field1(0x1fu);
327 reg.set_field2(0x1u);
328 EXPECT_EQ(0x1fu, reg.field1());
329 EXPECT_EQ(0x1u, reg.field2());
330
331 reg.WriteTo(&mmio);
332 EXPECT_EQ((0x1fu << 3) | 1, fake_reg);
333 }
334 {
335 constexpr uint16_t kInitVal = 0b1010'1111'0101'0000u;
336 fake_reg = kInitVal;
337 auto reg = TestReg16::Get().ReadFrom(&mmio);
338 EXPECT_EQ(kInitVal, reg.reg_value());
339 EXPECT_EQ((kInitVal >> 3) & ((1u << 11) - 1), reg.field1());
340 EXPECT_EQ((kInitVal >> 1) & 0x3u, reg.field2());
341 EXPECT_EQ(kInitVal & 1u, reg.field3());
342 reg.set_field1(42);
343 reg.set_field2(2);
344 reg.set_field3(1);
345 EXPECT_EQ(42u, reg.field1());
346 EXPECT_EQ(2u, reg.field2());
347 EXPECT_EQ(1u, reg.field3());
348 reg.WriteTo(&mmio);
349 EXPECT_EQ((0b10u << 14) | (42u << 3) | (2u << 1) | 1u, fake_reg);
350 }
351 {
352 constexpr uint32_t kInitVal = 0xe987'2fffu;
353 fake_reg = kInitVal;
354 auto reg = TestReg32::Get().ReadFrom(&mmio);
355 EXPECT_EQ(kInitVal, reg.reg_value());
356 EXPECT_EQ((kInitVal >> 21) & ((1u << 10) - 1), reg.field1());
357 EXPECT_EQ((kInitVal >> 12) & ((1u << 9) - 1), reg.field2());
358 reg.set_field1(0x3a7);
359 reg.set_field2(0x8f);
360 EXPECT_EQ(0x3a7u, reg.field1());
361 EXPECT_EQ(0x8fu, reg.field2());
362 reg.WriteTo(&mmio);
363 EXPECT_EQ((0b1u << 31) | (0x3a7u << 21) | (0x8fu << 12), fake_reg);
364 }
365 {
366 constexpr uint64_t kInitVal = 0xfedc'ba98'7654'3210ull;
367 fake_reg = kInitVal;
368 auto reg = TestReg64::Get().ReadFrom(&mmio);
369 EXPECT_EQ(kInitVal, reg.reg_value());
370 EXPECT_EQ((kInitVal >> 20) & ((1ull << 41) - 1), reg.field1());
371 EXPECT_EQ(kInitVal & ((1ull << 11) - 1), reg.field2());
372 reg.set_field1(0x1a2'3456'789aull);
373 reg.set_field2(0x78c);
374 EXPECT_EQ(0x1a2'3456'789aull, reg.field1());
375 EXPECT_EQ(0x78cu, reg.field2());
376 reg.WriteTo(&mmio);
377 EXPECT_EQ((0b111ull << 61) | (0x1a2'3456'789aull << 20) | (0x86ull << 11) | 0x78cu, fake_reg);
378 }
379
380 END_TEST;
381 }
382
print_test()383 static bool print_test() {
384 BEGIN_TEST;
385
386 class TestReg : public hwreg::RegisterBase<TestReg, uint32_t, hwreg::EnablePrinter> {
387 public:
388 DEF_RSVDZ_BIT(31);
389 DEF_FIELD(30, 21, field1);
390 DEF_FIELD(20, 12, field2);
391 DEF_RSVDZ_FIELD(11, 0);
392
393 static auto Get() { return hwreg::RegisterAddr<TestReg>(0); }
394 };
395
396 volatile uint64_t fake_reg;
397 hwreg::RegisterIo mmio(&fake_reg);
398
399 constexpr uint32_t kInitVal = 0xe987'2fffu;
400 fake_reg = kInitVal;
401 {
402 auto reg = TestReg::Get().ReadFrom(&mmio);
403 unsigned call_count = 0;
404 const char* expected[] = {
405 "RsvdZ[31:31]: 0x1 (1)",
406 "field1[30:21]: 0x34c (844)",
407 "field2[20:12]: 0x072 (114)",
408 "RsvdZ[11:0]: 0xfff (4095)",
409 };
410 reg.Print([&](const char* buf) {
411 EXPECT_STR_EQ(expected[call_count], buf, "mismatch");
412 call_count++;
413 });
414 EXPECT_EQ(fbl::count_of(expected), call_count);
415 }
416
417 class TestReg2 : public hwreg::RegisterBase<TestReg2, uint32_t, hwreg::EnablePrinter> {
418 public:
419 DEF_FIELD(30, 21, field1);
420 DEF_FIELD(20, 12, field2);
421
422 static auto Get() { return hwreg::RegisterAddr<TestReg2>(0); }
423 };
424
425 {
426 auto reg = TestReg2::Get().ReadFrom(&mmio);
427 unsigned call_count = 0;
428 const char* expected[] = {
429 "field1[30:21]: 0x34c (844)",
430 "field2[20:12]: 0x072 (114)",
431 "unknown set bits: 0x80000fff",
432 };
433 reg.Print([&](const char* buf) {
434 EXPECT_STR_EQ(expected[call_count], buf, "mismatch");
435 call_count++;
436 });
437 EXPECT_EQ(fbl::count_of(expected), call_count);
438 }
439
440 END_TEST;
441 }
442
443 // Test using the "fluent" style of chaining calls, like:
444 // TestReg::Get().ReadFrom(&mmio).set_field1(0x234).set_field2(0x123).WriteTo(&mmio);
set_chaining_test()445 static bool set_chaining_test() {
446 BEGIN_TEST;
447
448 class TestReg : public hwreg::RegisterBase<TestReg, uint32_t> {
449 public:
450 DEF_RSVDZ_BIT(31);
451 DEF_FIELD(30, 21, field1);
452 DEF_FIELD(20, 12, field2);
453 DEF_RSVDZ_FIELD(11, 0);
454
455 static auto Get() { return hwreg::RegisterAddr<TestReg>(0); }
456 };
457
458 volatile uint32_t fake_reg;
459 hwreg::RegisterIo mmio(&fake_reg);
460
461 // With ReadFrom from a RegAddr
462 fake_reg = ~0u;
463 TestReg::Get().ReadFrom(&mmio).set_field1(0x234).set_field2(0x123).WriteTo(&mmio);
464 EXPECT_EQ((0x234u << 21) | (0x123u << 12), fake_reg);
465
466 // With ReadFrom from TestReg
467 fake_reg = ~0u;
468 auto reg = TestReg::Get().FromValue(0);
469 reg.ReadFrom(&mmio).set_field1(0x234).set_field2(0x123).WriteTo(&mmio);
470 EXPECT_EQ((0x234u << 21) | (0x123u << 12), fake_reg);
471
472 END_TEST;
473 }
474
475 // Compile-time test that not enabling printing functions provides a size reduction
printer_size_reduction()476 static void printer_size_reduction() {
477 class TestRegWithPrinter : public hwreg::RegisterBase<TestRegWithPrinter, uint64_t,
478 hwreg::EnablePrinter> {
479 };
480 class TestRegWithoutPrinter : public hwreg::RegisterBase<TestRegWithoutPrinter, uint64_t> {
481 };
482
483 static_assert(sizeof(TestRegWithPrinter) > sizeof(TestRegWithoutPrinter), "");
484 }
485
486 #define RUN_TEST_FOR_UINTS(test) \
487 RUN_TEST(test<uint8_t>) \
488 RUN_TEST(test<uint16_t>) \
489 RUN_TEST(test<uint32_t>) \
490 RUN_TEST(test<uint64_t>)
491
492 BEGIN_TEST_CASE(libhwreg_tests)
RUN_TEST_FOR_UINTS(struct_sub_bit_test)493 RUN_TEST_FOR_UINTS(struct_sub_bit_test)
494 RUN_TEST_FOR_UINTS(struct_sub_field_test)
495 RUN_TEST(reg_rsvdz_test)
496 RUN_TEST(reg_rsvdz_full_test)
497 RUN_TEST(reg_field_test)
498 RUN_TEST(print_test)
499 RUN_TEST(set_chaining_test)
500 END_TEST_CASE(libhwreg_tests)
501
502 int main(int argc, char** argv) {
503 bool success = unittest_run_all_tests(argc, argv);
504 return success ? 0 : -1;
505 }
506