libmicroemu 0.2.0
ARM Microcontroller Emulator Library
Loading...
Searching...
No Matches
ternary_instr_with_shift.h
1#pragma once
2#include "libmicroemu/internal/decoder/decoder.h"
3#include "libmicroemu/internal/executor/instr/post_exec.h"
4#include "libmicroemu/internal/executor/instr_context.h"
5#include "libmicroemu/internal/executor/instr_exec_results.h"
7#include "libmicroemu/internal/utils/rarg.h"
8#include "libmicroemu/register_details.h"
9#include "libmicroemu/types.h"
10
11namespace libmicroemu::internal {
12
18template <typename TInstrContext> class Eor2ShiftOp {
19public:
20 template <typename TDest, typename TArg0, typename TArg1>
21 static Result<InstrExecFlagsSet> Call(TInstrContext &ictx, const InstrFlagsSet &iflags,
22 const TDest &rd, const TArg0 &rn, const TArg1 &rm,
23 const ImmShiftResults &shift_res) {
24 auto n = ictx.cpua.ReadRegister(rn.Get());
25 auto m = ictx.cpua.ReadRegister(rm.Get());
26 auto apsr = ictx.cpua.template ReadSpecialRegister<SpecialRegisterId::kApsr>();
27 const auto shift_val = Alu32::Shift_C(m, shift_res.type, shift_res.value,
28 (apsr & ApsrRegister::kCMsk) == ApsrRegister::kCMsk);
29 const auto &shifted = shift_val.result;
30
31 const u32 result = Alu32::EOR(n, shifted);
32 const auto op_res =
33 OpResult{result, shift_val.carry_out, (apsr & ApsrRegister::kVMsk) == ApsrRegister::kVMsk};
34
35 PostExecWriteRegPcExcluded::Call(ictx, rd, op_res.value);
36 PostExecOptionalSetFlags::Call(ictx, iflags, op_res);
37 PostExecAdvancePcAndIt::Call(ictx, iflags);
38 return Ok(kNoInstrExecFlags);
39 }
40};
41
47template <typename TInstrContext> class Orr2ShiftOp {
48public:
49 template <typename TDest, typename TArg0, typename TArg1>
50 static Result<InstrExecFlagsSet> Call(TInstrContext &ictx, const InstrFlagsSet &iflags,
51 const TDest &rd, const TArg0 &rn, const TArg1 &rm,
52 const ImmShiftResults &shift_res) {
53 auto n = ictx.cpua.ReadRegister(rn.Get());
54 auto m = ictx.cpua.ReadRegister(rm.Get());
55 auto apsr = ictx.cpua.template ReadSpecialRegister<SpecialRegisterId::kApsr>();
56 const auto shift_val = Alu32::Shift_C(m, shift_res.type, shift_res.value,
57 (apsr & ApsrRegister::kCMsk) == ApsrRegister::kCMsk);
58 const auto &shifted = shift_val.result;
59
60 const u32 result = Alu32::OR(n, shifted);
61 const auto op_res =
62 OpResult{result, shift_val.carry_out, (apsr & ApsrRegister::kVMsk) == ApsrRegister::kVMsk};
63 PostExecWriteRegPcExcluded::Call(ictx, rd, op_res.value);
64 PostExecOptionalSetFlags::Call(ictx, iflags, op_res);
65 PostExecAdvancePcAndIt::Call(ictx, iflags);
66 return Ok(kNoInstrExecFlags);
67 }
68};
69
75template <typename TInstrContext> class And2ShiftOp {
76public:
77 template <typename TDest, typename TArg0, typename TArg1>
78 static Result<InstrExecFlagsSet> Call(TInstrContext &ictx, const InstrFlagsSet &iflags,
79 const TDest &rd, const TArg0 &rn, const TArg1 &rm,
80 const ImmShiftResults &shift_res) {
81 auto n = ictx.cpua.ReadRegister(rn.Get());
82 auto m = ictx.cpua.ReadRegister(rm.Get());
83 auto apsr = ictx.cpua.template ReadSpecialRegister<SpecialRegisterId::kApsr>();
84 const auto shift_val = Alu32::Shift_C(m, shift_res.type, shift_res.value,
85 (apsr & ApsrRegister::kCMsk) == ApsrRegister::kCMsk);
86 const auto &shifted = shift_val.result;
87
88 const u32 result = Alu32::AND(n, shifted);
89 const auto op_res =
90 OpResult{result, shift_val.carry_out, (apsr & ApsrRegister::kVMsk) == ApsrRegister::kVMsk};
91 PostExecWriteRegPcExcluded::Call(ictx, rd, op_res.value);
92 PostExecOptionalSetFlags::Call(ictx, iflags, op_res);
93 PostExecAdvancePcAndIt::Call(ictx, iflags);
94 return Ok(kNoInstrExecFlags);
95 }
96};
97
103template <typename TInstrContext> class Bic2ShiftOp {
104public:
105 template <typename TDest, typename TArg0, typename TArg1>
106 static Result<InstrExecFlagsSet> Call(TInstrContext &ictx, const InstrFlagsSet &iflags,
107 const TDest &rd, const TArg0 &rn, const TArg1 &rm,
108 const ImmShiftResults &shift_res) {
109 auto n = ictx.cpua.ReadRegister(rn.Get());
110 auto m = ictx.cpua.ReadRegister(rm.Get());
111 auto apsr = ictx.cpua.template ReadSpecialRegister<SpecialRegisterId::kApsr>();
112 const auto shift_val = Alu32::Shift_C(m, shift_res.type, shift_res.value,
113 (apsr & ApsrRegister::kCMsk) == ApsrRegister::kCMsk);
114 const auto &shifted = shift_val.result;
115
116 const u32 result = Alu32::AND(n, ~shifted);
117 const auto op_res =
118 OpResult{result, shift_val.carry_out, (apsr & ApsrRegister::kVMsk) == ApsrRegister::kVMsk};
119 PostExecWriteRegPcExcluded::Call(ictx, rd, op_res.value);
120 PostExecOptionalSetFlags::Call(ictx, iflags, op_res);
121 PostExecAdvancePcAndIt::Call(ictx, iflags);
122 return Ok(kNoInstrExecFlags);
123 }
124};
125
131template <typename TInstrContext> class Sbc2ShiftOp {
132public:
133 template <typename TDest, typename TArg0, typename TArg1>
134 static Result<InstrExecFlagsSet> Call(TInstrContext &ictx, const InstrFlagsSet &iflags,
135 const TDest &rd, const TArg0 &rn, const TArg1 &rm,
136 const ImmShiftResults &shift_res) {
137 auto n = ictx.cpua.ReadRegister(rn.Get());
138 auto m = ictx.cpua.ReadRegister(rm.Get());
139 auto apsr = ictx.cpua.template ReadSpecialRegister<SpecialRegisterId::kApsr>();
140 const auto shifted = Alu32::Shift(m, shift_res.type, shift_res.value,
141 (apsr & ApsrRegister::kCMsk) == ApsrRegister::kCMsk);
142 const auto result =
143 Alu32::AddWithCarry(n, ~shifted, (apsr & ApsrRegister::kCMsk) == ApsrRegister::kCMsk);
144
145 const auto op_res = OpResult{result.value, result.carry_out, result.overflow};
146 PostExecWriteRegPcExcluded::Call(ictx, rd, op_res.value);
147 PostExecOptionalSetFlags::Call(ictx, iflags, op_res);
148 PostExecAdvancePcAndIt::Call(ictx, iflags);
149 return Ok(kNoInstrExecFlags);
150 }
151};
152
158template <typename TInstrContext> class Sub2ShiftOp {
159public:
160 template <typename TDest, typename TArg0, typename TArg1>
161 static Result<InstrExecFlagsSet> Call(TInstrContext &ictx, const InstrFlagsSet &iflags,
162 const TDest &rd, const TArg0 &rn, const TArg1 &rm,
163 const ImmShiftResults &shift_res) {
164 auto n = ictx.cpua.ReadRegister(rn.Get());
165 auto m = ictx.cpua.ReadRegister(rm.Get());
166 auto apsr = ictx.cpua.template ReadSpecialRegister<SpecialRegisterId::kApsr>();
167 const auto shifted = Alu32::Shift(m, shift_res.type, shift_res.value,
168 (apsr & ApsrRegister::kCMsk) == ApsrRegister::kCMsk);
169 const auto result = Alu32::AddWithCarry(n, ~shifted, true);
170 const auto op_res = OpResult{result.value, result.carry_out, result.overflow};
171 PostExecWriteRegPcExcluded::Call(ictx, rd, op_res.value);
172 PostExecOptionalSetFlags::Call(ictx, iflags, op_res);
173 PostExecAdvancePcAndIt::Call(ictx, iflags);
174 return Ok(kNoInstrExecFlags);
175 }
176};
177
183template <typename TInstrContext> class Rsb2ShiftOp {
184public:
185 template <typename TDest, typename TArg0, typename TArg1>
186 static Result<InstrExecFlagsSet> Call(TInstrContext &ictx, const InstrFlagsSet &iflags,
187 const TDest &rd, const TArg0 &rn, const TArg1 &rm,
188 const ImmShiftResults &shift_res) {
189 auto n = ictx.cpua.ReadRegister(rn.Get());
190 auto m = ictx.cpua.ReadRegister(rm.Get());
191 auto apsr = ictx.cpua.template ReadSpecialRegister<SpecialRegisterId::kApsr>();
192 const auto shifted = Alu32::Shift(m, shift_res.type, shift_res.value,
193 (apsr & ApsrRegister::kCMsk) == ApsrRegister::kCMsk);
194 const auto result = Alu32::AddWithCarry(~n, shifted, true);
195 const auto op_res = OpResult{result.value, result.carry_out, result.overflow};
196 PostExecWriteRegPcExcluded::Call(ictx, rd, op_res.value);
197 PostExecOptionalSetFlags::Call(ictx, iflags, op_res);
198 PostExecAdvancePcAndIt::Call(ictx, iflags);
199 return Ok(kNoInstrExecFlags);
200 }
201};
202
207template <typename TInstrContext> class Add2ShiftOp {
208public:
209 template <typename TDest, typename TArg0, typename TArg1>
210 static Result<InstrExecFlagsSet> Call(TInstrContext &ictx, const InstrFlagsSet &iflags,
211 const TDest &rd, const TArg0 &rn, const TArg1 &rm,
212 const ImmShiftResults &shift_res) {
213 auto n = ictx.cpua.ReadRegister(rn.Get());
214 auto m = ictx.cpua.ReadRegister(rm.Get());
215 auto apsr = ictx.cpua.template ReadSpecialRegister<SpecialRegisterId::kApsr>();
216 const auto shifted = Alu32::Shift(m, shift_res.type, shift_res.value,
217 (apsr & ApsrRegister::kCMsk) == ApsrRegister::kCMsk);
218 const auto result = Alu32::AddWithCarry(n, shifted, false);
219 const auto op_res = OpResult{result.value, result.carry_out, result.overflow};
220 PostExecWriteRegPcExcluded::Call(ictx, rd, op_res.value);
221 PostExecOptionalSetFlags::Call(ictx, iflags, op_res);
222 PostExecAdvancePcAndIt::Call(ictx, iflags);
223 return Ok(kNoInstrExecFlags);
224 }
225};
226
231template <typename TInstrContext> class Adc2ShiftOp {
232public:
233 template <typename TDest, typename TArg0, typename TArg1>
234 static Result<InstrExecFlagsSet> Call(TInstrContext &ictx, const InstrFlagsSet &iflags,
235 const TDest &rd, const TArg0 &rn, const TArg1 &rm,
236 const ImmShiftResults &shift_res) {
237 auto n = ictx.cpua.ReadRegister(rn.Get());
238 auto m = ictx.cpua.ReadRegister(rm.Get());
239 auto apsr = ictx.cpua.template ReadSpecialRegister<SpecialRegisterId::kApsr>();
240 const auto shifted = Alu32::Shift(m, shift_res.type, shift_res.value,
241 (apsr & ApsrRegister::kCMsk) == ApsrRegister::kCMsk);
242 const auto result =
243 Alu32::AddWithCarry(n, shifted, (apsr & ApsrRegister::kCMsk) == ApsrRegister::kCMsk);
244 const auto op_res = OpResult{result.value, result.carry_out, result.overflow};
245 PostExecWriteRegPcExcluded::Call(ictx, rd, op_res.value);
246 PostExecOptionalSetFlags::Call(ictx, iflags, op_res);
247 PostExecAdvancePcAndIt::Call(ictx, iflags);
248 return Ok(kNoInstrExecFlags);
249 }
250};
251
252template <typename TOp, typename TInstrContext> class TernaryInstrWithShift {
253public:
254 using It = typename TInstrContext::It;
255 using Pc = typename TInstrContext::Pc;
256
257 template <typename TDest, typename TArg0, typename TArg1>
258 static Result<InstrExecResult> Call(TInstrContext &ictx, const InstrFlagsSet &iflags,
259 const TDest &rd, const TArg0 &rn, const TArg1 &rm,
260 const ImmShiftResults &shift_res) {
261 TRY_ASSIGN(condition_passed, InstrExecResult, It::ConditionPassed(ictx.cpua));
262 if (!condition_passed) {
263 PostExecAdvancePcAndIt::Call(ictx, iflags);
264 return Ok(InstrExecResult{kNoInstrExecFlags});
265 }
266
267 TRY_ASSIGN(eflags, InstrExecResult, TOp::Call(ictx, iflags, rd, rn, rm, shift_res));
268
269 return Ok(InstrExecResult{eflags});
270 }
271
272private:
276 TernaryInstrWithShift() = delete;
277
281 ~TernaryInstrWithShift() = delete;
282
287 TernaryInstrWithShift(const TernaryInstrWithShift &r_src) = delete;
288
293 TernaryInstrWithShift &operator=(const TernaryInstrWithShift &r_src) = delete;
294
299 TernaryInstrWithShift(TernaryInstrWithShift &&r_src) = delete;
300
305 TernaryInstrWithShift &operator=(TernaryInstrWithShift &&r_src) = delete;
306};
307
308} // namespace libmicroemu::internal
Adc.
Definition ternary_instr_with_shift.h:231
Add.
Definition ternary_instr_with_shift.h:207
And operation.
Definition ternary_instr_with_shift.h:75
Bit clear operation.
Definition ternary_instr_with_shift.h:103
Exclusive Or operation.
Definition ternary_instr_with_shift.h:18
Orr operation.
Definition ternary_instr_with_shift.h:47
Reverse Subtract.
Definition ternary_instr_with_shift.h:183
Subtract with carry.
Definition ternary_instr_with_shift.h:131
Subtract.
Definition ternary_instr_with_shift.h:158
The libmicroemu::internal namespace contains all classes and functions of libmicroemu which are priva...
Definition bkpt_flags.h:6
Contains the Result class which is used to return the result of a function.
#define TRY_ASSIGN(NAME, OUT_TYPE, CALL)
Try to assign a value to a variable and return an error if the assignment fails.
Definition result.h:123
Definition imm_shift_results.h:15
Definition instr_exec_results.h:23
Definition post_exec.h:12
Definition result.h:15