all repos — mgba @ 4025bf89f2f351f6c7b5bdb0571c65a1cd17c8b4

mGBA Game Boy Advance Emulator

src/arm.c (view raw)

  1#include "arm.h"
  2
  3static inline void _ARMSetMode(struct ARMCore*, enum ExecutionMode);
  4static ARMInstruction _ARMLoadInstructionARM(struct ARMMemory*, uint32_t address, uint32_t* opcodeOut);
  5static ARMInstruction _ARMLoadInstructionThumb(struct ARMMemory*, uint32_t address, uint32_t* opcodeOut);
  6
  7static inline void _ARMReadCPSR(struct ARMCore* cpu) {
  8	_ARMSetMode(cpu, cpu->cpsr.t);
  9}
 10
 11static inline int _ARMModeHasSPSR(enum PrivilegeMode mode) {
 12	return mode != MODE_SYSTEM && mode != MODE_USER;
 13}
 14
 15static const ARMInstruction armTable[0x100000];
 16
 17static inline void _ARMSetMode(struct ARMCore* cpu, enum ExecutionMode executionMode) {
 18	if (executionMode == cpu->executionMode) {
 19		return;
 20	}
 21
 22	cpu->executionMode = executionMode;
 23	switch (executionMode) {
 24	case MODE_ARM:
 25		cpu->cpsr.t = 0;
 26		cpu->instructionWidth = WORD_SIZE_ARM;
 27		cpu->loadInstruction = _ARMLoadInstructionARM;
 28		break;
 29	case MODE_THUMB:
 30		cpu->cpsr.t = 1;
 31		cpu->instructionWidth = WORD_SIZE_THUMB;
 32		cpu->loadInstruction = _ARMLoadInstructionThumb;
 33	}
 34}
 35
 36static ARMInstruction _ARMLoadInstructionARM(struct ARMMemory* memory, uint32_t address, uint32_t* opcodeOut) {
 37	uint32_t opcode = memory->load32(memory, address);
 38	*opcodeOut = opcode;
 39	return 0;
 40}
 41
 42static ARMInstruction _ARMLoadInstructionThumb(struct ARMMemory* memory, uint32_t address, uint32_t* opcodeOut) {
 43	uint16_t opcode = memory->loadU16(memory, address);
 44	*opcodeOut = opcode;
 45	return 0;
 46}
 47
 48void ARMInit(struct ARMCore* cpu) {
 49	int i;
 50	for (i = 0; i < 16; ++i) {
 51		cpu->gprs[i] = 0;
 52	}
 53
 54	cpu->cpsr.packed = MODE_SYSTEM;
 55	cpu->spsr.packed = 0;
 56
 57	cpu->cyclesToEvent = 0;
 58
 59	cpu->shifterOperand = 0;
 60	cpu->shifterCarryOut = 0;
 61
 62	cpu->memory = 0;
 63	cpu->board = 0;
 64
 65	cpu->executionMode = MODE_THUMB;
 66	_ARMSetMode(cpu, MODE_ARM);
 67}
 68
 69void ARMAssociateMemory(struct ARMCore* cpu, struct ARMMemory* memory) {
 70	cpu->memory = memory;
 71}
 72
 73inline void ARMCycle(struct ARMCore* cpu) {
 74	// TODO
 75	uint32_t opcode;
 76	ARMInstruction instruction = cpu->loadInstruction(cpu->memory, cpu->gprs[ARM_PC] - cpu->instructionWidth, &opcode);
 77	cpu->gprs[ARM_PC] += cpu->instructionWidth;
 78	instruction(cpu, opcode);
 79}
 80
 81// Instruction definitions
 82// Beware pre-processor antics
 83
 84#define ARM_CARRY_FROM ((((M) | (N)) >> 31) && !((D) >> 31)))
 85
 86#define ARM_COND_EQ (cpu->cpsr.z)
 87#define ARM_COND_NE (!cpu->cpsr.z)
 88#define ARM_COND_CS (cpu->cpsr.c)
 89#define ARM_COND_CC (!cpu->cpsr.c)
 90#define ARM_COND_MI (cpu->cpsr.n)
 91#define ARM_COND_PL (!cpu->cpsr.n)
 92#define ARM_COND_VS (cpu->cpsr.v)
 93#define ARM_COND_VC (!cpu->cpsr.v)
 94#define ARM_COND_HI (cpu->cpsr.c && !cpu->cpsr.z)
 95#define ARM_COND_LS (!cpu->cpsr.c || cpu->cpsr.z)
 96#define ARM_COND_GE (!cpu->cpsr.n == !cpu->cpsr.v)
 97#define ARM_COND_LT (!cpu->cpsr.n != !cpu->cpsr.v)
 98#define ARM_COND_GT (!cpu->cpsr.z && !cpu->cpsr.n == !cpu->cpsr.v)
 99#define ARM_COND_LE (cpu->cpsr.z || !cpu->cpsr.n != !cpu->cpsr.v)
