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 #pragma once
6 
7 #include <fbl/algorithm.h>
8 #include <inttypes.h>
9 #include <limits.h>
10 #include <stdint.h>
11 #include <zircon/assert.h>
12 
13 namespace hwreg {
14 
15 struct EnablePrinter;
16 
17 namespace internal {
18 
19 template <typename T> struct IsSupportedInt : fbl::false_type {};
20 template <> struct IsSupportedInt<uint8_t> : fbl::true_type {};
21 template <> struct IsSupportedInt<uint16_t> : fbl::true_type {};
22 template <> struct IsSupportedInt<uint32_t> : fbl::true_type {};
23 template <> struct IsSupportedInt<uint64_t> : fbl::true_type {};
24 
25 template <class IntType> constexpr IntType ComputeMask(uint32_t num_bits) {
26     if (num_bits == sizeof(IntType) * CHAR_BIT) {
27         return static_cast<IntType>(~0ull);
28     }
29     return static_cast<IntType>((static_cast<IntType>(1) << num_bits) - 1);
30 }
31 
32 class FieldPrinter {
33 public:
34     constexpr FieldPrinter() : name_(nullptr), bit_high_incl_(0), bit_low_(0) {
35     }
36     constexpr FieldPrinter(const char* name, uint32_t bit_high_incl, uint32_t bit_low)
37         : name_(name), bit_high_incl_(bit_high_incl), bit_low_(bit_low) {
38     }
39 
40     // Prints the field name, and the result of extracting the field from |value| in
41     // hex (with a left-padding of zeroes to a length matching the maximum number of
42     // nibbles needed to represent any value the field could take).
43     void Print(uint64_t value, char* buf, size_t len) const;
44 
45 private:
46     const char* name_;
47     uint32_t bit_high_incl_;
48     uint32_t bit_low_;
49 };
50 
51 // Structure used to reduce the storage cost of the pretty-printing features if
52 // they are not enabled.
53 template <typename T, typename IntType> struct FieldPrinterList {
54     void AppendField(const char* name, uint32_t bit_high_incl, uint32_t bit_low) {
55     }
56 };
57 
58 template <typename IntType> struct FieldPrinterList<EnablePrinter, IntType> {
59     // These two members are used for implementing the Print() function above.
60     // They will typically be optimized away if Print() is not used.
61     FieldPrinter fields[sizeof(IntType) * CHAR_BIT];
62     unsigned num_fields = 0;
63 
64     void AppendField(const char* name, uint32_t bit_high_incl, uint32_t bit_low) {
65         ZX_DEBUG_ASSERT(num_fields < fbl::count_of(fields));
66         fields[num_fields++] = FieldPrinter(name, bit_high_incl, bit_low);
67     }
68 };
69 
70 // Used to record information about a field at construction time.  This enables
71 // checking for overlapping fields and pretty-printing.
72 template <class RegType> class Field {
73 private:
74     using IntType = typename RegType::ValueType;
75 public:
76     Field(RegType* reg, const char* name, uint32_t bit_high_incl, uint32_t bit_low) {
77         IntType mask = static_cast<IntType>(
78                 internal::ComputeMask<IntType>(bit_high_incl - bit_low + 1) << bit_low);
79         // Check for overlapping bit ranges
80         ZX_DEBUG_ASSERT((reg->fields_mask_ & mask) == 0ull);
81         reg->fields_mask_ = static_cast<IntType>(reg->fields_mask_ | mask);
82 
83         reg->printer_.AppendField(name, bit_high_incl, bit_low);
84     }
85 };
86 
87 // Used to record information about reserved-zero fields at construction time.
88 // This enables auto-zeroing of reserved-zero fields on register write.
89 // Represents a field that must be zeroed on write.
90 template <class RegType> class RsvdZField {
91 private:
92     using IntType = typename RegType::ValueType;
93 public:
94     RsvdZField(RegType* reg, uint32_t bit_high_incl, uint32_t bit_low) {
95         IntType mask = static_cast<IntType>(
96                 internal::ComputeMask<IntType>(bit_high_incl - bit_low + 1) << bit_low);
97         reg->rsvdz_mask_ = static_cast<IntType>(reg->rsvdz_mask_ | mask);
98     }
99 };
100 
101 // Implementation for RegisterBase::Print, see the documentation there.
102 // |reg_value| is the current value of the register.
103 // |fields_mask| is a bitmask with a bit set for each bit that has been defined
104 // in the register.
105 template <typename F>
106 void PrintRegister(F print_fn,
107                    FieldPrinter fields[], size_t num_fields,
108                    uint64_t reg_value, uint64_t fields_mask,
109                    int register_width_bytes) {
110     char buf[128];
111     for (unsigned i = 0; i < num_fields; ++i) {
112         fields[i].Print(reg_value, buf, sizeof(buf));
113         print_fn(buf);
114     }
115 
116     // Check if any unknown bits are set, and if so let the caller know
117     uint64_t val = reg_value & ~fields_mask;
118     if (val != 0) {
119         int pad_len = (register_width_bytes * CHAR_BIT) / 4;
120         snprintf(buf, sizeof(buf), "unknown set bits: 0x%0*" PRIx64, pad_len, val);
121         buf[sizeof(buf) - 1] = 0;
122         print_fn(buf);
123     }
124 }
125 
126 // Utility for the common print function of [](const char* arg) { printf("%s\n", arg); }
127 void PrintRegisterPrintf(FieldPrinter fields[], size_t num_fields,
128                          uint64_t reg_value, uint64_t fields_mask,
129                          int register_width_bytes);
130 
131 } // namespace internal
132 
133 } // namespace hwreg
134