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