100#define ARM_COND_AL 1
101
102#define ARM_ADDITION_S(M, N, D) \
103	if (rd == ARM_PC && _ARMModeHasSPSR(cpu->cpsr.priv)) { \
104		cpu->cpsr = cpu->spsr; \
105		_ARMReadCPSR(cpu); \
106	} else { \
107		cpu->cpsr.n = (D) >> 31; \
108		cpu->cpsr.z = !(D); \
109		cpu->cpsr.c = ARM_CARRY_FROM(M, N, D); \
110	} \
111
112#define ARM_NEUTRAL_S(M, N, D) \
113	if (rd == ARM_PC && _ARMModeHasSPSR(cpu->cpsr.priv)) { \
114		cpu->cpsr = cpu->spsr; \
115		_ARMReadCPSR(cpu); \
116	} else { \
117		cpu->cpsr.n = (D) >> 31; \
118		cpu->cpsr.z = !(D); \
119		cpu->cpsr.c = cpu->shifterCarryOut; \
120	} \
121
122// TODO: shifter
123#define DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, COND, COND_BODY, S, S_BODY, BODY) \
124	static void _ARMInstruction ## NAME ## S ## COND (struct ARMCore* cpu, uint32_t opcode) { \
125		if (!COND_BODY) { \
126			return; \
127		} \
128		int rd = (opcode >> 12) & 0xF; \
129		int rn = (opcode >> 16) & 0xF; \
130		BODY; \
131		S_BODY; \
132	}
133
134#define DEFINE_ALU_INSTRUCTION_ARM(NAME, S_BODY, BODY) \
135	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, EQ, ARM_COND_EQ, , , BODY) \
136	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, NE, ARM_COND_NE, , , BODY) \
137	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, CS, ARM_COND_CS, , , BODY) \
138	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, CC, ARM_COND_CC, , , BODY) \
139	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, MI, ARM_COND_MI, , , BODY) \
140	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, PL, ARM_COND_PL, , , BODY) \
141	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, VS, ARM_COND_VS, , , BODY) \
142	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, VC, ARM_COND_VC, , , BODY) \
143	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, HI, ARM_COND_HI, , , BODY) \
144	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LS, ARM_COND_LS, , , BODY) \
145	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, GE, ARM_COND_GE, , , BODY) \
146	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LT, ARM_COND_LT, , , BODY) \
147	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, GT, ARM_COND_GT, , , BODY) \
148	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LE, ARM_COND_LE, , , BODY) \
149	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, AL, ARM_COND_AL, , , BODY) \
150	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, EQ, ARM_COND_EQ, S, S_BODY, BODY) \
151	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, NE, ARM_COND_NE, S, S_BODY, BODY) \
152	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, CS, ARM_COND_CS, S, S_BODY, BODY) \
153	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, CC, ARM_COND_CC, S, S_BODY, BODY) \
154	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, MI, ARM_COND_MI, S, S_BODY, BODY) \
155	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, PL, ARM_COND_PL, S, S_BODY, BODY) \
156	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, VS, ARM_COND_VS, S, S_BODY, BODY) \
157	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, VC, ARM_COND_VC, S, S_BODY, BODY) \
158	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, HI, ARM_COND_HI, S, S_BODY, BODY) \
159	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LS, ARM_COND_LS, S, S_BODY, BODY) \
160	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, GE, ARM_COND_GE, S, S_BODY, BODY) \
161	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LT, ARM_COND_LT, S, S_BODY, BODY) \
162	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, GT, ARM_COND_GT, S, S_BODY, BODY) \
163	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, LE, ARM_COND_LE, S, S_BODY, BODY) \
164	DEFINE_ALU_INSTRUCTION_EX_ARM(NAME, AL, ARM_COND_AL, S, S_BODY, BODY)
165
166DEFINE_ALU_INSTRUCTION_ARM(AND, ARM_NEUTRAL_S(cpu->gprs[rn], cpu->shifterOperand, cpu->gprs[rd]), \
167	cpu->gprs[rd] = cpu->gprs[rn] & cpu->shifterOperand; \
168)
169
170#define DECLARE_INSTRUCTION_ARM(COND, NAME) \
171	_ARMInstruction ## NAME ## COND
172
173#define DO_16(DIRECTIVE) \
174	DIRECTIVE, \
175	DIRECTIVE, \
176	DIRECTIVE, \
177	DIRECTIVE, \
178	DIRECTIVE, \
179	DIRECTIVE, \
180	DIRECTIVE, \
181	DIRECTIVE, \
182	DIRECTIVE, \
183	DIRECTIVE, \
184	DIRECTIVE, \
185	DIRECTIVE, \
186	DIRECTIVE, \
187	DIRECTIVE, \
188	DIRECTIVE, \
189	DIRECTIVE \
190
191#define DO_128(DIRECTIVE) \
192	DO_16(DIRECTIVE), \
193	DO_16(DIRECTIVE), \
194	DO_16(DIRECTIVE), \
195	DO_16(DIRECTIVE), \
196	DO_16(DIRECTIVE), \
197	DO_16(DIRECTIVE), \
198	DO_16(DIRECTIVE), \
199	DO_16(DIRECTIVE) \
200
201// TODO: MUL
202#define DECLARE_ARM_ALU_MUL_BLOCK(COND, ALU, MUL) \
203	DO_128(DECLARE_INSTRUCTION_ARM(COND, ALU)), \
204	DO_16(0), \
205	DO_16(DECLARE_INSTRUCTION_ARM(COND, ALU)), \
206	DO_16(DECLARE_INSTRUCTION_ARM(COND, ALU)), \
207	DO_16(DECLARE_INSTRUCTION_ARM(COND, ALU)), \
208	DO_16(DECLARE_INSTRUCTION_ARM(COND, ALU)), \
209	DO_16(DECLARE_INSTRUCTION_ARM(COND, ALU)), \
210	DO_16(DECLARE_INSTRUCTION_ARM(COND, ALU)), \
211	DO_16(DECLARE_INSTRUCTION_ARM(COND, ALU))
212
213#define DECLARE_COND_BLOCK(COND) \
214	DECLARE_ARM_ALU_MUL_BLOCK(COND, AND, MUL), \
215	DECLARE_ARM_ALU_MUL_BLOCK(COND, ANDS, MULS)
216
217static const ARMInstruction armTable[0x100000] = {
218	DECLARE_COND_BLOCK(EQ),
219	DECLARE_COND_BLOCK(NE),
220	DECLARE_COND_BLOCK(CS),
221	DECLARE_COND_BLOCK(CC),
222	DECLARE_COND_BLOCK(MI),
223	DECLARE_COND_BLOCK(PL),
224	DECLARE_COND_BLOCK(VS),
225	DECLARE_COND_BLOCK(VC),
226	DECLARE_COND_BLOCK(HI),
227	DECLARE_COND_BLOCK(LS),
228	DECLARE_COND_BLOCK(GE),
229	DECLARE_COND_BLOCK(LT),
230	DECLARE_COND_BLOCK(GT),
231	DECLARE_COND_BLOCK(LE),
232	DECLARE_COND_BLOCK(AL)
233};