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->memory = 0;
69 cpu->board = 0;
70}
71
72void ARMAssociateMemory(struct ARMCore* cpu, struct ARMMemory* memory) {
73 cpu->memory = memory;
74}
75
76void ARMAssociateBoard(struct ARMCore* cpu, struct ARMBoard* board) {
77 cpu->board = board;
78 board->cpu = cpu;
79}
80
81void ARMReset(struct ARMCore* cpu) {
82 int i;
83 for (i = 0; i < 16; ++i) {
84 cpu->gprs[i] = 0;
85 }
86 for (i = 0; i < 6; ++i) {
87 cpu->bankedRegisters[i][0] = 0;
88 cpu->bankedRegisters[i][1] = 0;
89 cpu->bankedRegisters[i][2] = 0;
90 cpu->bankedRegisters[i][3] = 0;
91 cpu->bankedRegisters[i][4] = 0;
92 cpu->bankedRegisters[i][5] = 0;
93 cpu->bankedRegisters[i][6] = 0;
94 cpu->bankedSPSRs[i] = 0;
95 }
96
97 cpu->privilegeMode = MODE_SYSTEM;
98 cpu->cpsr.packed = MODE_SYSTEM;
99 cpu->spsr.packed = 0;
100
101 cpu->shifterOperand = 0;
102 cpu->shifterCarryOut = 0;
103
104 cpu->executionMode = MODE_THUMB;
105 _ARMSetMode(cpu, MODE_ARM);
106
107 cpu->currentPC = 0;
108 int currentCycles = 0;
109 ARM_WRITE_PC;
110
111 cpu->cycles = 0;
112 cpu->nextEvent = 0;
113
114 cpu->board->reset(cpu->board);
115}
116
117void ARMRaiseIRQ(struct ARMCore* cpu) {
118 if (cpu->cpsr.i) {
119 return;
120 }
121 union PSR cpsr = cpu->cpsr;
122 int instructionWidth;
123 if (cpu->executionMode == MODE_THUMB) {
124 instructionWidth = WORD_SIZE_THUMB;
125 } else {
126 instructionWidth = WORD_SIZE_ARM;
127 }
128 ARMSetPrivilegeMode(cpu, MODE_IRQ);
129 cpu->cpsr.priv = MODE_IRQ;
130 cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth + WORD_SIZE_ARM;
131 cpu->gprs[ARM_PC] = BASE_IRQ + WORD_SIZE_ARM;
132 cpu->memory->setActiveRegion(cpu->memory, cpu->gprs[ARM_PC]);
133 _ARMSetMode(cpu, MODE_ARM);
134 cpu->spsr = cpsr;
135 cpu->cpsr.i = 1;
136}
137
138void ARMRaiseSWI(struct ARMCore* cpu) {
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_SUPERVISOR);
147 cpu->cpsr.priv = MODE_SUPERVISOR;
148 cpu->gprs[ARM_LR] = cpu->gprs[ARM_PC] - instructionWidth;
149 cpu->gprs[ARM_PC] = BASE_SWI + WORD_SIZE_ARM;
150 cpu->memory->setActiveRegion(cpu->memory, cpu->gprs[ARM_PC]);
151 _ARMSetMode(cpu, MODE_ARM);
152 cpu->spsr = cpsr;
153 cpu->cpsr.i = 1;
154}
155
156static inline void ARMStep(struct ARMCore* cpu) {
157 uint32_t opcode;
158 cpu->currentPC = cpu->gprs[ARM_PC] - WORD_SIZE_ARM;
159 LOAD_32(opcode, cpu->currentPC & cpu->memory->activeMask, cpu->memory->activeRegion);
160 cpu->gprs[ARM_PC] += WORD_SIZE_ARM;
161
162 int condition = opcode >> 28;
163 if (condition == 0xE) {
164 ARMInstruction instruction = _armTable[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)];
165 instruction(cpu, opcode);
166 return;
167 } else {
168 switch (condition) {
169 case 0x0:
170 if (!ARM_COND_EQ) {
171 cpu->cycles += ARM_PREFETCH_CYCLES;
172 return;
173 }
174 break;
175 case 0x1:
176 if (!ARM_COND_NE) {
177 cpu->cycles += ARM_PREFETCH_CYCLES;
178 return;
179 }
180 break;
181 case 0x2:
182 if (!ARM_COND_CS) {
183 cpu->cycles += ARM_PREFETCH_CYCLES;
184 return;
185 }
186 break;
187 case 0x3:
188 if (!ARM_COND_CC) {
189 cpu->cycles += ARM_PREFETCH_CYCLES;
190 return;
191 }
192 break;
193 case 0x4:
194 if (!ARM_COND_MI) {
195 cpu->cycles += ARM_PREFETCH_CYCLES;
196 return;
197 }
198 break;
199 case 0x5:
200 if (!ARM_COND_PL) {
201 cpu->cycles += ARM_PREFETCH_CYCLES;
202 return;
203 }
204 break;
205 case 0x6:
206 if (!ARM_COND_VS) {
207 cpu->cycles += ARM_PREFETCH_CYCLES;
208 return;
209 }
210 break;
211 case 0x7:
212 if (!ARM_COND_VC) {
213 cpu->cycles += ARM_PREFETCH_CYCLES;
214 return;
215 }
216 break;
217 case 0x8:
218 if (!ARM_COND_HI) {
219 cpu->cycles += ARM_PREFETCH_CYCLES;
220 return;
221 }
222 break;
223 case 0x9:
224 if (!ARM_COND_LS) {
225 cpu->cycles += ARM_PREFETCH_CYCLES;
226 return;
227 }
228 break;
229 case 0xA:
230 if (!ARM_COND_GE) {
231 cpu->cycles += ARM_PREFETCH_CYCLES;
232 return;
233 }
234 break;
235 case 0xB:
236 if (!ARM_COND_LT) {
237 cpu->cycles += ARM_PREFETCH_CYCLES;
238 return;
239 }
240 break;
241 case 0xC:
242 if (!ARM_COND_GT) {
243 cpu->cycles += ARM_PREFETCH_CYCLES;
244 return;
245 }
246 break;
247 case 0xD:
248 if (!ARM_COND_LE) {
249 cpu->cycles += ARM_PREFETCH_CYCLES;
250 return;
251 }
252 break;
253 default:
254 break;
255 }
256 }
257 ARMInstruction instruction = _armTable[((opcode >> 16) & 0xFF0) | ((opcode >> 4) & 0x00F)];
258 instruction(cpu, opcode);
259}
260
261static inline void ThumbStep(struct ARMCore* cpu) {
262 cpu->currentPC = cpu->gprs[ARM_PC] - WORD_SIZE_THUMB;
263 cpu->gprs[ARM_PC] += WORD_SIZE_THUMB;
264 uint16_t opcode;
265 LOAD_16(opcode, cpu->currentPC & cpu->memory->activeMask, cpu->memory->activeRegion);
266 ThumbInstruction instruction = _thumbTable[opcode >> 6];
267 instruction(cpu, opcode);
268}
269
270void ARMRun(struct ARMCore* cpu) {
271 if (cpu->executionMode == MODE_THUMB) {
272 ThumbStep(cpu);
273 } else {
274 ARMStep(cpu);
275 }
276 if (cpu->cycles >= cpu->nextEvent) {
277 cpu->board->processEvents(cpu->board);
278 }
279}