mirror of
https://github.com/mikage-emu/mikage-dev.git
synced 2025-01-08 14:30:59 +01:00
588 lines
20 KiB
C++
588 lines
20 KiB
C++
#pragma once
|
|
|
|
#include "bit_field.h"
|
|
|
|
#include <array>
|
|
#include <cassert>
|
|
#include <cstdint>
|
|
#include <stdexcept>
|
|
#include <type_traits>
|
|
|
|
namespace ARM {
|
|
|
|
using BitField::v1::ViewBitField;
|
|
using BitField::v1::BitField;
|
|
|
|
namespace Regs {
|
|
enum {
|
|
LR = 14,
|
|
PC = 15,
|
|
};
|
|
}
|
|
|
|
enum class ProcessorMode {
|
|
User = 0b10000,
|
|
FIQ = 0b10001,
|
|
IRQ = 0b10010,
|
|
Supervisor = 0b10011,
|
|
Abort = 0b10111,
|
|
Undefined = 0b11011,
|
|
System = 0b11111,
|
|
};
|
|
|
|
// More convenient internal storage
|
|
enum class InternalProcessorMode : uint32_t {
|
|
User,
|
|
FIQ,
|
|
IRQ,
|
|
Supervisor,
|
|
Abort,
|
|
Undefined,
|
|
System,
|
|
NumModes,
|
|
Invalid = NumModes // Reserved for actually invalid (or "reserved") processor modes
|
|
};
|
|
static constexpr size_t NumInternalProcessorModes = static_cast<size_t>(InternalProcessorMode::NumModes);
|
|
|
|
inline InternalProcessorMode MakeInternal(ProcessorMode mode) {
|
|
switch (mode) {
|
|
case ProcessorMode::User: return InternalProcessorMode::User;
|
|
case ProcessorMode::FIQ: return InternalProcessorMode::FIQ;
|
|
case ProcessorMode::IRQ: return InternalProcessorMode::IRQ;
|
|
case ProcessorMode::Supervisor: return InternalProcessorMode::Supervisor;
|
|
case ProcessorMode::Abort: return InternalProcessorMode::Abort;
|
|
case ProcessorMode::Undefined: return InternalProcessorMode::Undefined;
|
|
case ProcessorMode::System: return InternalProcessorMode::System;
|
|
default: return InternalProcessorMode::Invalid;
|
|
}
|
|
}
|
|
|
|
inline ProcessorMode MakeNative(InternalProcessorMode mode) {
|
|
switch (mode) {
|
|
case InternalProcessorMode::User: return ProcessorMode::User;
|
|
case InternalProcessorMode::FIQ: return ProcessorMode::FIQ;
|
|
case InternalProcessorMode::IRQ: return ProcessorMode::IRQ;
|
|
case InternalProcessorMode::Supervisor: return ProcessorMode::Supervisor;
|
|
case InternalProcessorMode::Abort: return ProcessorMode::Abort;
|
|
case InternalProcessorMode::Undefined: return ProcessorMode::Undefined;
|
|
case InternalProcessorMode::System: return ProcessorMode::System;
|
|
default: throw std::runtime_error("Invalid internal processor mode");
|
|
}
|
|
}
|
|
|
|
enum class AddressingShift : uint32_t {
|
|
LSL = 0,
|
|
LSR = 1,
|
|
ASR = 2,
|
|
ROR_RRX = 3
|
|
};
|
|
|
|
struct DoublePrecisionRegister {
|
|
uint32_t raw_low;
|
|
uint32_t raw_high;
|
|
};
|
|
|
|
struct State {
|
|
std::array<uint32_t,16> reg;
|
|
|
|
// VFP (floating point) registers
|
|
// TODO: Current usage of this union is not compatible with strict aliasing rules!
|
|
union {
|
|
std::array<float, 32> fpreg;
|
|
std::array<double, 16> dpreg;
|
|
std::array<DoublePrecisionRegister, 16> dpreg_raw;
|
|
};
|
|
|
|
// FP Status and Control Register
|
|
union {
|
|
uint32_t raw;
|
|
|
|
BitField<28, 1, uint32_t> unordered; // aka V
|
|
BitField<29, 1, uint32_t> greater_equal_unordered; // aka C
|
|
BitField<30, 1, uint32_t> equal; // aka Z
|
|
BitField<31, 1, uint32_t> less; // aka N
|
|
} fpscr;
|
|
|
|
// Current Program Status Register
|
|
union ProgramStatusRegister {
|
|
/**
|
|
* Copies the given PSR into *this, as if a memcpy() had been performed.
|
|
*/
|
|
void RawCopyFrom(const ProgramStatusRegister& psr) {
|
|
reinterpret_cast<uint32_t&>(*this) = reinterpret_cast<const uint32_t&>(psr);
|
|
}
|
|
|
|
// Processor Mode ("M"): Guaranteed to be one of the values defined in #InternalProcessorMode
|
|
BitField< 0, 5, InternalProcessorMode> mode; // "M"
|
|
|
|
// BitField< 0, 5, ProcessorMode> native_mode; // Used only for accessing within MSR. Do not use outside of that!
|
|
|
|
BitField< 5, 1, uint32_t> thumb; // "T"
|
|
|
|
BitField< 6, 1, uint32_t> F; // disable FIQ interrupts
|
|
BitField< 7, 1, uint32_t> I; // disable IRQ interrupts
|
|
BitField< 8, 1, uint32_t> A; // disable imprecise data aborts
|
|
|
|
BitField<16, 4, uint32_t> ge;
|
|
|
|
BitField<16, 2, uint32_t> ge10;
|
|
BitField<18, 2, uint32_t> ge32;
|
|
|
|
BitField<16, 1, uint32_t> ge0;
|
|
BitField<17, 1, uint32_t> ge1;
|
|
BitField<18, 1, uint32_t> ge2;
|
|
BitField<19, 1, uint32_t> ge3;
|
|
|
|
BitField<27, 1, uint32_t> q; // overflow or saturation in saturated integer arithmetic
|
|
|
|
BitField<28, 1, uint32_t> overflow; // "V"
|
|
BitField<29, 1, uint32_t> carry; // "C"
|
|
BitField<30, 1, uint32_t> zero; // "Z", "equal"
|
|
BitField<31, 1, uint32_t> neg; // "N"
|
|
|
|
bool InPrivilegedMode() const {
|
|
return (mode != InternalProcessorMode::User);
|
|
}
|
|
|
|
/**
|
|
* Fill PSR contents using the given value.
|
|
* This is required to make sure the processor mode field is converted to InternalProcessorMode properly.
|
|
*/
|
|
static ProgramStatusRegister FromNativeRaw32(uint32_t val) {
|
|
ProgramStatusRegister psr;
|
|
reinterpret_cast<uint32_t&>(psr) = val;
|
|
psr.mode = MakeInternal(ViewBitField<0, 5, ProcessorMode>(val));
|
|
return psr;
|
|
}
|
|
|
|
/**
|
|
* Return the raw uint32_t value expected by the ARM ISA.
|
|
* This is required to make sure the processor mode field is converted to ProcessorMode properly.
|
|
*/
|
|
uint32_t ToNativeRaw32() const {
|
|
uint32_t val = reinterpret_cast<const uint32_t&>(*this);
|
|
ViewBitField<0, 5, ProcessorMode>(val).Assign(MakeNative(mode));
|
|
return val;
|
|
}
|
|
};
|
|
|
|
ProgramStatusRegister cpsr;
|
|
ProgramStatusRegister spsr[NumInternalProcessorModes]; // The SPSRs for User and System are just dummies!
|
|
|
|
bool InPrivilegedMode() const {
|
|
return cpsr.InPrivilegedMode();
|
|
}
|
|
|
|
bool HasSPSR() const {
|
|
return (cpsr.mode != InternalProcessorMode::User && cpsr.mode != InternalProcessorMode::System);
|
|
}
|
|
|
|
ProgramStatusRegister& GetSPSR(InternalProcessorMode mode) {
|
|
return spsr[static_cast<uint32_t>(mode)];
|
|
}
|
|
|
|
std::array<uint32_t,7> banked_regs_user; // r8-r14 (virtual bank used whenever another mode has its registers banked in; shared with System mode)
|
|
std::array<uint32_t,8> banked_regs_fiq; // r8-r14 + SPSR_fiq
|
|
std::array<uint32_t,3> banked_regs_svc; // r13 + r14 + SPSR_fiq
|
|
std::array<uint32_t,3> banked_regs_abt; // r13 + r14 + SPSR_abt
|
|
std::array<uint32_t,3> banked_regs_irq; // r13 + r14 + SPSR_irq
|
|
std::array<uint32_t,3> banked_regs_und; // r13 + r14 + SPSR_und
|
|
|
|
/**
|
|
* Move the given PSR to the CPSR register, performing a mode switch and other handling if necessary
|
|
*/
|
|
void ReplaceCPSR(ProgramStatusRegister psr) {
|
|
if (cpsr.mode == psr.mode) {
|
|
cpsr.RawCopyFrom(psr);
|
|
return;
|
|
}
|
|
|
|
// Bank out current registers
|
|
switch (cpsr.mode) {
|
|
case InternalProcessorMode::User:
|
|
case InternalProcessorMode::System:
|
|
std::copy(®[8], ®[15], banked_regs_user.begin());
|
|
break;
|
|
|
|
case InternalProcessorMode::FIQ:
|
|
std::copy(®[8], ®[15], banked_regs_fiq.begin());
|
|
break;
|
|
|
|
case InternalProcessorMode::IRQ:
|
|
std::copy(®[13], ®[15], banked_regs_irq.begin());
|
|
break;
|
|
|
|
case InternalProcessorMode::Supervisor:
|
|
std::copy(®[13], ®[15], banked_regs_svc.begin());
|
|
break;
|
|
|
|
case InternalProcessorMode::Abort:
|
|
std::copy(®[13], ®[15], banked_regs_abt.begin());
|
|
break;
|
|
|
|
case InternalProcessorMode::Undefined:
|
|
std::copy(®[13], ®[15], banked_regs_und.begin());
|
|
break;
|
|
|
|
// It should not be possible to set cpsr.mode to this value
|
|
case InternalProcessorMode::Invalid:
|
|
assert(false);
|
|
break;
|
|
}
|
|
|
|
// Bank in new registers
|
|
switch (cpsr.mode) {
|
|
case InternalProcessorMode::User:
|
|
case InternalProcessorMode::System:
|
|
std::copy(banked_regs_user.begin(), banked_regs_user.end(), ®[8]);
|
|
break;
|
|
|
|
case InternalProcessorMode::FIQ:
|
|
std::copy(banked_regs_fiq.begin(), banked_regs_fiq.end(), ®[8]);
|
|
break;
|
|
|
|
case InternalProcessorMode::IRQ:
|
|
std::copy(banked_regs_irq.begin(), banked_regs_irq.end(), ®[13]);
|
|
break;
|
|
|
|
case InternalProcessorMode::Supervisor:
|
|
std::copy(banked_regs_svc.begin(), banked_regs_svc.end(), ®[13]);
|
|
break;
|
|
|
|
case InternalProcessorMode::Abort:
|
|
std::copy(banked_regs_abt.begin(), banked_regs_abt.end(), ®[13]);
|
|
break;
|
|
|
|
case InternalProcessorMode::Undefined:
|
|
std::copy(banked_regs_und.begin(), banked_regs_und.end(), ®[13]);
|
|
break;
|
|
|
|
// It should not be possible to set cpsr.mode to this value
|
|
case InternalProcessorMode::Invalid:
|
|
assert(false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint32_t& LR() {
|
|
return reg[14];
|
|
}
|
|
|
|
uint32_t& PC() {
|
|
return reg[15];
|
|
}
|
|
|
|
uint32_t FetchReg(unsigned index) {
|
|
if (index == 15)
|
|
return PC() + 8;
|
|
|
|
return reg[index];
|
|
}
|
|
|
|
union {
|
|
// NOTE: The internal mapping from "raw" to any of the getter functions below is arbitrary.
|
|
uint32_t raw[6];
|
|
|
|
auto& CPUId() {
|
|
union Type {
|
|
uint32_t raw;
|
|
|
|
BitField< 0, 4, uint32_t> CPUID;
|
|
BitField< 4, 4, uint32_t> reserved1; // SBZ
|
|
BitField< 8, 4, uint32_t> ClusterID;
|
|
BitField<12, 20, uint32_t> reserved2; // SBZ
|
|
};
|
|
return reinterpret_cast<Type&>(raw[2]);
|
|
}
|
|
|
|
auto& Control() {
|
|
union Type {
|
|
uint32_t raw;
|
|
|
|
BitField< 0, 1, uint32_t> M; // MMU enable
|
|
BitField< 1, 1, uint32_t> A; // strict alignment fault checking enable
|
|
BitField< 2, 1, uint32_t> C; // data cache enable
|
|
BitField< 3, 4, uint32_t> reserved1; // Should Be One
|
|
BitField< 7, 1, uint32_t> reserved2; // Should Be Zero
|
|
BitField< 8, 1, uint32_t> S; // System protection (deprecated)
|
|
BitField< 9, 1, uint32_t> R; // ROM protection (deprecated)
|
|
BitField<10, 1, uint32_t> reserved3; // Should Be Zero
|
|
BitField<11, 1, uint32_t> Z; // program flow prediction enable
|
|
BitField<12, 1, uint32_t> I; // L1 instruction cache enable
|
|
BitField<13, 1, uint32_t> V; // location of exception vectors: 0=normal(0x00000000), 1=high(0xFFFF0000)
|
|
BitField<14, 1, uint32_t> reserved4; // Read As One/Should Be One
|
|
BitField<15, 1, uint32_t> L4; // If zero, loads to PC will set the T bit (otherwise, they won't)
|
|
BitField<16, 6, uint32_t> reserved5; // Read As 0b000101
|
|
BitField<22, 1, uint32_t> U; // unaligned data access operation enable (including support for mixed-endianness data)
|
|
BitField<23, 1, uint32_t> XP; // hardware page translation: subpage AP bits enable
|
|
BitField<24, 1, uint32_t> reserved6; // SBZ/RAZ
|
|
BitField<25, 1, uint32_t> EE; // Value is copied to the E bit of CPSR when taking an exception
|
|
BitField<26, 1, uint32_t> reserved7; // SBZ/RAZ
|
|
BitField<27, 1, uint32_t> NMFI; // If one, FIQs behave as NMFIs (otherwise, they have normal behavior)
|
|
BitField<28, 1, uint32_t> TEX_remap; // TEX remap enable
|
|
BitField<29, 1, uint32_t> force_AP; // Force AP enable
|
|
BitField<30, 2, uint32_t> reserved8; // SBZ/RAZ
|
|
};
|
|
return reinterpret_cast<Type&>(raw[0]);
|
|
}
|
|
|
|
auto& AuxiliaryControl() {
|
|
union Type {
|
|
uint32_t raw;
|
|
|
|
BitField<0, 1, uint32_t> RS; // Return stack enable (set on reset)
|
|
BitField<1, 1, uint32_t> DB; // Dynamic branch prediction enable (set on reset)
|
|
BitField<2, 1, uint32_t> SB; // Static branch prediction enable (set on reset)
|
|
BitField<3, 1, uint32_t> F; // Instruction folding enable
|
|
BitField<4, 1, uint32_t> EXCL; // 0 = L1 and L2 caches are inclusive, 1 = caches are exclusive
|
|
BitField<5, 1, uint32_t> SMP; // 0 = AMP (no coherency), 1 = SMP (coherency)
|
|
BitField<6, 1, uint32_t> L1_parity_checking; // L1 parity checking enable
|
|
|
|
BitField<7, 25, uint32_t> reserved; // Should be preserved
|
|
};
|
|
return reinterpret_cast<Type&>(raw[1]);
|
|
}
|
|
|
|
// privileged modes, only
|
|
auto& TranslationTableBase0() {
|
|
union Type {
|
|
uint32_t raw;
|
|
|
|
BitField< 3, 2, uint32_t> RGN; // Out cachable attributes for page table walking
|
|
|
|
BitField< 1, 1, uint32_t> S; // Page table walk to shared (S=1) or nonshared (S=0) memory
|
|
|
|
// Bits 13-ttbc.N:5 UNP/SBZ.
|
|
|
|
/*template<typename TTBC>
|
|
uint32_t GetTTB0(const TTBC& ttbc) const {
|
|
// return 18-N uppermost bits
|
|
return BitFieldView<14, 18, uint32_t>(raw) >> ttbc.N;
|
|
}*/
|
|
};
|
|
return reinterpret_cast<Type&>(raw[3]);
|
|
}
|
|
|
|
// TODO: TranslationTableBase1
|
|
|
|
// privileged modes, only
|
|
auto& TranslationTableBaseControl() {
|
|
union Type {
|
|
uint32_t raw;
|
|
|
|
// NOTE: Reading this register (or specifically, "N") returns the size of the page table boundary for TTBR0. SBZ_UNP should be zero then.
|
|
// This is probably equivalent to just returning the value of N, though...
|
|
|
|
BitField< 0, 3, uint32_t> N; // 0=Use Translation Table Base Register 0; otherwise=Consider TTBR1
|
|
BitField< 3, 29, uint32_t> SBZ_UNP; // Should Be Zero or Unpredictable
|
|
};
|
|
return reinterpret_cast<Type&>(raw[4]);
|
|
}
|
|
|
|
// Accessible from all modes
|
|
auto& ThreadLocalStorage() {
|
|
union Type {
|
|
// TODO: Double-check that this does not contain any other fields
|
|
uint32_t virtual_addr;
|
|
};
|
|
return reinterpret_cast<Type&>(raw[5]);
|
|
}
|
|
} cp15;
|
|
|
|
uint64_t cycle_count;
|
|
};
|
|
static_assert(std::is_pod<State>::value, "State is not a POD type");
|
|
|
|
enum class OperandShifterMode : uint32_t {
|
|
LSL = 0, // Logical Shift Left
|
|
LSR = 1, // Logical Shift Right
|
|
ASR = 2, // Arithmetic Shift Right
|
|
ROR_RRX = 3, // ROtate Right or Rotate Right with Extend
|
|
};
|
|
|
|
union ARMInstr {
|
|
uint32_t raw;
|
|
|
|
BitField<28, 4, uint32_t> cond;
|
|
|
|
BitField<24, 4, uint32_t> opcode_prim;
|
|
BitField< 4, 20, uint32_t> identifier_4_23;
|
|
BitField<20, 8, uint32_t> identifier_20_27;
|
|
|
|
BitField< 0, 24, int32_t> branch_target;
|
|
|
|
BitField< 0, 8, uint32_t> immed_8;
|
|
|
|
BitField<22, 1, uint32_t> R;
|
|
|
|
BitField<25, 1, uint32_t> msr_I;
|
|
BitField<16, 4, uint32_t> msr_field_mask;
|
|
|
|
uint32_t ExpandMSRFieldMask() const {
|
|
return (msr_field_mask & 0x8) * (0xFF << 21)
|
|
| (msr_field_mask & 0x4) * (0xFF << 14)
|
|
| (msr_field_mask & 0x2) * (0xFF << 7)
|
|
| (msr_field_mask & 0x1) * 0xFF;
|
|
}
|
|
|
|
// Addressing Mode 1
|
|
BitField< 5, 2, OperandShifterMode> addr1_shift;
|
|
BitField< 7, 5, uint32_t> addr1_shift_imm;
|
|
BitField< 8, 4, uint32_t> rotate_imm;
|
|
BitField<20, 1, uint32_t> addr1_S; // update CPSR flags
|
|
|
|
BitField< 0, 4, uint32_t> addr3_immed_lo;
|
|
BitField< 8, 4, uint32_t> addr3_immed_hi;
|
|
|
|
// The HLS bits are weird: Originally they were used to configure
|
|
// signed/unsigned (S), load/store (L), and halfword/byte (H).
|
|
// However, certain configurations are invalid or have a different meaning:
|
|
// S=0, H=0 is a different instruction
|
|
// S=1, L=0 is used to define double-word access
|
|
BitField< 5, 1, uint32_t> addr3_H;
|
|
BitField< 6, 1, uint32_t> addr3_S;
|
|
BitField<20, 1, uint32_t> addr3_L;
|
|
|
|
// Addressing Mode 4 - Load/Store Multiple
|
|
BitField< 0, 16, uint32_t> addr4_registers;
|
|
BitField<20, 1, uint32_t> addr4_L; // 0=Store, 1=Load
|
|
BitField<21, 1, uint32_t> addr4_W; // Update base register after the transfer
|
|
BitField<22, 1, uint32_t> addr4_S; // ??
|
|
BitField<23, 1, uint32_t> addr4_U; // 0=Decrement address, 1=Increment address
|
|
BitField<24, 1, uint32_t> addr4_P; // 0=Change address after transfer, 1=Change address before transfer
|
|
|
|
// NOTE: Despite their name, these are generic to all adressing modes, it seems.
|
|
// TODO: These are actually addressing mode 2/5 fields
|
|
BitField<21, 1, uint32_t> ldr_W;
|
|
BitField<23, 1, uint32_t> ldr_U;
|
|
BitField<24, 1, uint32_t> ldr_P;
|
|
BitField<25, 1, uint32_t> ldr_I;
|
|
|
|
// For VFP instructions, this bit is used to select a register index (D=0: bottom 16 registers, D=1: top 16 registers)
|
|
BitField< 0, 8, uint32_t> addr5_offset; // actual offset is obtained by multiplying with 4
|
|
|
|
BitField<20, 1, uint32_t> addr5_L; // 0=Store, 1=Load
|
|
BitField<22, 1, uint32_t> addr5_D;
|
|
|
|
BitField< 5, 2, OperandShifterMode> ldr_shift;
|
|
BitField< 7, 5, uint32_t> ldr_shift_imm;
|
|
BitField< 0, 12, uint32_t> ldr_offset;
|
|
|
|
BitField< 0, 4, uint32_t> idx_rm;
|
|
BitField< 8, 4, uint32_t> idx_rs;
|
|
BitField<12, 4, uint32_t> idx_rd;
|
|
BitField<16, 4, uint32_t> idx_rn;
|
|
|
|
BitField<16, 5, uint32_t> sat_imm;
|
|
|
|
BitField< 6, 1, uint32_t> cps_F;
|
|
BitField< 7, 1, uint32_t> cps_I;
|
|
BitField< 8, 1, uint32_t> cps_A;
|
|
BitField<19, 1, uint32_t> cps_imod_enable; // modify interrupt flags
|
|
BitField<18, 1, uint32_t> cps_imod_value; // new value for interrupt flags (used iff cps_imod_enable is true)
|
|
BitField<17, 1, uint32_t> cps_mmod; // modify processor mode
|
|
BitField< 0, 5, ProcessorMode> cps_mode;
|
|
|
|
BitField< 8, 4, uint32_t> coproc_id;
|
|
BitField<21, 3, uint32_t> coproc_opcode1;
|
|
BitField< 5, 3, uint32_t> coproc_opcode2;
|
|
|
|
BitField<10, 2, uint32_t> uxtb_rotate;
|
|
|
|
BitField< 5, 1, uint32_t> vfp_data_M;
|
|
BitField< 7, 1, uint32_t> vfp_data_N;
|
|
|
|
BitField< 6, 1, uint32_t> vfp_data_opcode_s;
|
|
BitField<20, 1, uint32_t> vfp_data_opcode_r;
|
|
BitField<21, 1, uint32_t> vfp_data_opcode_q;
|
|
BitField<23, 1, uint32_t> vfp_data_opcode_p;
|
|
};
|
|
|
|
enum class AddrMode1Encoding {
|
|
Imm,
|
|
ShiftByImm,
|
|
ShiftByReg,
|
|
Unknown
|
|
};
|
|
|
|
inline AddrMode1Encoding GetAddrMode1Encoding(const ARMInstr& instr) {
|
|
auto raw = instr.raw;
|
|
|
|
// Bits 26 and 27 must be zero
|
|
bool is_valid_addr_mode1_instruction = (0 == ViewBitField<26, 2, uint32_t>(raw));
|
|
if (!is_valid_addr_mode1_instruction)
|
|
return AddrMode1Encoding::Unknown;
|
|
|
|
auto is_immediate = ViewBitField<25, 1, uint32_t>(raw);
|
|
if (is_immediate)
|
|
return AddrMode1Encoding::Imm;
|
|
|
|
// Check whether this is a register shift or an immediate shift
|
|
auto is_register_shift = ViewBitField<4, 1, uint32_t>(raw);
|
|
if (!is_register_shift)
|
|
return AddrMode1Encoding::ShiftByImm;
|
|
|
|
// register shift encodings must have bit 7 set to zero to be valid.
|
|
auto is_valid_register_shift = (0 == ViewBitField<7, 1, uint32_t>(raw));
|
|
if (is_valid_register_shift)
|
|
return AddrMode1Encoding::ShiftByReg;
|
|
|
|
return AddrMode1Encoding::Unknown;
|
|
}
|
|
|
|
enum class AddrMode3AccessType {
|
|
// These three load a small value into a larger register, hence sign-extension may be wished
|
|
LoadSignedByte,
|
|
LoadSignedHalfword,
|
|
LoadUnsignedHalfword,
|
|
|
|
// These load values into equally-sized registers, hence sign-extension is not applicable
|
|
LoadDoubleword,
|
|
StoreByte,
|
|
StoreHalfword,
|
|
StoreDoubleword,
|
|
|
|
// Not an addressing mode 3 instruction
|
|
Invalid
|
|
};
|
|
|
|
union ThumbInstr {
|
|
uint16_t raw;
|
|
|
|
BitField<13, 3, uint16_t> opcode_upper3;
|
|
BitField<12, 4, uint16_t> opcode_upper4;
|
|
BitField<11, 5, uint16_t> opcode_upper5;
|
|
BitField<10, 6, uint16_t> opcode_upper6;
|
|
BitField< 9, 7, uint16_t> opcode_upper7;
|
|
BitField< 8, 8, uint16_t> opcode_upper8;
|
|
BitField< 7, 9, uint16_t> opcode_upper9;
|
|
BitField< 6, 10, uint16_t> opcode_upper10;
|
|
|
|
BitField<0, 3, uint16_t> idx_rd_low;
|
|
BitField<3, 3, uint16_t> idx_rm;
|
|
BitField<6, 3, uint16_t> idx_rn;
|
|
BitField<8, 3, uint16_t> idx_rd_high;
|
|
|
|
BitField<6, 1, uint16_t> idx_rm_upperbit;
|
|
BitField<7, 1, uint16_t> idx_rd_upperbit;
|
|
|
|
BitField<6, 5, uint16_t> immed_mid_5;
|
|
BitField<6, 3, uint16_t> immed_mid_5_lower3;
|
|
BitField<9, 2, uint16_t> immed_mid_5_upper2;
|
|
|
|
BitField<0, 7, uint16_t> immed_low_7;
|
|
|
|
BitField<0, 8, uint16_t> immed_low_8;
|
|
BitField<0, 8, int16_t> signed_immed_low_8;
|
|
|
|
BitField<0, 11, int16_t> signed_immed_11;
|
|
BitField<0, 11, uint16_t> unsigned_immed_11;
|
|
|
|
// Conditional Branch
|
|
BitField<8, 4, uint16_t> cond;
|
|
|
|
// Push/Pop
|
|
BitField<0, 8, uint16_t> register_list;
|
|
};
|
|
|
|
} // namespace
|