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