#pragma once #include "Emu/Memory/Memory.h" enum ARMv7InstructionSet { ARM, Thumb, Jazelle, ThumbEE }; enum armv7_debug_flags : u32 { DF_DISASM = 1 << 0, DF_PRINT = 1 << 1, DF_NO_EXE = 1 << 2, }; struct ARMv7Context { union { u32 GPR[15]; struct { u32 pad[13]; union { u32 SP; struct { u16 SP_main, SP_process; }; }; u32 LR; union { struct { u32 reserved0 : 16; u32 GE : 4; u32 reserved1 : 4; u32 dummy : 3; u32 Q : 1; // Set to 1 if an SSAT or USAT instruction changes (saturates) the input value for the signed or unsigned range of the result u32 V : 1; // Overflow condition code flag u32 C : 1; // Carry condition code flag u32 Z : 1; // Zero condition code flag u32 N : 1; // Negative condition code flag }; u32 APSR; } APSR; }; struct { u64 GPR_D[8]; }; }; union { struct { u32 dummy : 24; u32 exception : 8; }; u32 IPSR; } IPSR; ARMv7InstructionSet ISET; union { struct { u8 shift_state : 5; u8 cond_base : 3; }; struct { u8 check_state : 4; u8 condition : 4; }; u8 IT; u32 advance() { const u32 res = check_state ? condition : 0xe /* always true */; shift_state <<= 1; if (!check_state) { IT = 0; // clear } return res; } operator bool() const { return check_state != 0; } } ITSTATE; u32 TLS; struct perf_counter { u32 event; u32 value; }; std::array counters; u32 PC; s32 prio; u32 stack_addr; u32 stack_size; u32 hle_func; // current function ID u32 debug; std::string debug_str; void write_pc(u32 value, u32 size) { ISET = value & 1 ? Thumb : ARM; PC = (value & ~1) - size; } u32 read_pc() { return ISET == ARM ? PC + 8 : PC + 4; } u32 get_stack_arg(u32 pos) { return vm::psv::read32(SP + sizeof(u32) * (pos - 5)); } void fast_call(u32 addr); void write_gpr(u32 n, u32 value, u32 size) { assert(n < 16); if (n < 15) { GPR[n] = value; } else { write_pc(value, size); } } u32 read_gpr(u32 n) { assert(n < 16); if (n < 15) { return GPR[n]; } return read_pc(); } // function for processing va_args in printf-like functions u32 get_next_gpr_arg(u32& g_count, u32& f_count, u32& v_count) { assert(!f_count && !v_count); // not supported if (g_count < 4) { return GPR[g_count++]; } else { return get_stack_arg(g_count++); } } template never_inline void fmt_debug_str(const char* fmt, T... args) { debug_str = fmt::format(fmt, args...); } }; template::value> struct cast_armv7_gpr { static_assert(is_enum, "Invalid type for cast_armv7_gpr"); force_inline static u32 to_gpr(const T& value) { return cast_armv7_gpr>::to_gpr(static_cast>(value)); } force_inline static T from_gpr(const u32 reg) { return static_cast(cast_armv7_gpr>::from_gpr(reg)); } }; template<> struct cast_armv7_gpr { force_inline static u32 to_gpr(const u8& value) { return value; } force_inline static u8 from_gpr(const u32 reg) { return static_cast(reg); } }; template<> struct cast_armv7_gpr { force_inline static u32 to_gpr(const u16& value) { return value; } force_inline static u16 from_gpr(const u32 reg) { return static_cast(reg); } }; template<> struct cast_armv7_gpr { force_inline static u32 to_gpr(const u32& value) { return value; } force_inline static u32 from_gpr(const u32 reg) { return reg; } }; template<> struct cast_armv7_gpr { force_inline static u32 to_gpr(const s8& value) { return value; } force_inline static s8 from_gpr(const u32 reg) { return static_cast(reg); } }; template<> struct cast_armv7_gpr { force_inline static u32 to_gpr(const s16& value) { return value; } force_inline static s16 from_gpr(const u32 reg) { return static_cast(reg); } }; template<> struct cast_armv7_gpr { force_inline static u32 to_gpr(const s32& value) { return value; } force_inline static s32 from_gpr(const u32 reg) { return static_cast(reg); } }; template<> struct cast_armv7_gpr { force_inline static u32 to_gpr(const bool& value) { return value; } force_inline static bool from_gpr(const u32& reg) { return reinterpret_cast(reg); } }; template force_inline u32 cast_to_armv7_gpr(const T& value) { return cast_armv7_gpr::to_gpr(value); } template force_inline T cast_from_armv7_gpr(const u32 reg) { return cast_armv7_gpr::from_gpr(reg); }