src/arm/arm.c (view raw)
1#include "arm.h"
2
3#include "isa-arm.h"
4#include "isa-inlines.h"
5#include "isa-thumb.h"
6
7#include <limits.h>
8
9static inline enum RegisterBank _ARMSelectBank(enum PrivilegeMode);
10
11void ARMSetPrivilegeMode(struct ARMCore* cpu, enum PrivilegeMode mode) {
12 if (mode == cpu->privilegeMode) {
13 // Not switching modes after all
14 return;
15 }
16
17 enum RegisterBank newBank = _ARMSelectBank(mode);
18 enum RegisterBank oldBank = _ARMSelectBank(cpu->privilegeMode);
19 if (newBank != oldBank) {
20 // Switch banked registers
21 if (mode == MODE_FIQ || cpu->privilegeMode == MODE_FIQ) {
22 int oldFIQBank = oldBank == BANK_FIQ;
23 int newFIQBank = newBank == BANK_FIQ;
24 cpu->bankedRegisters[oldFIQBank][2] = cpu->gprs[8];
25 cpu->bankedRegisters[oldFIQBank][3] = cpu->gprs[9];
26 cpu->bankedRegisters[oldFIQBank][4] = cpu->gprs[10];
27 cpu->bankedRegisters[oldFIQBank][5] = cpu->gprs[11];
28 cpu->bankedRegisters[oldFIQBank][6] = cpu->gprs[12];
29 cpu->gprs[8] = cpu->bankedRegisters[newFIQBank][2];
30 cpu->gprs[9] = cpu->bankedRegisters[newFIQBank][3];
31 cpu->gprs[10] = cpu->bankedRegisters[newFIQBank][4];
32 cpu->gprs[11] = cpu->bankedRegisters[newFIQBank][5];
33 cpu->gprs[12] = cpu->bankedRegisters[newFIQBank][6];
34 }
35 cpu->bankedRegisters[oldBank][0] = cpu->gprs[ARM_SP];
36 cpu->bankedRegisters[oldBank][1] = cpu->gprs[ARM_LR];
37 cpu->gprs[ARM_SP] = cpu->bankedRegisters[newBank][0];
38 cpu->gprs[ARM_LR] = cpu->bankedRegisters[newBank][1];
39
40 cpu->bankedSPSRs[oldBank] = cpu->spsr.packed;
41 cpu->spsr.packed = cpu->bankedSPSRs[newBank];
42
43 }
44 cpu->privilegeMode = mode;
45}
46
47static inline enum RegisterBank _ARMSelectBank(enum PrivilegeMode mode) {
48 switch (mode) {
49 case MODE_USER:
50 case MODE_SYSTEM:
51 // No banked registers
52 return BANK_NONE;
53 case MODE_FIQ:
54 return BANK_FIQ;
55 case MODE_IRQ:
56 return BANK_IRQ;
57 case MODE_SUPERVISOR:
58 return BANK_SUPERVISOR;
59 case MODE_ABORT:
60 return BANK_ABORT;
61 case MODE_UNDEFINED:
62 return BANK_UNDEFINED;
63 default:
64 // This should be unreached
65 return BANK_NONE;
66 }
67}
68
69void ARMInit(struct ARMCore* cpu) {
70 cpu->memory = 0;
71 cpu->board = 0;
72}
73
74void ARMAssociateMemory(struct ARMCore* cpu, struct ARMMemory* memory) {
75 cpu->memory = memory;
76}
77
78void ARMAssociateBoard(struct ARMCore* cpu, struct ARMBoard* board) {
79 cpu->board = board;
80 board->cpu = cpu;
81}
82
83void ARMReset(struct ARMCore* cpu) {
84 int i;
85 for (i = 0; i < 16; ++i) {
86 cpu->gprs[i] = 0;
87 }
88 for (i = 0; i < 6; ++i) {
89 cpu->bankedRegisters[i][0] = 0;
90 cpu->bankedRegisters[i][1] = 0;
91 cpu->bankedRegisters[i][2] = 0;
92 cpu->bankedRegisters[i][3] = 0;
93 cpu->bankedRegisters[i][4] = 0;
94 cpu->bankedRegisters[i][5] = 0;
95 cpu->bankedRegisters[i][6] = 0;
96 cpu->bankedSPSRs[i] = 0;
97 }
98
99 cpu->privilegeMode = MODE_SYSTEM;
100 cpu->cpsr.packed = MODE_SYSTEM;
101 cpu->spsr.packed = 0;
102
103 cpu->shifterOperand = 0;
104 cpu->shifterCarryOut = 0;
105
106 cpu->executionMode = MODE_THUMB;
107 _ARMSetMode(cpu, MODE_ARM);
108
109 cpu->currentPC = 0;
110 int currentCycles = 0;
111 ARM_WRITE_PC;
112
113 cpu->cycles = 0;
114 cpu->nextEvent = 0;
115
116 cpu->board->reset(cpu->board);
117}
118
119void ARMRaiseIRQ(struct ARMCore* cpu) {
120 if (cpu->cpsr.i) {
121 return;
122 }
123 union PSR cpsr = cpu->cpsr;
124 int instructionWidth;
125 if (cpu->executionMode == MODE_THUMB) {
126 instructionWidth = WORD_SIZE_THUMB;
127 } else {
128 instructionWidth = WORD_SIZE_ARM;
129 }
130 ARMSetPrivilegeMode(cpu, MODE_IRQ);
131 cpu->cpsr.priv = MODE_IRQ;
132 cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth + WORD_SIZE_ARM;
133 cpu->gprs[ARM_PC] = BASE_IRQ + WORD_SIZE_ARM;
134 cpu->memory->setActiveRegion(cpu->memory, cpu->gprs[ARM_PC]);
135 _ARMSetMode(cpu, MODE_ARM);
136 cpu->spsr = cpsr;
137 cpu->cpsr.i = 1;
138}
139
140void ARMRaiseSWI(struct ARMCore* cpu) {
141 union PSR cpsr = cpu->cpsr;
142 int instructionWidth;
143 if (cpu->executionMode == MODE_THUMB) {
144 instructionWidth = WORD_SIZE_THUMB;
145 } else {
146 instructionWidth = WORD_SIZE_ARM;
147 }
148 ARMSetPrivilegeMode(cpu, MODE_SUPERVISOR);
149 cpu->cpsr.priv = MODE_SUPERVISOR;
150 cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth;
151 cpu->gprs[ARM_PC] = BASE_SWI + WORD_SIZE_ARM;
152 cpu->memory->setActiveRegion(cpu->memory, cpu->gprs[ARM_PC]);
153 _ARMSetMode(cpu, MODE_ARM);
154 cpu->spsr = cpsr;
155 cpu->cpsr.i = 1;
156}
157
158static inline void ARMStep(struct ARMCore* cpu) {
159 uint32_t opcode;
160 cpu->currentPC = cpu->gprs[ARM_PC] - WORD_SIZE_ARM;
161 LOAD_32(opcode, cpu->currentPC & cpu->memory->activeMask, cpu->memory->activeRegion);
162 cpu->gprs[ARM_PC] += WORD_SIZE_ARM;
163
164 int condition = opcode >> 28;
165 if (condition == 0xE) {
166 ARMInstruction instruction = _armTable[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)];
167 instruction(cpu, opcode);
168 return;
169 } else {
170 switch (condition) {
171 case 0x0:
172 if (!ARM_COND_EQ) {
173 cpu->cycles += ARM_PREFETCH_CYCLES;
174 return;
175 }
176 break;
177 case 0x1:
178 if (!ARM_COND_NE) {
179 cpu->cycles += ARM_PREFETCH_CYCLES;
180 return;
181 }
182 break;
183 case 0x2:
184 if (!ARM_COND_CS) {
185 cpu->cycles += ARM_PREFETCH_CYCLES;
186 return;
187 }
188 break;
189 case 0x3:
190 if (!ARM_COND_CC) {
191 cpu->cycles += ARM_PREFETCH_CYCLES;
192 return;
193 }
194 break;
195 case 0x4:
196 if (!ARM_COND_MI) {
197 cpu->cycles += ARM_PREFETCH_CYCLES;
198 return;
199 }
200 break;
201 case 0x5:
202 if (!ARM_COND_PL) {
203 cpu->cycles += ARM_PREFETCH_CYCLES;
204 return;
205 }
206 break;
207 case 0x6:
208 if (!ARM_COND_VS) {
209 cpu->cycles += ARM_PREFETCH_CYCLES;
210 return;
211 }
212 break;
213 case 0x7:
214 if (!ARM_COND_VC) {
215 cpu->cycles += ARM_PREFETCH_CYCLES;
216 return;
217 }
218 break;
219 case 0x8:
220 if (!ARM_COND_HI) {
221 cpu->cycles += ARM_PREFETCH_CYCLES;
222 return;
223 }
224 break;
225 case 0x9:
226 if (!ARM_COND_LS) {
227 cpu->cycles += ARM_PREFETCH_CYCLES;
228 return;
229 }
230 break;
231 case 0xA:
232 if (!ARM_COND_GE) {
233 cpu->cycles += ARM_PREFETCH_CYCLES;
234 return;
235 }
236 break;
237 case 0xB:
238 if (!ARM_COND_LT) {
239 cpu->cycles += ARM_PREFETCH_CYCLES;
240 return;
241 }
242 break;
243 case 0xC:
244 if (!ARM_COND_GT) {
245 cpu->cycles += ARM_PREFETCH_CYCLES;
246 return;
247 }
248 break;
249 case 0xD:
250 if (!ARM_COND_LE) {
251 cpu->cycles += ARM_PREFETCH_CYCLES;
252 return;
253 }
254 break;
255 default:
256 break;
257 }
258 }
259 ARMInstruction instruction = _armTable[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)];
260 instruction(cpu, opcode);
261}
262
263static inline void ThumbStep(struct ARMCore* cpu) {
264 cpu->currentPC = cpu->gprs[ARM_PC] - WORD_SIZE_THUMB;
265 cpu->gprs[ARM_PC] += WORD_SIZE_THUMB;
266 uint16_t opcode;
267 LOAD_16(opcode, cpu->currentPC & cpu->memory->activeMask, cpu->memory->activeRegion);
268 ThumbInstruction instruction = _thumbTable[opcode >> 6];
269 instruction(cpu, opcode);
270}
271
272void ARMRun(struct ARMCore* cpu) {
273 if (cpu->executionMode == MODE_THUMB) {
274 ThumbStep(cpu);
275 } else {
276 ARMStep(cpu);
277 }
278 if (cpu->cycles >= cpu->nextEvent) {
279 cpu->board->processEvents(cpu->board);
280 }
281}