mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-01-03 15:20:27 +01:00
325 lines
4.6 KiB
C++
325 lines
4.6 KiB
C++
#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<perf_counter, 6> 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<typename... T>
|
|
never_inline void fmt_debug_str(const char* fmt, T... args)
|
|
{
|
|
debug_str = fmt::format(fmt, args...);
|
|
}
|
|
};
|
|
|
|
template<typename T, bool is_enum = std::is_enum<T>::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<std::underlying_type_t<T>>::to_gpr(static_cast<std::underlying_type_t<T>>(value));
|
|
}
|
|
|
|
force_inline static T from_gpr(const u32 reg)
|
|
{
|
|
return static_cast<T>(cast_armv7_gpr<std::underlying_type_t<T>>::from_gpr(reg));
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct cast_armv7_gpr<u8, false>
|
|
{
|
|
force_inline static u32 to_gpr(const u8& value)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
force_inline static u8 from_gpr(const u32 reg)
|
|
{
|
|
return static_cast<u8>(reg);
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct cast_armv7_gpr<u16, false>
|
|
{
|
|
force_inline static u32 to_gpr(const u16& value)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
force_inline static u16 from_gpr(const u32 reg)
|
|
{
|
|
return static_cast<u16>(reg);
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct cast_armv7_gpr<u32, false>
|
|
{
|
|
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<s8, false>
|
|
{
|
|
force_inline static u32 to_gpr(const s8& value)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
force_inline static s8 from_gpr(const u32 reg)
|
|
{
|
|
return static_cast<s8>(reg);
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct cast_armv7_gpr<s16, false>
|
|
{
|
|
force_inline static u32 to_gpr(const s16& value)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
force_inline static s16 from_gpr(const u32 reg)
|
|
{
|
|
return static_cast<s16>(reg);
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct cast_armv7_gpr<s32, false>
|
|
{
|
|
force_inline static u32 to_gpr(const s32& value)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
force_inline static s32 from_gpr(const u32 reg)
|
|
{
|
|
return static_cast<s32>(reg);
|
|
}
|
|
};
|
|
|
|
template<>
|
|
struct cast_armv7_gpr<b8, false>
|
|
{
|
|
force_inline static u32 to_gpr(const b8& value)
|
|
{
|
|
return value;
|
|
}
|
|
|
|
force_inline static b8 from_gpr(const u32& reg)
|
|
{
|
|
return reg != 0;
|
|
}
|
|
};
|
|
|
|
template<typename T>
|
|
force_inline u32 cast_to_armv7_gpr(const T& value)
|
|
{
|
|
return cast_armv7_gpr<T>::to_gpr(value);
|
|
}
|
|
|
|
template<typename T>
|
|
force_inline T cast_from_armv7_gpr(const u32 reg)
|
|
{
|
|
return cast_armv7_gpr<T>::from_gpr(reg);
|
|
}
|