1 //===-- RegisterFlags.h -----------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLDB_TARGET_REGISTERFLAGS_H
10 #define LLDB_TARGET_REGISTERFLAGS_H
11 
12 #include <stdint.h>
13 #include <string>
14 #include <vector>
15 
16 namespace lldb_private {
17 
18 class StreamString;
19 class Log;
20 
21 class RegisterFlags {
22 public:
23   class Field {
24   public:
25     /// Where start is the least significant bit and end is the most
26     /// significant bit. The start bit must be <= the end bit.
27     Field(std::string name, unsigned start, unsigned end);
28 
29     /// Construct a field that occupies a single bit.
Field(std::string name,unsigned bit_position)30     Field(std::string name, unsigned bit_position)
31         : m_name(std::move(name)), m_start(bit_position), m_end(bit_position) {}
32 
33     /// Get size of the field in bits. Will always be at least 1.
GetSizeInBits()34     unsigned GetSizeInBits() const { return m_end - m_start + 1; }
35 
36     /// A mask that covers all bits of the field.
GetMask()37     uint64_t GetMask() const {
38       return (((uint64_t)1 << (GetSizeInBits())) - 1) << m_start;
39     }
40 
41     /// Extract value of the field from a whole register value.
GetValue(uint64_t register_value)42     uint64_t GetValue(uint64_t register_value) const {
43       return (register_value & GetMask()) >> m_start;
44     }
45 
GetName()46     const std::string &GetName() const { return m_name; }
GetStart()47     unsigned GetStart() const { return m_start; }
GetEnd()48     unsigned GetEnd() const { return m_end; }
49     bool Overlaps(const Field &other) const;
50     void log(Log *log) const;
51 
52     /// Return the number of bits between this field and the other, that are not
53     /// covered by either field.
54     unsigned PaddingDistance(const Field &other) const;
55 
56     /// Output XML that describes this field, to be inserted into a target XML
57     /// file. Reserved characters in field names like "<" are replaced with
58     /// their XML safe equivalents like "&gt;".
59     void ToXML(StreamString &strm) const;
60 
61     bool operator<(const Field &rhs) const {
62       return GetStart() < rhs.GetStart();
63     }
64 
65     bool operator==(const Field &rhs) const {
66       return (m_name == rhs.m_name) && (m_start == rhs.m_start) &&
67              (m_end == rhs.m_end);
68     }
69 
70   private:
71     std::string m_name;
72     /// Start/end bit positions. Where start N, end N means a single bit
73     /// field at position N. We expect that start <= end. Bit positions begin
74     /// at 0.
75     /// Start is the LSB, end is the MSB.
76     unsigned m_start;
77     unsigned m_end;
78   };
79 
80   /// This assumes that:
81   /// * There is at least one field.
82   /// * The fields are sorted in descending order.
83   /// Gaps are allowed, they will be filled with anonymous padding fields.
84   RegisterFlags(std::string id, unsigned size,
85                 const std::vector<Field> &fields);
86 
87   /// Replace all the fields with the new set of fields. All the assumptions
88   /// and checks apply as when you use the constructor. Intended to only be used
89   /// when runtime field detection is needed.
90   void SetFields(const std::vector<Field> &fields);
91 
92   // Reverse the order of the fields, keeping their values the same.
93   // For example a field from bit 31 to 30 with value 0b10 will become bits
94   // 1 to 0, with the same 0b10 value.
95   // Use this when you are going to show the register using a bitfield struct
96   // type. If that struct expects MSB first and you are on little endian where
97   // LSB would be first, this corrects that (and vice versa for big endian).
ReverseFieldOrder(T value)98   template <typename T> T ReverseFieldOrder(T value) const {
99     T ret = 0;
100     unsigned shift = 0;
101     for (auto field : GetFields()) {
102       ret |= field.GetValue(value) << shift;
103       shift += field.GetSizeInBits();
104     }
105 
106     return ret;
107   }
108 
GetFields()109   const std::vector<Field> &GetFields() const { return m_fields; }
GetID()110   const std::string &GetID() const { return m_id; }
GetSize()111   unsigned GetSize() const { return m_size; }
112   void log(Log *log) const;
113 
114   /// Produce a text table showing the layout of all the fields. Unnamed/padding
115   /// fields will be included, with only their positions shown.
116   /// max_width will be the width in characters of the terminal you are
117   /// going to print the table to. If the table would exceed this width, it will
118   /// be split into many tables as needed.
119   std::string AsTable(uint32_t max_width) const;
120 
121   // Output XML that describes this set of flags.
122   void ToXML(StreamString &strm) const;
123 
124 private:
125   const std::string m_id;
126   /// Size in bytes
127   const unsigned m_size;
128   std::vector<Field> m_fields;
129 };
130 
131 } // namespace lldb_private
132 
133 #endif // LLDB_TARGET_REGISTERFLAGS_H
134