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. |
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. |
34 | unsigned GetSizeInBits() const { return m_end - m_start + 1; } |
35 | |
36 | /// A mask that covers all bits of the field. |
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. |
42 | uint64_t GetValue(uint64_t register_value) const { |
43 | return (register_value & GetMask()) >> m_start; |
44 | } |
45 | |
46 | const std::string &GetName() const { return m_name; } |
47 | unsigned GetStart() const { return m_start; } |
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 ">". |
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). |
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(register_value: value) << shift; |
103 | shift += field.GetSizeInBits(); |
104 | } |
105 | |
106 | return ret; |
107 | } |
108 | |
109 | const std::vector<Field> &GetFields() const { return m_fields; } |
110 | const std::string &GetID() const { return m_id; } |
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 | |