Commit | Line | Data |
---|---|---|
c906108c SS |
1 | /* armsupp.c -- ARMulator support code: ARM6 Instruction Emulator. |
2 | Copyright (C) 1994 Advanced RISC Machines Ltd. | |
3 | ||
4 | This program is free software; you can redistribute it and/or modify | |
5 | it under the terms of the GNU General Public License as published by | |
6 | the Free Software Foundation; either version 2 of the License, or | |
7 | (at your option) any later version. | |
8 | ||
9 | This program is distributed in the hope that it will be useful, | |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | GNU General Public License for more details. | |
13 | ||
14 | You should have received a copy of the GNU General Public License | |
15 | along with this program; if not, write to the Free Software | |
16 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ | |
17 | ||
18 | #include "armdefs.h" | |
19 | #include "armemu.h" | |
20 | ||
21 | /***************************************************************************\ | |
22 | * Definitions for the support routines * | |
23 | \***************************************************************************/ | |
24 | ||
25 | ARMword ARMul_GetReg(ARMul_State *state, unsigned mode, unsigned reg) ; | |
26 | void ARMul_SetReg(ARMul_State *state, unsigned mode, unsigned reg, ARMword value) ; | |
27 | ARMword ARMul_GetPC(ARMul_State *state) ; | |
28 | ARMword ARMul_GetNextPC(ARMul_State *state) ; | |
29 | void ARMul_SetPC(ARMul_State *state, ARMword value) ; | |
30 | ARMword ARMul_GetR15(ARMul_State *state) ; | |
31 | void ARMul_SetR15(ARMul_State *state, ARMword value) ; | |
32 | ||
33 | ARMword ARMul_GetCPSR(ARMul_State *state) ; | |
34 | void ARMul_SetCPSR(ARMul_State *state, ARMword value) ; | |
35 | void ARMul_FixCPSR(ARMul_State *state, ARMword instr, ARMword rhs) ; | |
36 | ARMword ARMul_GetSPSR(ARMul_State *state, ARMword mode) ; | |
37 | void ARMul_SetSPSR(ARMul_State *state, ARMword mode, ARMword value) ; | |
38 | void ARMul_FixSPSR(ARMul_State *state, ARMword instr, ARMword rhs) ; | |
39 | ||
40 | void ARMul_CPSRAltered(ARMul_State *state) ; | |
41 | void ARMul_R15Altered(ARMul_State *state) ; | |
42 | ||
43 | ARMword ARMul_SwitchMode(ARMul_State *state,ARMword oldmode, ARMword newmode) ; | |
44 | static ARMword ModeToBank(ARMul_State *state,ARMword mode) ; | |
45 | ||
46 | unsigned ARMul_NthReg(ARMword instr, unsigned number) ; | |
47 | ||
48 | void ARMul_NegZero(ARMul_State *state, ARMword result) ; | |
49 | void ARMul_AddCarry(ARMul_State *state, ARMword a, ARMword b, ARMword result) ; | |
50 | void ARMul_AddOverflow(ARMul_State *state, ARMword a, ARMword b, ARMword result) ; | |
51 | void ARMul_SubCarry(ARMul_State *state, ARMword a, ARMword b, ARMword result) ; | |
52 | void ARMul_SubOverflow(ARMul_State *state, ARMword a, ARMword b, ARMword result) ; | |
53 | ||
54 | void ARMul_LDC(ARMul_State *state,ARMword instr,ARMword address) ; | |
55 | void ARMul_STC(ARMul_State *state,ARMword instr,ARMword address) ; | |
56 | void ARMul_MCR(ARMul_State *state,ARMword instr, ARMword source) ; | |
57 | ARMword ARMul_MRC(ARMul_State *state,ARMword instr) ; | |
58 | void ARMul_CDP(ARMul_State *state,ARMword instr) ; | |
59 | void ARMul_UndefInstr(ARMul_State *state,ARMword instr) ; | |
60 | unsigned IntPending(ARMul_State *state) ; | |
61 | ||
62 | ARMword ARMul_Align(ARMul_State *state, ARMword address, ARMword data) ; | |
63 | ||
64 | void ARMul_ScheduleEvent(ARMul_State *state, unsigned long delay, | |
65 | unsigned (*what)()) ; | |
66 | void ARMul_EnvokeEvent(ARMul_State *state) ; | |
67 | unsigned long ARMul_Time(ARMul_State *state) ; | |
68 | static void EnvokeList(ARMul_State *state, unsigned long from, unsigned long to) ; | |
69 | ||
70 | struct EventNode { /* An event list node */ | |
71 | unsigned (*func)() ; /* The function to call */ | |
72 | struct EventNode *next ; | |
73 | } ; | |
74 | ||
75 | /***************************************************************************\ | |
76 | * This routine returns the value of a register from a mode. * | |
77 | \***************************************************************************/ | |
78 | ||
79 | ARMword ARMul_GetReg(ARMul_State *state, unsigned mode, unsigned reg) | |
80 | {mode &= MODEBITS ; | |
81 | if (mode != state->Mode) | |
82 | return(state->RegBank[ModeToBank(state,(ARMword)mode)][reg]) ; | |
83 | else | |
84 | return(state->Reg[reg]) ; | |
85 | } | |
86 | ||
87 | /***************************************************************************\ | |
88 | * This routine sets the value of a register for a mode. * | |
89 | \***************************************************************************/ | |
90 | ||
91 | void ARMul_SetReg(ARMul_State *state, unsigned mode, unsigned reg, ARMword value) | |
92 | {mode &= MODEBITS ; | |
93 | if (mode != state->Mode) | |
94 | state->RegBank[ModeToBank(state,(ARMword)mode)][reg] = value ; | |
95 | else | |
96 | state->Reg[reg] = value ; | |
97 | } | |
98 | ||
99 | /***************************************************************************\ | |
100 | * This routine returns the value of the PC, mode independently. * | |
101 | \***************************************************************************/ | |
102 | ||
103 | ARMword ARMul_GetPC(ARMul_State *state) | |
104 | {if (state->Mode > SVC26MODE) | |
105 | return(state->Reg[15]) ; | |
106 | else | |
107 | return(R15PC) ; | |
108 | } | |
109 | ||
110 | /***************************************************************************\ | |
111 | * This routine returns the value of the PC, mode independently. * | |
112 | \***************************************************************************/ | |
113 | ||
114 | ARMword ARMul_GetNextPC(ARMul_State *state) | |
115 | {if (state->Mode > SVC26MODE) | |
116 | return(state->Reg[15] + isize) ; | |
117 | else | |
118 | return((state->Reg[15] + isize) & R15PCBITS) ; | |
119 | } | |
120 | ||
121 | /***************************************************************************\ | |
122 | * This routine sets the value of the PC. * | |
123 | \***************************************************************************/ | |
124 | ||
125 | void ARMul_SetPC(ARMul_State *state, ARMword value) | |
126 | {if (ARMul_MODE32BIT) | |
127 | state->Reg[15] = value & PCBITS ; | |
128 | else | |
129 | state->Reg[15] = R15CCINTMODE | (value & R15PCBITS) ; | |
130 | FLUSHPIPE ; | |
131 | } | |
132 | ||
133 | /***************************************************************************\ | |
134 | * This routine returns the value of register 15, mode independently. * | |
135 | \***************************************************************************/ | |
136 | ||
137 | ARMword ARMul_GetR15(ARMul_State *state) | |
138 | {if (state->Mode > SVC26MODE) | |
139 | return(state->Reg[15]) ; | |
140 | else | |
141 | return(R15PC | ECC | ER15INT | EMODE) ; | |
142 | } | |
143 | ||
144 | /***************************************************************************\ | |
145 | * This routine sets the value of Register 15. * | |
146 | \***************************************************************************/ | |
147 | ||
148 | void ARMul_SetR15(ARMul_State *state, ARMword value) | |
149 | { | |
150 | if (ARMul_MODE32BIT) | |
151 | state->Reg[15] = value & PCBITS ; | |
152 | else { | |
153 | state->Reg[15] = value ; | |
154 | ARMul_R15Altered(state) ; | |
155 | } | |
156 | FLUSHPIPE ; | |
157 | } | |
158 | ||
159 | /***************************************************************************\ | |
160 | * This routine returns the value of the CPSR * | |
161 | \***************************************************************************/ | |
162 | ||
163 | ARMword ARMul_GetCPSR(ARMul_State *state) | |
164 | { | |
165 | return(CPSR) ; | |
166 | } | |
167 | ||
168 | /***************************************************************************\ | |
169 | * This routine sets the value of the CPSR * | |
170 | \***************************************************************************/ | |
171 | ||
172 | void ARMul_SetCPSR(ARMul_State *state, ARMword value) | |
173 | {state->Cpsr = CPSR ; | |
174 | SETPSR(state->Cpsr,value) ; | |
175 | ARMul_CPSRAltered(state) ; | |
176 | } | |
177 | ||
178 | /***************************************************************************\ | |
179 | * This routine does all the nasty bits involved in a write to the CPSR, * | |
180 | * including updating the register bank, given a MSR instruction. * | |
181 | \***************************************************************************/ | |
182 | ||
183 | void ARMul_FixCPSR(ARMul_State *state, ARMword instr, ARMword rhs) | |
184 | {state->Cpsr = CPSR ; | |
185 | if (state->Bank==USERBANK) { /* Only write flags in user mode */ | |
186 | if (BIT(19)) { | |
187 | SETCC(state->Cpsr,rhs) ; | |
188 | } | |
189 | } | |
190 | else { /* Not a user mode */ | |
191 | if (BITS(16,19)==9) SETPSR(state->Cpsr,rhs) ; | |
192 | else if (BIT(16)) SETINTMODE(state->Cpsr,rhs) ; | |
193 | else if (BIT(19)) SETCC(state->Cpsr,rhs) ; | |
194 | } | |
195 | ARMul_CPSRAltered(state) ; | |
196 | } | |
197 | ||
198 | /***************************************************************************\ | |
199 | * Get an SPSR from the specified mode * | |
200 | \***************************************************************************/ | |
201 | ||
202 | ARMword ARMul_GetSPSR(ARMul_State *state, ARMword mode) | |
203 | {ARMword bank = ModeToBank(state,mode & MODEBITS) ; | |
204 | if (bank == USERBANK || bank == DUMMYBANK) | |
205 | return(CPSR) ; | |
206 | else | |
207 | return(state->Spsr[bank]) ; | |
208 | } | |
209 | ||
210 | /***************************************************************************\ | |
211 | * This routine does a write to an SPSR * | |
212 | \***************************************************************************/ | |
213 | ||
214 | void ARMul_SetSPSR(ARMul_State *state, ARMword mode, ARMword value) | |
215 | {ARMword bank = ModeToBank(state,mode & MODEBITS) ; | |
216 | if (bank != USERBANK && bank !=DUMMYBANK) | |
217 | state->Spsr[bank] = value ; | |
218 | } | |
219 | ||
220 | /***************************************************************************\ | |
221 | * This routine does a write to the current SPSR, given an MSR instruction * | |
222 | \***************************************************************************/ | |
223 | ||
224 | void ARMul_FixSPSR(ARMul_State *state, ARMword instr, ARMword rhs) | |
225 | {if (state->Bank != USERBANK && state->Bank !=DUMMYBANK) { | |
226 | if (BITS(16,19)==9) SETPSR(state->Spsr[state->Bank],rhs) ; | |
227 | else if (BIT(16)) SETINTMODE(state->Spsr[state->Bank],rhs) ; | |
228 | else if (BIT(19)) SETCC(state->Spsr[state->Bank],rhs) ; | |
229 | } | |
230 | } | |
231 | ||
232 | /***************************************************************************\ | |
233 | * This routine updates the state of the emulator after the Cpsr has been * | |
234 | * changed. Both the processor flags and register bank are updated. * | |
235 | \***************************************************************************/ | |
236 | ||
237 | void ARMul_CPSRAltered(ARMul_State *state) | |
238 | {ARMword oldmode ; | |
239 | ||
240 | if (state->prog32Sig == LOW) | |
241 | state->Cpsr &= (CCBITS | INTBITS | R15MODEBITS) ; | |
242 | oldmode = state->Mode ; | |
243 | if (state->Mode != (state->Cpsr & MODEBITS)) { | |
244 | state->Mode = ARMul_SwitchMode(state,state->Mode,state->Cpsr & MODEBITS) ; | |
245 | state->NtransSig = (state->Mode & 3)?HIGH:LOW ; | |
246 | } | |
247 | ||
248 | ASSIGNINT(state->Cpsr & INTBITS) ; | |
249 | ASSIGNN((state->Cpsr & NBIT) != 0) ; | |
250 | ASSIGNZ((state->Cpsr & ZBIT) != 0) ; | |
251 | ASSIGNC((state->Cpsr & CBIT) != 0) ; | |
252 | ASSIGNV((state->Cpsr & VBIT) != 0) ; | |
253 | #ifdef MODET | |
254 | ASSIGNT((state->Cpsr & TBIT) != 0); | |
255 | #endif | |
256 | ||
257 | if (oldmode > SVC26MODE) { | |
258 | if (state->Mode <= SVC26MODE) { | |
259 | state->Emulate = CHANGEMODE ; | |
260 | state->Reg[15] = ECC | ER15INT | EMODE | R15PC ; | |
261 | } | |
262 | } | |
263 | else { | |
264 | if (state->Mode > SVC26MODE) { | |
265 | state->Emulate = CHANGEMODE ; | |
266 | state->Reg[15] = R15PC ; | |
267 | } | |
268 | else | |
269 | state->Reg[15] = ECC | ER15INT | EMODE | R15PC ; | |
270 | } | |
271 | ||
272 | } | |
273 | ||
274 | /***************************************************************************\ | |
275 | * This routine updates the state of the emulator after register 15 has * | |
276 | * been changed. Both the processor flags and register bank are updated. * | |
277 | * This routine should only be called from a 26 bit mode. * | |
278 | \***************************************************************************/ | |
279 | ||
280 | void ARMul_R15Altered(ARMul_State *state) | |
281 | { | |
282 | if (state->Mode != R15MODE) { | |
283 | state->Mode = ARMul_SwitchMode(state,state->Mode,R15MODE) ; | |
284 | state->NtransSig = (state->Mode & 3)?HIGH:LOW ; | |
285 | } | |
286 | if (state->Mode > SVC26MODE) | |
287 | state->Emulate = CHANGEMODE ; | |
288 | ASSIGNR15INT(R15INT) ; | |
289 | ASSIGNN((state->Reg[15] & NBIT) != 0) ; | |
290 | ASSIGNZ((state->Reg[15] & ZBIT) != 0) ; | |
291 | ASSIGNC((state->Reg[15] & CBIT) != 0) ; | |
292 | ASSIGNV((state->Reg[15] & VBIT) != 0) ; | |
293 | } | |
294 | ||
295 | /***************************************************************************\ | |
296 | * This routine controls the saving and restoring of registers across mode * | |
297 | * changes. The regbank matrix is largely unused, only rows 13 and 14 are * | |
298 | * used across all modes, 8 to 14 are used for FIQ, all others use the USER * | |
299 | * column. It's easier this way. old and new parameter are modes numbers. * | |
300 | * Notice the side effect of changing the Bank variable. * | |
301 | \***************************************************************************/ | |
302 | ||
303 | ARMword ARMul_SwitchMode(ARMul_State *state,ARMword oldmode, ARMword newmode) | |
304 | {unsigned i ; | |
305 | ||
306 | oldmode = ModeToBank(state,oldmode) ; | |
307 | state->Bank = ModeToBank(state,newmode) ; | |
308 | if (oldmode != state->Bank) { /* really need to do it */ | |
309 | switch (oldmode) { /* save away the old registers */ | |
310 | case USERBANK : | |
311 | case IRQBANK : | |
312 | case SVCBANK : | |
313 | case ABORTBANK : | |
314 | case UNDEFBANK : if (state->Bank == FIQBANK) | |
315 | for (i = 8 ; i < 13 ; i++) | |
316 | state->RegBank[USERBANK][i] = state->Reg[i] ; | |
317 | state->RegBank[oldmode][13] = state->Reg[13] ; | |
318 | state->RegBank[oldmode][14] = state->Reg[14] ; | |
319 | break ; | |
320 | case FIQBANK : for (i = 8 ; i < 15 ; i++) | |
321 | state->RegBank[FIQBANK][i] = state->Reg[i] ; | |
322 | break ; | |
323 | case DUMMYBANK : for (i = 8 ; i < 15 ; i++) | |
324 | state->RegBank[DUMMYBANK][i] = 0 ; | |
325 | break ; | |
326 | ||
327 | } | |
328 | switch (state->Bank) { /* restore the new registers */ | |
329 | case USERBANK : | |
330 | case IRQBANK : | |
331 | case SVCBANK : | |
332 | case ABORTBANK : | |
333 | case UNDEFBANK : if (oldmode == FIQBANK) | |
334 | for (i = 8 ; i < 13 ; i++) | |
335 | state->Reg[i] = state->RegBank[USERBANK][i] ; | |
336 | state->Reg[13] = state->RegBank[state->Bank][13] ; | |
337 | state->Reg[14] = state->RegBank[state->Bank][14] ; | |
338 | break ; | |
339 | case FIQBANK : for (i = 8 ; i < 15 ; i++) | |
340 | state->Reg[i] = state->RegBank[FIQBANK][i] ; | |
341 | break ; | |
342 | case DUMMYBANK : for (i = 8 ; i < 15 ; i++) | |
343 | state->Reg[i] = 0 ; | |
344 | break ; | |
345 | } /* switch */ | |
346 | } /* if */ | |
347 | return(newmode) ; | |
348 | } | |
349 | ||
350 | /***************************************************************************\ | |
351 | * Given a processor mode, this routine returns the register bank that * | |
352 | * will be accessed in that mode. * | |
353 | \***************************************************************************/ | |
354 | ||
355 | static ARMword ModeToBank(ARMul_State *state, ARMword mode) | |
356 | {static ARMword bankofmode[] = {USERBANK, FIQBANK, IRQBANK, SVCBANK, | |
357 | DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK, | |
358 | DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK, | |
359 | DUMMYBANK, DUMMYBANK, DUMMYBANK, DUMMYBANK, | |
360 | USERBANK, FIQBANK, IRQBANK, SVCBANK, | |
361 | DUMMYBANK, DUMMYBANK, DUMMYBANK, ABORTBANK, | |
362 | DUMMYBANK, DUMMYBANK, DUMMYBANK, UNDEFBANK | |
363 | } ; | |
364 | ||
365 | if (mode > UNDEF32MODE) | |
366 | return(DUMMYBANK) ; | |
367 | else | |
368 | return(bankofmode[mode]) ; | |
369 | } | |
370 | ||
371 | /***************************************************************************\ | |
372 | * Returns the register number of the nth register in a reg list. * | |
373 | \***************************************************************************/ | |
374 | ||
375 | unsigned ARMul_NthReg(ARMword instr, unsigned number) | |
376 | {unsigned bit, upto ; | |
377 | ||
378 | for (bit = 0, upto = 0 ; upto <= number ; bit++) | |
379 | if (BIT(bit)) upto++ ; | |
380 | return(bit - 1) ; | |
381 | } | |
382 | ||
383 | /***************************************************************************\ | |
384 | * Assigns the N and Z flags depending on the value of result * | |
385 | \***************************************************************************/ | |
386 | ||
387 | void ARMul_NegZero(ARMul_State *state, ARMword result) | |
388 | { | |
389 | if (NEG(result)) { SETN ; CLEARZ ; } | |
390 | else if (result == 0) { CLEARN ; SETZ ; } | |
391 | else { CLEARN ; CLEARZ ; } ; | |
392 | } | |
393 | ||
394 | /***************************************************************************\ | |
395 | * Assigns the C flag after an addition of a and b to give result * | |
396 | \***************************************************************************/ | |
397 | ||
398 | void ARMul_AddCarry(ARMul_State *state, ARMword a,ARMword b,ARMword result) | |
399 | { | |
400 | ASSIGNC( (NEG(a) && NEG(b)) || | |
401 | (NEG(a) && POS(result)) || | |
402 | (NEG(b) && POS(result)) ) ; | |
403 | } | |
404 | ||
405 | /***************************************************************************\ | |
406 | * Assigns the V flag after an addition of a and b to give result * | |
407 | \***************************************************************************/ | |
408 | ||
409 | void ARMul_AddOverflow(ARMul_State *state, ARMword a,ARMword b,ARMword result) | |
410 | { | |
411 | ASSIGNV( (NEG(a) && NEG(b) && POS(result)) || | |
412 | (POS(a) && POS(b) && NEG(result)) ) ; | |
413 | } | |
414 | ||
415 | /***************************************************************************\ | |
416 | * Assigns the C flag after an subtraction of a and b to give result * | |
417 | \***************************************************************************/ | |
418 | ||
419 | void ARMul_SubCarry(ARMul_State *state, ARMword a,ARMword b,ARMword result) | |
420 | { | |
421 | ASSIGNC( (NEG(a) && POS(b)) || | |
422 | (NEG(a) && POS(result)) || | |
423 | (POS(b) && POS(result)) ) ; | |
424 | } | |
425 | ||
426 | /***************************************************************************\ | |
427 | * Assigns the V flag after an subtraction of a and b to give result * | |
428 | \***************************************************************************/ | |
429 | ||
430 | void ARMul_SubOverflow(ARMul_State *state,ARMword a,ARMword b,ARMword result) | |
431 | { | |
432 | ASSIGNV( (NEG(a) && POS(b) && POS(result)) || | |
433 | (POS(a) && NEG(b) && NEG(result)) ) ; | |
434 | } | |
435 | ||
436 | /***************************************************************************\ | |
437 | * This function does the work of generating the addresses used in an * | |
438 | * LDC instruction. The code here is always post-indexed, it's up to the * | |
439 | * caller to get the input address correct and to handle base register * | |
440 | * modification. It also handles the Busy-Waiting. * | |
441 | \***************************************************************************/ | |
442 | ||
443 | void ARMul_LDC(ARMul_State *state,ARMword instr,ARMword address) | |
444 | {unsigned cpab ; | |
445 | ARMword data ; | |
446 | ||
447 | UNDEF_LSCPCBaseWb ; | |
448 | if (ADDREXCEPT(address)) { | |
449 | INTERNALABORT(address) ; | |
450 | } | |
451 | cpab = (state->LDC[CPNum])(state,ARMul_FIRST,instr,0) ; | |
452 | while (cpab == ARMul_BUSY) { | |
453 | ARMul_Icycles(state,1,0) ; | |
454 | if (IntPending(state)) { | |
455 | cpab = (state->LDC[CPNum])(state,ARMul_INTERRUPT,instr,0) ; | |
456 | return ; | |
457 | } | |
458 | else | |
459 | cpab = (state->LDC[CPNum])(state,ARMul_BUSY,instr,0) ; | |
460 | } | |
461 | if (cpab == ARMul_CANT) { | |
462 | CPTAKEABORT ; | |
463 | return ; | |
464 | } | |
465 | cpab = (state->LDC[CPNum])(state,ARMul_TRANSFER,instr,0) ; | |
466 | data = ARMul_LoadWordN(state,address) ; | |
467 | BUSUSEDINCPCN ; | |
468 | if (BIT(21)) | |
469 | LSBase = state->Base ; | |
470 | cpab = (state->LDC[CPNum])(state,ARMul_DATA,instr,data) ; | |
471 | while (cpab == ARMul_INC) { | |
472 | address += 4 ; | |
473 | data = ARMul_LoadWordN(state,address) ; | |
474 | cpab = (state->LDC[CPNum])(state,ARMul_DATA,instr,data) ; | |
475 | } | |
476 | if (state->abortSig || state->Aborted) { | |
477 | TAKEABORT ; | |
478 | } | |
479 | } | |
480 | ||
481 | /***************************************************************************\ | |
482 | * This function does the work of generating the addresses used in an * | |
483 | * STC instruction. The code here is always post-indexed, it's up to the * | |
484 | * caller to get the input address correct and to handle base register * | |
485 | * modification. It also handles the Busy-Waiting. * | |
486 | \***************************************************************************/ | |
487 | ||
488 | void ARMul_STC(ARMul_State *state,ARMword instr,ARMword address) | |
489 | {unsigned cpab ; | |
490 | ARMword data ; | |
491 | ||
492 | UNDEF_LSCPCBaseWb ; | |
493 | if (ADDREXCEPT(address) || VECTORACCESS(address)) { | |
494 | INTERNALABORT(address) ; | |
495 | } | |
496 | cpab = (state->STC[CPNum])(state,ARMul_FIRST,instr,&data) ; | |
497 | while (cpab == ARMul_BUSY) { | |
498 | ARMul_Icycles(state,1,0) ; | |
499 | if (IntPending(state)) { | |
500 | cpab = (state->STC[CPNum])(state,ARMul_INTERRUPT,instr,0) ; | |
501 | return ; | |
502 | } | |
503 | else | |
504 | cpab = (state->STC[CPNum])(state,ARMul_BUSY,instr,&data) ; | |
505 | } | |
506 | if (cpab == ARMul_CANT) { | |
507 | CPTAKEABORT ; | |
508 | return ; | |
509 | } | |
510 | #ifndef MODE32 | |
511 | if (ADDREXCEPT(address) || VECTORACCESS(address)) { | |
512 | INTERNALABORT(address) ; | |
513 | } | |
514 | #endif | |
515 | BUSUSEDINCPCN ; | |
516 | if (BIT(21)) | |
517 | LSBase = state->Base ; | |
518 | cpab = (state->STC[CPNum])(state,ARMul_DATA,instr,&data) ; | |
519 | ARMul_StoreWordN(state,address,data) ; | |
520 | while (cpab == ARMul_INC) { | |
521 | address += 4 ; | |
522 | cpab = (state->STC[CPNum])(state,ARMul_DATA,instr,&data) ; | |
523 | ARMul_StoreWordN(state,address,data) ; | |
524 | } | |
525 | if (state->abortSig || state->Aborted) { | |
526 | TAKEABORT ; | |
527 | } | |
528 | } | |
529 | ||
530 | /***************************************************************************\ | |
531 | * This function does the Busy-Waiting for an MCR instruction. * | |
532 | \***************************************************************************/ | |
533 | ||
534 | void ARMul_MCR(ARMul_State *state,ARMword instr, ARMword source) | |
535 | {unsigned cpab ; | |
536 | ||
537 | cpab = (state->MCR[CPNum])(state,ARMul_FIRST,instr,source) ; | |
538 | while (cpab == ARMul_BUSY) { | |
539 | ARMul_Icycles(state,1,0) ; | |
540 | if (IntPending(state)) { | |
541 | cpab = (state->MCR[CPNum])(state,ARMul_INTERRUPT,instr,0) ; | |
542 | return ; | |
543 | } | |
544 | else | |
545 | cpab = (state->MCR[CPNum])(state,ARMul_BUSY,instr,source) ; | |
546 | } | |
547 | if (cpab == ARMul_CANT) | |
548 | ARMul_Abort(state,ARMul_UndefinedInstrV) ; | |
549 | else { | |
550 | BUSUSEDINCPCN ; | |
551 | ARMul_Ccycles(state,1,0) ; | |
552 | } | |
553 | } | |
554 | ||
555 | /***************************************************************************\ | |
556 | * This function does the Busy-Waiting for an MRC instruction. * | |
557 | \***************************************************************************/ | |
558 | ||
559 | ARMword ARMul_MRC(ARMul_State *state,ARMword instr) | |
560 | {unsigned cpab ; | |
561 | ARMword result = 0 ; | |
562 | ||
563 | cpab = (state->MRC[CPNum])(state,ARMul_FIRST,instr,&result) ; | |
564 | while (cpab == ARMul_BUSY) { | |
565 | ARMul_Icycles(state,1,0) ; | |
566 | if (IntPending(state)) { | |
567 | cpab = (state->MRC[CPNum])(state,ARMul_INTERRUPT,instr,0) ; | |
568 | return(0) ; | |
569 | } | |
570 | else | |
571 | cpab = (state->MRC[CPNum])(state,ARMul_BUSY,instr,&result) ; | |
572 | } | |
573 | if (cpab == ARMul_CANT) { | |
574 | ARMul_Abort(state,ARMul_UndefinedInstrV) ; | |
575 | result = ECC ; /* Parent will destroy the flags otherwise */ | |
576 | } | |
577 | else { | |
578 | BUSUSEDINCPCN ; | |
579 | ARMul_Ccycles(state,1,0) ; | |
580 | ARMul_Icycles(state,1,0) ; | |
581 | } | |
582 | return(result) ; | |
583 | } | |
584 | ||
585 | /***************************************************************************\ | |
586 | * This function does the Busy-Waiting for an CDP instruction. * | |
587 | \***************************************************************************/ | |
588 | ||
589 | void ARMul_CDP(ARMul_State *state,ARMword instr) | |
590 | {unsigned cpab ; | |
591 | ||
592 | cpab = (state->CDP[CPNum])(state,ARMul_FIRST,instr) ; | |
593 | while (cpab == ARMul_BUSY) { | |
594 | ARMul_Icycles(state,1,0) ; | |
595 | if (IntPending(state)) { | |
596 | cpab = (state->CDP[CPNum])(state,ARMul_INTERRUPT,instr) ; | |
597 | return ; | |
598 | } | |
599 | else | |
600 | cpab = (state->CDP[CPNum])(state,ARMul_BUSY,instr) ; | |
601 | } | |
602 | if (cpab == ARMul_CANT) | |
603 | ARMul_Abort(state,ARMul_UndefinedInstrV) ; | |
604 | else | |
605 | BUSUSEDN ; | |
606 | } | |
607 | ||
608 | /***************************************************************************\ | |
609 | * This function handles Undefined instructions, as CP isntruction * | |
610 | \***************************************************************************/ | |
611 | ||
612 | void ARMul_UndefInstr(ARMul_State *state,ARMword instr) | |
613 | { | |
614 | ARMul_Abort(state,ARMul_UndefinedInstrV) ; | |
615 | } | |
616 | ||
617 | /***************************************************************************\ | |
618 | * Return TRUE if an interrupt is pending, FALSE otherwise. * | |
619 | \***************************************************************************/ | |
620 | ||
621 | unsigned IntPending(ARMul_State *state) | |
622 | { | |
623 | if (state->Exception) { /* Any exceptions */ | |
624 | if (state->NresetSig == LOW) { | |
625 | ARMul_Abort(state,ARMul_ResetV) ; | |
626 | return(TRUE) ; | |
627 | } | |
628 | else if (!state->NfiqSig && !FFLAG) { | |
629 | ARMul_Abort(state,ARMul_FIQV) ; | |
630 | return(TRUE) ; | |
631 | } | |
632 | else if (!state->NirqSig && !IFLAG) { | |
633 | ARMul_Abort(state,ARMul_IRQV) ; | |
634 | return(TRUE) ; | |
635 | } | |
636 | } | |
637 | return(FALSE) ; | |
638 | } | |
639 | ||
640 | /***************************************************************************\ | |
641 | * Align a word access to a non word boundary * | |
642 | \***************************************************************************/ | |
643 | ||
644 | ARMword ARMul_Align(ARMul_State *state, ARMword address, ARMword data) | |
645 | {/* this code assumes the address is really unaligned, | |
646 | as a shift by 32 is undefined in C */ | |
647 | ||
648 | address = (address & 3) << 3 ; /* get the word address */ | |
649 | return( ( data >> address) | (data << (32 - address)) ) ; /* rot right */ | |
650 | } | |
651 | ||
652 | /***************************************************************************\ | |
653 | * This routine is used to call another routine after a certain number of * | |
654 | * cycles have been executed. The first parameter is the number of cycles * | |
655 | * delay before the function is called, the second argument is a pointer * | |
656 | * to the function. A delay of zero doesn't work, just call the function. * | |
657 | \***************************************************************************/ | |
658 | ||
659 | void ARMul_ScheduleEvent(ARMul_State *state, unsigned long delay, unsigned (*what)()) | |
660 | {unsigned long when ; | |
661 | struct EventNode *event ; | |
662 | ||
663 | if (state->EventSet++ == 0) | |
664 | state->Now = ARMul_Time(state) ; | |
665 | when = (state->Now + delay) % EVENTLISTSIZE ; | |
666 | event = (struct EventNode *)malloc(sizeof(struct EventNode)) ; | |
667 | event->func = what ; | |
668 | event->next = *(state->EventPtr + when) ; | |
669 | *(state->EventPtr + when) = event ; | |
670 | } | |
671 | ||
672 | /***************************************************************************\ | |
673 | * This routine is called at the beginning of every cycle, to envoke * | |
674 | * scheduled events. * | |
675 | \***************************************************************************/ | |
676 | ||
677 | void ARMul_EnvokeEvent(ARMul_State *state) | |
678 | {static unsigned long then ; | |
679 | ||
680 | then = state->Now ; | |
681 | state->Now = ARMul_Time(state) % EVENTLISTSIZE ; | |
682 | if (then < state->Now) /* schedule events */ | |
683 | EnvokeList(state,then,state->Now) ; | |
684 | else if (then > state->Now) { /* need to wrap around the list */ | |
685 | EnvokeList(state,then,EVENTLISTSIZE-1L) ; | |
686 | EnvokeList(state,0L,state->Now) ; | |
687 | } | |
688 | } | |
689 | ||
690 | static void EnvokeList(ARMul_State *state, unsigned long from, unsigned long to) | |
691 | /* envokes all the entries in a range */ | |
692 | {struct EventNode *anevent ; | |
693 | ||
694 | for (; from <= to ; from++) { | |
695 | anevent = *(state->EventPtr + from) ; | |
696 | while (anevent) { | |
697 | (anevent->func)(state) ; | |
698 | state->EventSet-- ; | |
699 | anevent = anevent->next ; | |
700 | } | |
701 | *(state->EventPtr + from) = NULL ; | |
702 | } | |
703 | } | |
704 | ||
705 | /***************************************************************************\ | |
706 | * This routine is returns the number of clock ticks since the last reset. * | |
707 | \***************************************************************************/ | |
708 | ||
709 | unsigned long ARMul_Time(ARMul_State *state) | |
710 | {return(state->NumScycles + state->NumNcycles + | |
711 | state->NumIcycles + state->NumCcycles + state->NumFcycles) ; | |
712 | } |