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