2#include "libmicroemu/internal/decoder/decoder.h"
3#include "libmicroemu/internal/executor/instr_context.h"
4#include "libmicroemu/internal/executor/instr_exec_results.h"
5#include "libmicroemu/internal/i_breakpoint.h"
8#include "libmicroemu/internal/utils/rarg.h"
9#include "libmicroemu/logger.h"
10#include "libmicroemu/register_details.h"
12#include "libmicroemu/types.h"
16template <
typename TInstrContext,
typename TLogger = NullLogger>
class SpecialInstr {
18 using TCpuAccessor =
decltype(TInstrContext::cpua);
19 using It =
typename TInstrContext::It;
20 using Pc =
typename TInstrContext::Pc;
22 using ExcTrig =
typename TInstrContext::ExcTrig;
29 const u32 &firstcond,
const u32 &mask) {
30 const auto is_32bit = (iflags &
static_cast<InstrFlagsSet
>(InstrFlags::k32Bit)) != 0U;
31 auto istate = ictx.cpua.template ReadSpecialRegister<SpecialRegisterId::kIstate>();
32 istate = firstcond << 4U | mask;
34 ictx.cpua.template WriteSpecialRegister<SpecialRegisterId::kIstate>(istate);
35 Pc::AdvanceInstr(ictx.cpua, is_32bit);
44 template <
typename TDelegates>
46 const u32 &imm32, TDelegates &delegates) {
48 if (!condition_passed) {
49 PostExecAdvancePcAndIt::Call(ictx, iflags);
52 InstrExecFlagsSet eflags{kNoInstrExecFlags};
53 if (delegates.IsSvcSet()) {
56 if ((svc_flags &
static_cast<SvcFlagsSet
>(SvcFlags::kRequestExit)) != 0U) {
57 eflags |=
static_cast<InstrExecFlagsSet
>(InstrExecFlags::kSvcReqExit);
58 }
else if ((svc_flags &
static_cast<SvcFlagsSet
>(SvcFlags::kRequestErrorExit)) != 0U) {
59 eflags |=
static_cast<InstrExecFlagsSet
>(InstrExecFlags::kSvcReqErrorExit);
62 if ((svc_flags &
static_cast<SvcFlagsSet
>(SvcFlags::kOmitException)) == 0U) {
68 PostExecAdvancePcAndIt::Call(ictx, iflags);
77 template <
typename TDelegates>
79 const u32 &imm32, TDelegates &delegates) {
80 InstrExecFlagsSet eflags{kNoInstrExecFlags};
81 if (delegates.IsBkptSet()) {
84 if ((bkpt_flags &
static_cast<BkptFlagsSet
>(BkptFlags::kRequestExit)) != 0U) {
85 eflags |=
static_cast<InstrExecFlagsSet
>(InstrExecFlags::kBkptReqExit);
86 }
else if ((bkpt_flags &
static_cast<BkptFlagsSet
>(BkptFlags::kRequestErrorExit)) != 0U) {
87 eflags |=
static_cast<InstrExecFlagsSet
>(InstrExecFlags::kBkptReqErrorExit);
89 if ((bkpt_flags &
static_cast<BkptFlagsSet
>(BkptFlags::kOmitException)) == 0U) {
95 PostExecAdvancePcAndIt::Call(ictx, iflags);
105 const u32 &imm32,
const u8 &cond) {
106 const auto condition_passed = It::ConditionPassed(ictx.cpua, cond);
107 if (!condition_passed) {
108 PostExecAdvancePcAndIt::Call(ictx, iflags);
111 const me_adr_t pc =
static_cast<me_adr_t
>(ictx.cpua.template ReadRegister<RegisterId::kPc>());
112 Pc::BranchWritePC(ictx.cpua, pc + imm32);
121 template <
typename TDest,
typename TArg0>
123 const TDest &rd,
const TArg0 &rn,
const u8 &lsbit,
126 if (!condition_passed) {
127 PostExecAdvancePcAndIt::Call(ictx, iflags);
130 if (msbit >= lsbit) {
131 const auto n = ictx.cpua.ReadRegister(rn.Get());
132 const auto d = ictx.cpua.ReadRegister(rd.Get());
134 const auto src_bitmask =
static_cast<u32
>(
static_cast<u32
>(1U) << (msbit - lsbit + 1U)) - 1U;
135 const auto dest_bitmask =
static_cast<u32
>(
136 ((
static_cast<u32
>(1U) << (msbit - lsbit + 1U)) -
static_cast<u32
>(1U)) << lsbit);
138 const auto rn_slice = (n & src_bitmask) << lsbit;
139 const auto rd_result = (d & ~dest_bitmask) | rn_slice;
141 ictx.cpua.WriteRegister(rd.Get(), rd_result);
146 PostExecAdvancePcAndIt::Call(ictx, iflags);
155 template <
typename TDest,
typename TArg0>
157 const TDest &rd,
const TArg0 &rn,
const u8 &lsbit,
158 const u8 &widthminus1) {
160 if (!condition_passed) {
161 PostExecAdvancePcAndIt::Call(ictx, iflags);
165 const u8 msbit = lsbit + widthminus1;
170 u32 msk = ((
static_cast<u32
>(1U) << (msbit - lsbit + 1U)) -
static_cast<u32
>(1U)) << lsbit;
171 const auto n = ictx.cpua.ReadRegister(rn.Get());
172 const auto result = (n & msk) >> lsbit;
174 PostExecWriteRegPcExcluded::Call(ictx, rd, result);
175 PostExecAdvancePcAndIt::Call(ictx, iflags);
184 template <
typename TTgt0,
typename TTgt1,
typename TArg0>
186 const TTgt0 &rt,
const TTgt1 &rt2,
const TArg0 &rn,
188 const bool is_wback = (iflags &
static_cast<InstrFlagsSet
>(InstrFlags::kWBack)) != 0U;
189 const bool is_index = (iflags &
static_cast<InstrFlagsSet
>(InstrFlags::kIndex)) != 0U;
190 const bool is_add = (iflags &
static_cast<InstrFlagsSet
>(InstrFlags::kAdd)) != 0U;
194 if (!condition_passed) {
195 PostExecAdvancePcAndIt::Call(ictx, iflags);
198 const auto n = ictx.cpua.ReadRegister(rn.Get());
199 const me_adr_t offset_addr = is_add ==
true ? n + imm32 : n - imm32;
200 const me_adr_t address = is_index ==
true ? offset_addr : n;
204 ictx.bus.template ReadOrRaise<u32>(ictx.cpua, address,
205 BusExceptionType::kRaisePreciseDataBusError));
207 ictx.bus.template ReadOrRaise<u32>(ictx.cpua, address + 0x4U,
208 BusExceptionType::kRaisePreciseDataBusError));
210 PostExecWriteRegPcExcluded::Call(ictx, rn, offset_addr);
212 PostExecWriteRegPcExcluded::Call(ictx, rt, data);
213 PostExecWriteRegPcExcluded::Call(ictx, rt2, data2);
214 PostExecAdvancePcAndIt::Call(ictx, iflags);
224 template <
typename TArg0>
226 const TArg0 &rn,
const uint8_t mask,
const uint8_t SYSm) {
228 if (!condition_passed) {
229 PostExecAdvancePcAndIt::Call(ictx, iflags);
233 const auto n = ictx.cpua.ReadRegister(rn.Get());
239 assert(
false &&
"not implemented");
242 assert(
false &&
"not implemented");
251 ictx.cpua.template WriteSpecialRegister<SpecialRegisterId::kSpMain>(n);
252 LOG_TRACE(TLogger,
"MSR Call - Write main stack pointer: 0x%08X", rn);
257 ictx.cpua.template WriteSpecialRegister<SpecialRegisterId::kSpProcess>(n);
258 LOG_TRACE(TLogger,
"MSR Call - Write process stack pointer: 0x%08X", rn);
263 assert(
false &&
"undefined");
273 assert(
false &&
"not implemented");
277 assert(
false &&
"not implemented");
281 assert(
false &&
"not implemented");
285 assert(
false &&
"not implemented");
292 auto control = ictx.cpua.template ReadSpecialRegister<SpecialRegisterId::kControl>();
295 control |= ((n & 0x1U) >> 0U) << ControlRegister::kNPrivPos;
299 control |= ((n & 0x2U) >> 1U) << ControlRegister::kSpselPos;
301 LOG_TRACE(TLogger,
"MSR Call - Write CONTROL: 0x%08X", control);
303 ictx.cpua.template WriteSpecialRegister<SpecialRegisterId::kControl>(control);
311 assert(
false &&
"undefined");
317 assert(
false &&
"undefined");
321 PostExecAdvancePcAndIt::Call(ictx, iflags);
330 template <
typename TDest>
332 const TDest &rd,
const uint8_t mask,
const uint8_t SYSm) {
334 if (!condition_passed) {
335 PostExecAdvancePcAndIt::Call(ictx, iflags);
345 assert(
false &&
"not implemented");
348 assert(
false &&
"not implemented");
357 rd_val = ictx.cpua.template ReadSpecialRegister<SpecialRegisterId::kSpMain>();
358 LOG_TRACE(TLogger,
"MRS Call - Read MSP: 0x%08X", rd_val);
363 rd_val = ictx.cpua.template ReadSpecialRegister<SpecialRegisterId::kSpProcess>();
364 LOG_TRACE(TLogger,
"MRS Call - Read PSP: 0x%08X", rd_val);
369 assert(
false &&
"undefined");
379 assert(
false &&
"not implemented");
383 assert(
false &&
"not implemented");
387 assert(
false &&
"not implemented");
391 assert(
false &&
"not implemented");
396 const auto control = ictx.cpua.template ReadSpecialRegister<SpecialRegisterId::kControl>();
400 rd_val |= control & ControlRegister::kControlBit2toBit0Msk;
404 rd_val |= control & ControlRegister::kControlBit1toBit0Msk;
407 LOG_TRACE(TLogger,
"MRS Call - Read CONTROL: 0x%08X", rd_val);
412 assert(
false &&
"undefined");
418 assert(
false &&
"undefined");
422 PostExecWriteRegPcExcluded::Call(ictx, rd, rd_val);
423 PostExecAdvancePcAndIt::Call(ictx, iflags);
432 template <
typename TTgt,
typename TArg0,
typename TArg1>
434 const TTgt &rt,
const TArg0 &rt2,
const TArg1 &rn,
437 const bool is_wback = (iflags &
static_cast<InstrFlagsSet
>(InstrFlags::kWBack)) != 0U;
438 const bool is_index = (iflags &
static_cast<InstrFlagsSet
>(InstrFlags::kIndex)) != 0U;
439 const bool is_add = (iflags &
static_cast<InstrFlagsSet
>(InstrFlags::kAdd)) != 0U;
442 if (!condition_passed) {
443 PostExecAdvancePcAndIt::Call(ictx, iflags);
446 const auto n = ictx.cpua.ReadRegister(rn.Get());
448 const u32 offset_addr = is_add ==
true ? n + imm32 : n - imm32;
449 const u32 address = is_index ==
true ? offset_addr : n;
451 const auto t = ictx.cpua.ReadRegister(rt.Get());
453 ictx.cpua, address, t, BusExceptionType::kRaisePreciseDataBusError));
456 const auto t2 = ictx.cpua.ReadRegister(rt2.Get());
458 ictx.bus.template WriteOrRaise<u32>(ictx.cpua, address + 0x4, t2,
459 BusExceptionType::kRaisePreciseDataBusError));
462 PostExecWriteRegPcExcluded::Call(ictx, rn, offset_addr);
464 PostExecAdvancePcAndIt::Call(ictx, iflags);
static constexpr u32 ExtractBits1R(const u32 &value)
Definition bit_manip.h:136
static bool IsCurrentModePrivileged(TCpuAccessor &cpua)
Check if the cpu is in privileged mode.
Definition predicates.h:73
static bool IsThreadMode(const TCpuAccessor &cpua)
Check if the cpu is in thread mode.
Definition predicates.h:27
Definition special_instr.h:16
static Result< InstrExecResult > Ubfx(TInstrContext &ictx, const InstrFlagsSet &iflags, const TDest &rd, const TArg0 &rn, const u8 &lsbit, const u8 &widthminus1)
Ubfx.
Definition special_instr.h:156
static Result< InstrExecResult > ItInstr(TInstrContext &ictx, const InstrFlagsSet &iflags, const u32 &firstcond, const u32 &mask)
It instruction.
Definition special_instr.h:28
static Result< InstrExecResult > Msr(TInstrContext &ictx, const InstrFlagsSet &iflags, const TArg0 &rn, const uint8_t mask, const uint8_t SYSm)
Msr.
Definition special_instr.h:225
static Result< InstrExecResult > Bkpt(TInstrContext &ictx, const InstrFlagsSet &iflags, const u32 &imm32, TDelegates &delegates)
Bkpt instruction.
Definition special_instr.h:78
static Result< InstrExecResult > Strd(TInstrContext &ictx, const InstrFlagsSet &iflags, const TTgt &rt, const TArg0 &rt2, const TArg1 &rn, const u32 &imm32)
Strd.
Definition special_instr.h:433
static Result< InstrExecResult > Bfi(TInstrContext &ictx, const InstrFlagsSet &iflags, const TDest &rd, const TArg0 &rn, const u8 &lsbit, const u8 &msbit)
Bfi.
Definition special_instr.h:122
static Result< InstrExecResult > BCond(TInstrContext &ictx, const InstrFlagsSet &iflags, const u32 &imm32, const u8 &cond)
Branch condition.
Definition special_instr.h:104
static Result< InstrExecResult > Svc(TInstrContext &ictx, const InstrFlagsSet &iflags, const u32 &imm32, TDelegates &delegates)
Svc instruction.
Definition special_instr.h:45
static Result< InstrExecResult > Mrs(TInstrContext &ictx, const InstrFlagsSet &iflags, const TDest &rd, const uint8_t mask, const uint8_t SYSm)
Mrs.
Definition special_instr.h:331
static Result< InstrExecResult > Ldrd(TInstrContext &ictx, const InstrFlagsSet &iflags, const TTgt0 &rt, const TTgt1 &rt2, const TArg0 &rn, const u32 &imm32)
Ldrd.
Definition special_instr.h:185
The libmicroemu::internal namespace contains all classes and functions of libmicroemu which are priva...
Definition bkpt_flags.h:6
@ kSVCall
Exception for system calls.
Definition exception_type.h:48
@ kHardFault
Hard fault exception, triggered by faults that cannot be handled by any other exception.
Definition exception_type.h:21
@ kExecutorUnpredictable
Executor encountered an unpredictable operation.
Definition status_code.h:76
This file contains the declaration of the Predicates class.
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
#define TRY(OUT_TYPE, CALL)
Try to call a function and return an error if the call fails.
Definition result.h:138
This file contains the declaration of the SpecialRegisterId enumeration and related functions.
Definition register_details.h:273
Definition instr_exec_results.h:23