libmicroemu 0.2.0
ARM Microcontroller Emulator Library
Loading...
Searching...
No Matches
ternary_null_instr_with_shift.h
1#pragma once
2#include "libmicroemu/internal/decoder/decoder.h"
3
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 Cmp2ShiftOp {
19public:
20 template <typename TArg0, typename TArg1>
21 static Result<InstrExecFlagsSet> Call(TInstrContext &ictx, const InstrFlagsSet &iflags,
22 const TArg0 &rm, const TArg1 &rn,
23 const ImmShiftResults &shift_res) {
24 auto apsr = ictx.cpua.template ReadSpecialRegister<SpecialRegisterId::kApsr>();
25 const auto m = ictx.cpua.ReadRegister(rm.Get());
26 const auto n = ictx.cpua.ReadRegister(rn.Get());
27
28 const auto shifted = Alu32::Shift(m, static_cast<SRType>(shift_res.type), shift_res.value,
29 (apsr & ApsrRegister::kCMsk) == ApsrRegister::kCMsk);
30
31 const auto result = Alu32::AddWithCarry(n, ~shifted, true);
32 const auto op_res = OpResult{result.value, result.carry_out, result.overflow};
33 PostExecSetFlags::Call(ictx, op_res);
34 PostExecAdvancePcAndIt::Call(ictx, iflags);
35 return Ok(kNoInstrExecFlags);
36 }
37};
38
44template <typename TInstrContext> class Tst2ShiftOp {
45public:
46 template <typename TArg0, typename TArg1>
47 static Result<InstrExecFlagsSet> Call(TInstrContext &ictx, const InstrFlagsSet &iflags,
48 const TArg0 &rm, const TArg1 &rn,
49 const ImmShiftResults &shift_res) {
50 auto apsr = ictx.cpua.template ReadSpecialRegister<SpecialRegisterId::kApsr>();
51 const auto m = ictx.cpua.ReadRegister(rm.Get());
52 const auto n = ictx.cpua.ReadRegister(rn.Get());
53
54 const auto r_shift_c = Alu32::Shift_C(m, shift_res.type, shift_res.value,
55 (apsr & ApsrRegister::kCMsk) == ApsrRegister::kCMsk);
56 const auto result = Alu32::AND(n, r_shift_c.result);
57
58 const auto op_res =
59 OpResult{result, r_shift_c.carry_out, (apsr & ApsrRegister::kVMsk) == ApsrRegister::kVMsk};
60
61 PostExecSetFlags::Call(ictx, op_res);
62 PostExecAdvancePcAndIt::Call(ictx, iflags);
63 return Ok(kNoInstrExecFlags);
64 }
65};
66
72template <typename TInstrContext> class Teq2ShiftOp {
73public:
74 template <typename TArg0, typename TArg1>
75 static Result<InstrExecFlagsSet> Call(TInstrContext &ictx, const InstrFlagsSet &iflags,
76 const TArg0 &rm, const TArg1 &rn,
77 const ImmShiftResults &shift_res) {
78 auto apsr = ictx.cpua.template ReadSpecialRegister<SpecialRegisterId::kApsr>();
79 const auto m = ictx.cpua.ReadRegister(rm.Get());
80 const auto n = ictx.cpua.ReadRegister(rn.Get());
81
82 const auto r_shift_c = Alu32::Shift_C(m, shift_res.type, shift_res.value,
83 (apsr & ApsrRegister::kCMsk) == ApsrRegister::kCMsk);
84 const auto result = Alu32::EOR(n, r_shift_c.result);
85 const auto op_res =
86 OpResult{result, r_shift_c.carry_out, (apsr & ApsrRegister::kVMsk) == ApsrRegister::kVMsk};
87
88 PostExecSetFlags::Call(ictx, op_res);
89 PostExecAdvancePcAndIt::Call(ictx, iflags);
90 return Ok(kNoInstrExecFlags);
91 }
92};
93
94template <typename TOp, typename TInstrContext> class TernaryNullInstrWithShift {
95public:
96 using It = typename TInstrContext::It;
97 using Pc = typename TInstrContext::Pc;
98
99 template <typename TArg0, typename TArg1>
100 static Result<InstrExecResult> Call(TInstrContext &ictx, const InstrFlagsSet &iflags,
101 const TArg0 &rm, const TArg1 &rn,
102 const ImmShiftResults &shift_res) {
103 TRY_ASSIGN(condition_passed, InstrExecResult, It::ConditionPassed(ictx.cpua));
104 if (!condition_passed) {
105 PostExecAdvancePcAndIt::Call(ictx, iflags);
106 return Ok(InstrExecResult{kNoInstrExecFlags});
107 }
108
109 TRY_ASSIGN(eflags, InstrExecResult, TOp::Call(ictx, iflags, rm, rn, shift_res));
110 return Ok(InstrExecResult{eflags});
111 }
112
113private:
117 TernaryNullInstrWithShift() = delete;
118
122 ~TernaryNullInstrWithShift() = delete;
123
128 TernaryNullInstrWithShift(const TernaryNullInstrWithShift &r_src) = delete;
129
134 TernaryNullInstrWithShift &operator=(const TernaryNullInstrWithShift &r_src) = delete;
135
140 TernaryNullInstrWithShift(TernaryNullInstrWithShift &&r_src) = delete;
141
146 TernaryNullInstrWithShift &operator=(TernaryNullInstrWithShift &&r_src) = delete;
147};
148
149} // namespace libmicroemu::internal
Compare two registers.
Definition ternary_null_instr_with_shift.h:18
TEQ - Test two registers.
Definition ternary_null_instr_with_shift.h:72
TST - Test two registers.
Definition ternary_null_instr_with_shift.h:44
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