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