libmicroemu 0.2.0
ARM Microcontroller Emulator Library
Loading...
Searching...
No Matches
if_then_ops.h
1#pragma once
2
4#include "libmicroemu/register_details.h"
6#include "libmicroemu/types.h"
7#include <cstddef>
8#include <cstdint>
9#include <string_view>
10
11namespace libmicroemu::internal {
12
13enum class Condition : u32 {
14 kCondEq = 0b0000U, // Equal
15 kCondNe = 0b0001U, // Not equal
16
17 kCondCs = 0b0010U, // Carry set
18 kCondCc = 0b0011U, // Carry clear
19
20 kCondMi = 0b0100U, // Minus, negative
21 kCondPl = 0b0101U, // Plus, positive or zero
22
23 kCondVs = 0b0110U, // Overflow
24 kCondVc = 0b0111U, // No overflow
25
26 kCondHi = 0b1000U, // Unsigned higher
27 kCondLs = 0b1001U, // Unsigned lower or same
28
29 kCondGe = 0b1010U, // Signed greater than or equal
30 kCondLt = 0b1011U, // Signed less than
31
32 kCondGt = 0b1100U, // Signed greater than
33 kCondLe = 0b1101U, // Signed less than or
34
35 kCondAl = 0b1110U, // Always
36 kUndefined = 0b1111U, // Undefined
37};
38
39template <typename TCpuAccessor> class IfThenOps {
40
41public:
45 IfThenOps() = delete;
46
50 ~IfThenOps() = delete;
51
56 IfThenOps(IfThenOps &r_src) = delete;
57
62 IfThenOps &operator=(const IfThenOps &r_src) = delete;
63
68 IfThenOps(IfThenOps &&r_src) = delete;
69
74 IfThenOps &operator=(IfThenOps &&r_src) = delete;
75
76 static inline bool InITBlock(const TCpuAccessor &cpua) {
77 auto istate = cpua.template ReadSpecialRegister<SpecialRegisterId::kIstate>();
78 return ((istate & IstateRegister::kItBit3to0Msk) != 0b0000U);
79 }
80
81 static inline bool LastInITBlock(TCpuAccessor &cpua) {
82 auto istate = cpua.template ReadSpecialRegister<SpecialRegisterId::kIstate>();
83 return ((istate & IstateRegister::kItBit3to0Msk) == 0b1000U);
84 }
85
86 static inline void ITAdvance(TCpuAccessor &cpua) {
87 auto istate = cpua.template ReadSpecialRegister<SpecialRegisterId::kIstate>();
88 const auto istate_2_0 = istate & IstateRegister::kItBit2to0Msk;
89
90 if (istate_2_0 == 0x0U) {
91 istate = 0x0U;
92 } else {
93 const auto next_istate_4_0 =
94 ((istate & IstateRegister::kItBit4to0Msk) << 1U) & IstateRegister::kItBit4to0Msk;
95 istate = (istate & ~IstateRegister::kItBit4to0Msk) | next_istate_4_0;
96 }
97
98 cpua.template WriteSpecialRegister<SpecialRegisterId::kIstate>(istate);
99 }
100
101 static inline Result<u32> CurrentCond(const TCpuAccessor &cpua) {
102 // • For the T1 and T3 encodings of the Branch instruction shown in B on
103 // page A7-205, it returns the 4-bit cond field of the encoding.
104 // --> This is handled by the encoder by Using ConiditionPassed(cond)
105
106 // • For all other Thumb instructions:
107 auto istate = cpua.template ReadSpecialRegister<SpecialRegisterId::kIstate>();
108
109 const auto it_3_0 = istate & IstateRegister::kItBit3to0Msk;
110
111 if (it_3_0 != 0x0U) {
112 const auto it_7_4 = (istate & IstateRegister::kItBit7to4Msk) >> IstateRegister::kItBit4Pos;
113 return Ok<u32>(it_7_4);
114 }
115
116 if (istate == 0x0U) {
117 return Ok<u32>(0xEU); // b1110
118 }
119
120 // Otherwise, execution of the instruction is UNPREDICTABLE.
121 return Err<u32>(StatusCode::kExecutorUnpredictable);
122 }
123
124 static inline Condition DecodeCondition(u8 cond) {
125 return static_cast<Condition>(cond & IstateRegister::kItBit3to0Msk);
126 }
127
128 static std::string_view ConditionToString(u8 cond) {
129 switch (DecodeCondition(cond)) {
130
131 case Condition::kCondEq: // Equal
132 return "EQ";
133 case Condition::kCondNe: // Not equal
134 return "NE";
135 case Condition::kCondCs: // Carry set
136 return "CS";
137 case Condition::kCondCc: // Carry clear
138 return "CC";
139 case Condition::kCondMi: // Minus, negative
140 return "MI";
141 case Condition::kCondPl: // Plus, positive or zero
142 return "PL";
143 case Condition::kCondVs: // Overflow
144 return "VS";
145 case Condition::kCondVc: // No overflow
146 return "VC";
147 case Condition::kCondHi: // Unsigned higher
148 return "HI";
149 case Condition::kCondLs: // Unsigned lower or same
150 return "LS";
151 case Condition::kCondGe: // Signed greater than or equal
152 return "GE";
153 case Condition::kCondLt: // Signed less than
154 return "LT";
155 case Condition::kCondGt: // Signed greater than
156 return "GT";
157 case Condition::kCondLe: // Signed less than or
158 return "LE";
159 case Condition::kCondAl: // Always
160 return "";
161 case Condition::kUndefined: // Undefined
162 default:
163 break;
164 }
165 return "invalid";
166 }
167
168 static std::string_view GetConditionAsStr(const TCpuAccessor &cpua) {
169 const auto r_cond = CurrentCond(cpua);
170 if (r_cond.IsErr()) {
171 return "invalid";
172 }
173
174 const auto &cond = r_cond.content;
175 return ConditionToString(cond);
176 }
177
178 static inline bool ConditionPassed(const TCpuAccessor &cpua, u8 cond) {
179 // see Armv7-M Architecture Reference Manual Issue E.e p.178 - 179
180 bool result{false};
181
182 auto cond_3_1 = (cond & IstateRegister::kItBit3to1Msk) >> IstateRegister::kItBit1Pos;
183 switch (cond_3_1) {
184 case 0b000U: { // EQ - Equal or NE - Not equal
185 auto apsr = cpua.template ReadSpecialRegister<SpecialRegisterId::kApsr>();
186 result = (apsr & ApsrRegister::kZMsk) == ApsrRegister::kZMsk;
187 break;
188 }
189 case 0b001U: { // CS - Carry set or CC - Carry clear
190 auto apsr = cpua.template ReadSpecialRegister<SpecialRegisterId::kApsr>();
191 result = (apsr & ApsrRegister::kCMsk) == ApsrRegister::kCMsk;
192 break;
193 }
194 case 0b010U: { // MI - Minus, negative or PL - Plus, positive or zero
195 auto apsr = cpua.template ReadSpecialRegister<SpecialRegisterId::kApsr>();
196 result = (apsr & ApsrRegister::kNMsk) == ApsrRegister::kNMsk;
197 break;
198 }
199 case 0b011U: { // VS - Overflow or VC - No overflow
200 auto apsr = cpua.template ReadSpecialRegister<SpecialRegisterId::kApsr>();
201 result = (apsr & ApsrRegister::kVMsk) == ApsrRegister::kVMsk;
202 break;
203 }
204 case 0b100U: { // HI - Unsigned higher or LS - Unsigned lower or same
205 auto apsr = cpua.template ReadSpecialRegister<SpecialRegisterId::kApsr>();
206 result = ((apsr & ApsrRegister::kCMsk) == ApsrRegister::kCMsk) &&
207 ((apsr & ApsrRegister::kZMsk) != ApsrRegister::kZMsk);
208 break;
209 }
210 case 0b101U: { // GE - Signed greater than or equal or LT - Signed less than
211 auto apsr = cpua.template ReadSpecialRegister<SpecialRegisterId::kApsr>();
212 result = ((apsr & ApsrRegister::kNMsk) >> ApsrRegister::kNPos) ==
213 ((apsr & ApsrRegister::kVMsk) >> ApsrRegister::kVPos);
214 break;
215 }
216 case 0b110U: { // GT - Signed greater than or LE - Signed less than or
217 // equal
218 auto apsr = cpua.template ReadSpecialRegister<SpecialRegisterId::kApsr>();
219 result = (((apsr & ApsrRegister::kNMsk) >> ApsrRegister::kNPos) ==
220 ((apsr & ApsrRegister::kVMsk) >> ApsrRegister::kVPos)) &&
221 ((apsr & ApsrRegister::kZMsk) != ApsrRegister::kZMsk);
222 break;
223 }
224 case 0b111U: { // AL - Always
225 result = true;
226 break;
227 }
228 default: {
229 // should not happen
230 assert(false);
231 }
232 }
233
234 // Condition flag values in the set '111x' indicate the instruction is
235 // always executed Otherwise, invert condition if necessary.
236
237 // if cond<0> == '1' && cond != '1111' then result = !result;
238 if (((cond & 0x1U) == 0x1U) && (cond != 0xFU)) {
239 result = !result;
240 }
241
242 return result;
243 }
244
245 static inline Result<bool> ConditionPassed(const TCpuAccessor &cpua) {
246 // see Armv7-M Architecture Reference Manual Issue E.e p.179
247
248 const auto r_cond = CurrentCond(cpua);
249 if (r_cond.IsErr()) {
250 return Err<u32, bool>(r_cond);
251 }
252
253 const auto &cond = r_cond.content;
254
255 return Ok(ConditionPassed(cpua, cond));
256 }
257};
258
259} // namespace libmicroemu::internal
IfThenOps & operator=(IfThenOps &&r_src)=delete
Move assignment operator for IfThenOps.
~IfThenOps()=delete
Destructor.
IfThenOps(IfThenOps &&r_src)=delete
Move constructor for IfThenOps.
IfThenOps(IfThenOps &r_src)=delete
Copy constructor for IfThenOps.
IfThenOps()=delete
Constructs a IfThenOps object.
IfThenOps & operator=(const IfThenOps &r_src)=delete
Copy assignment operator for IfThenOps.
The libmicroemu::internal namespace contains all classes and functions of libmicroemu which are priva...
Definition bkpt_flags.h:6
@ kExecutorUnpredictable
Executor encountered an unpredictable operation.
Definition status_code.h:76
Contains the Result class which is used to return the result of a function.
This file contains the declaration of the SpecialRegisterId enumeration and related functions.