mirror of https://github.com/mgba-emu/mgba.git
Add boilerplate for instructions
This commit is contained in:
parent
bf72532715
commit
4025bf89f2
191
src/arm.c
191
src/arm.c
|
@ -1,10 +1,20 @@
|
|||
#include "arm.h"
|
||||
|
||||
static void _ARMSetMode(struct ARMCore*, enum ExecutionMode);
|
||||
static ARMInstruction _ARMLoadInstructionARM(struct ARMMemory*, uint32_t address);
|
||||
static ARMInstruction _ARMLoadInstructionThumb(struct ARMMemory*, uint32_t address);
|
||||
static inline void _ARMSetMode(struct ARMCore*, enum ExecutionMode);
|
||||
static ARMInstruction _ARMLoadInstructionARM(struct ARMMemory*, uint32_t address, uint32_t* opcodeOut);
|
||||
static ARMInstruction _ARMLoadInstructionThumb(struct ARMMemory*, uint32_t address, uint32_t* opcodeOut);
|
||||
|
||||
static void _ARMSetMode(struct ARMCore* cpu, enum ExecutionMode executionMode) {
|
||||
static inline void _ARMReadCPSR(struct ARMCore* cpu) {
|
||||
_ARMSetMode(cpu, cpu->cpsr.t);
|
||||
}
|
||||
|
||||
static inline int _ARMModeHasSPSR(enum PrivilegeMode mode) {
|
||||
return mode != MODE_SYSTEM && mode != MODE_USER;
|
||||
}
|
||||
|
||||
static const ARMInstruction armTable[0x100000];
|
||||
|
||||
static inline void _ARMSetMode(struct ARMCore* cpu, enum ExecutionMode executionMode) {
|
||||
if (executionMode == cpu->executionMode) {
|
||||
return;
|
||||
}
|
||||
|
@ -23,13 +33,15 @@ static void _ARMSetMode(struct ARMCore* cpu, enum ExecutionMode executionMode) {
|
|||
}
|
||||
}
|
||||
|
||||
static ARMInstruction _ARMLoadInstructionARM(struct ARMMemory* memory, uint32_t address) {
|
||||
int32_t opcode = memory->load32(memory, address);
|
||||
static ARMInstruction _ARMLoadInstructionARM(struct ARMMemory* memory, uint32_t address, uint32_t* opcodeOut) {
|
||||
uint32_t opcode = memory->load32(memory, address);
|
||||
*opcodeOut = opcode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ARMInstruction _ARMLoadInstructionThumb(struct ARMMemory* memory, uint32_t address) {
|
||||
static ARMInstruction _ARMLoadInstructionThumb(struct ARMMemory* memory, uint32_t address, uint32_t* opcodeOut) {
|
||||
uint16_t opcode = memory->loadU16(memory, address);
|
||||
*opcodeOut = opcode;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -39,7 +51,7 @@ void ARMInit(struct ARMCore* cpu) {
|
|||
cpu->gprs[i] = 0;
|
||||
}
|
||||
|
||||
cpu->cpsr.packed = 0;
|
||||
cpu->cpsr.packed = MODE_SYSTEM;
|
||||
cpu->spsr.packed = 0;
|
||||
|
||||
cpu->cyclesToEvent = 0;
|
||||
|
@ -58,7 +70,164 @@ void ARMAssociateMemory(struct ARMCore* cpu, struct ARMMemory* memory) {
|
|||
cpu->memory = memory;
|
||||
}
|
||||
|
||||
void ARMCycle(struct ARMCore* cpu) {
|
||||
inline void ARMCycle(struct ARMCore* cpu) {
|
||||
// TODO
|
||||
ARMInstruction instruction = cpu->loadInstruction(cpu->memory, cpu->gprs[ARM_PC] - cpu->instructionWidth);
|
||||
}
|
||||
uint32_t opcode;
|
||||
ARMInstruction instruction = cpu->loadInstruction(cpu->memory, cpu->gprs[ARM_PC] - cpu->instructionWidth, &opcode);
|
||||
cpu->gprs[ARM_PC] += cpu->instructionWidth;
|
||||
instruction(cpu, opcode);
|
||||
}
|
||||
|
||||
// Instruction definitions
|
||||
// Beware pre-processor antics
|
||||
|
||||
#define ARM_CARRY_FROM ((((M) | (N)) >> 31) && !((D) >> 31)))
|
||||
|
||||
#define ARM_COND_EQ (cpu->cpsr.z)
|
||||
#define ARM_COND_NE (!cpu->cpsr.z)
|
||||
#define ARM_COND_CS (cpu->cpsr.c)
|
||||
#define ARM_COND_CC (!cpu->cpsr.c)
|
||||
#define ARM_COND_MI (cpu->cpsr.n)
|
||||
#define ARM_COND_PL (!cpu->cpsr.n)
|
||||
#define ARM_COND_VS (cpu->cpsr.v)
|
||||
#define ARM_COND_VC (!cpu->cpsr.v)
|
||||
#define ARM_COND_HI (cpu->cpsr.c && !cpu->cpsr.z)
|
||||
#define ARM_COND_LS (!cpu->cpsr.c || cpu->cpsr.z)
|
||||
#define ARM_COND_GE (!cpu->cpsr.n == !cpu->cpsr.v)
|
||||
#define ARM_COND_LT (!cpu->cpsr.n != !cpu->cpsr.v)
|
||||
#define ARM_COND_GT (!cpu->cpsr.z && !cpu->cpsr.n == !cpu->cpsr.v)
|
||||
#define ARM_COND_LE (cpu->cpsr.z || !cpu->cpsr.n != !cpu->cpsr.v)
|
||||
#define ARM_COND_AL 1
|
||||
|
||||
#define ARM_ADDITION_S(M, N, D) \
|
||||
if (rd == ARM_PC && _ARMModeHasSPSR(cpu->cpsr.priv)) { \
|
||||
cpu->cpsr = cpu->spsr; \
|
||||
_ARMReadCPSR(cpu); \
|
||||
} else { \
|
||||
cpu->cpsr.n = (D) >> 31; \
|
||||
cpu->cpsr.z = !(D); \
|
||||
cpu->cpsr.c = ARM_CARRY_FROM(M, N, D); \
|
||||
} \
|
||||
|
||||
#define ARM_NEUTRAL_S(M, N, D) \
|
||||
if (rd == ARM_PC && _ARMModeHasSPSR(cpu->cpsr.priv)) { \
|
||||
cpu->cpsr = cpu->spsr; \
|
||||
_ARMReadCPSR(cpu); \
|
||||
} else { \
|
||||
cpu->cpsr.n = (D) >> 31; \
|
||||
cpu->cpsr.z = !(D); \
|
||||
cpu->cpsr.c = cpu->shifterCarryOut; \
|
||||
} \
|
||||
|
||||
// TODO: shifter
|
||||
#define DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, COND, COND_BODY, S, S_BODY, BODY) \
|
||||
static void _ARMInstruction ## NAME ## S ## COND (struct ARMCore* cpu, uint32_t opcode) { \
|
||||
if (!COND_BODY) { \
|
||||
return; \
|
||||
} \
|
||||
int rd = (opcode >> 12) & 0xF; \
|
||||
int rn = (opcode >> 16) & 0xF; \
|
||||
BODY; \
|
||||
S_BODY; \
|
||||
}
|
||||
|
||||
#define DEFINE_ALU_INSTRUCTION_ARM(NAME, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, EQ, ARM_COND_EQ, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, NE, ARM_COND_NE, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, CS, ARM_COND_CS, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, CC, ARM_COND_CC, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, MI, ARM_COND_MI, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, PL, ARM_COND_PL, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, VS, ARM_COND_VS, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, VC, ARM_COND_VC, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, HI, ARM_COND_HI, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LS, ARM_COND_LS, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, GE, ARM_COND_GE, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LT, ARM_COND_LT, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, GT, ARM_COND_GT, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LE, ARM_COND_LE, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, AL, ARM_COND_AL, , , BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, EQ, ARM_COND_EQ, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, NE, ARM_COND_NE, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, CS, ARM_COND_CS, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, CC, ARM_COND_CC, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, MI, ARM_COND_MI, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, PL, ARM_COND_PL, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, VS, ARM_COND_VS, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, VC, ARM_COND_VC, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, HI, ARM_COND_HI, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LS, ARM_COND_LS, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, GE, ARM_COND_GE, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LT, ARM_COND_LT, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, GT, ARM_COND_GT, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LE, ARM_COND_LE, S, S_BODY, BODY) \
|
||||
DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, AL, ARM_COND_AL, S, S_BODY, BODY)
|
||||
|
||||
DEFINE_ALU_INSTRUCTION_ARM(AND, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), \
|
||||
cpu->gprs[rd] = cpu->gprs[rn] & cpu->shifterOperand; \
|
||||
)
|
||||
|
||||
#define DECLARE_INSTRUCTION_ARM(COND, NAME) \
|
||||
_ARMInstruction ## NAME ## COND
|
||||
|
||||
#define DO_16(DIRECTIVE) \
|
||||
DIRECTIVE, \
|
||||
DIRECTIVE, \
|
||||
DIRECTIVE, \
|
||||
DIRECTIVE, \
|
||||
DIRECTIVE, \
|
||||
DIRECTIVE, \
|
||||
DIRECTIVE, \
|
||||
DIRECTIVE, \
|
||||
DIRECTIVE, \
|
||||
DIRECTIVE, \
|
||||
DIRECTIVE, \
|
||||
DIRECTIVE, \
|
||||
DIRECTIVE, \
|
||||
DIRECTIVE, \
|
||||
DIRECTIVE, \
|
||||
DIRECTIVE \
|
||||
|
||||
#define DO_128(DIRECTIVE) \
|
||||
DO_16(DIRECTIVE), \
|
||||
DO_16(DIRECTIVE), \
|
||||
DO_16(DIRECTIVE), \
|
||||
DO_16(DIRECTIVE), \
|
||||
DO_16(DIRECTIVE), \
|
||||
DO_16(DIRECTIVE), \
|
||||
DO_16(DIRECTIVE), \
|
||||
DO_16(DIRECTIVE) \
|
||||
|
||||
// TODO: MUL
|
||||
#define DECLARE_ARM_ALU_MUL_BLOCK(COND, ALU, MUL) \
|
||||
DO_128(DECLARE_INSTRUCTION_ARM(COND, ALU)), \
|
||||
DO_16(0), \
|
||||
DO_16(DECLARE_INSTRUCTION_ARM(COND, ALU)), \
|
||||
DO_16(DECLARE_INSTRUCTION_ARM(COND, ALU)), \
|
||||
DO_16(DECLARE_INSTRUCTION_ARM(COND, ALU)), \
|
||||
DO_16(DECLARE_INSTRUCTION_ARM(COND, ALU)), \
|
||||
DO_16(DECLARE_INSTRUCTION_ARM(COND, ALU)), \
|
||||
DO_16(DECLARE_INSTRUCTION_ARM(COND, ALU)), \
|
||||
DO_16(DECLARE_INSTRUCTION_ARM(COND, ALU))
|
||||
|
||||
#define DECLARE_COND_BLOCK(COND) \
|
||||
DECLARE_ARM_ALU_MUL_BLOCK(COND, AND, MUL), \
|
||||
DECLARE_ARM_ALU_MUL_BLOCK(COND, ANDS, MULS)
|
||||
|
||||
static const ARMInstruction armTable[0x100000] = {
|
||||
DECLARE_COND_BLOCK(EQ),
|
||||
DECLARE_COND_BLOCK(NE),
|
||||
DECLARE_COND_BLOCK(CS),
|
||||
DECLARE_COND_BLOCK(CC),
|
||||
DECLARE_COND_BLOCK(MI),
|
||||
DECLARE_COND_BLOCK(PL),
|
||||
DECLARE_COND_BLOCK(VS),
|
||||
DECLARE_COND_BLOCK(VC),
|
||||
DECLARE_COND_BLOCK(HI),
|
||||
DECLARE_COND_BLOCK(LS),
|
||||
DECLARE_COND_BLOCK(GE),
|
||||
DECLARE_COND_BLOCK(LT),
|
||||
DECLARE_COND_BLOCK(GT),
|
||||
DECLARE_COND_BLOCK(LE),
|
||||
DECLARE_COND_BLOCK(AL)
|
||||
};
|
|
@ -40,15 +40,14 @@ enum ExecutionVector {
|
|||
};
|
||||
|
||||
struct ARMCore;
|
||||
typedef void (*ARMInstruction)(struct ARMCore*);
|
||||
typedef void (*ARMInstruction)(struct ARMCore*, uint32_t opcode);
|
||||
|
||||
union PSR {
|
||||
struct {
|
||||
int exec : 4;
|
||||
enum PrivilegeMode priv : 5;
|
||||
int t : 1;
|
||||
int f : 1;
|
||||
int i : 1;
|
||||
int a : 1;
|
||||
int : 20;
|
||||
int v : 1;
|
||||
int c : 1;
|
||||
|
@ -81,7 +80,7 @@ struct ARMCore {
|
|||
|
||||
int instructionWidth;
|
||||
|
||||
ARMInstruction (*loadInstruction)(struct ARMMemory*, uint32_t address);
|
||||
ARMInstruction (*loadInstruction)(struct ARMMemory*, uint32_t address, uint32_t* opcodeOut);
|
||||
enum ExecutionMode executionMode;
|
||||
|
||||
struct ARMMemory* memory;
|
||||
|
@ -91,6 +90,6 @@ struct ARMCore {
|
|||
void ARMInit(struct ARMCore* cpu);
|
||||
void ARMAssociateMemory(struct ARMCore* cpu, struct ARMMemory* memory);
|
||||
|
||||
void ARMCycle(struct ARMCore* cpu);
|
||||
inline void ARMCycle(struct ARMCore* cpu);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue