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};